Add support to programmably start a profile on the POWDER testbed, which can in turn...
[it/test.git] / XTesting / powder-control / powder / rpc.py
diff --git a/XTesting/powder-control/powder/rpc.py b/XTesting/powder-control/powder/rpc.py
new file mode 100644 (file)
index 0000000..5520b7e
--- /dev/null
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2004-2020 University of Utah and the Flux Group.
+#
+# {{{EMULAB-LICENSE
+#
+# This file is part of the Emulab network testbed software.
+#
+# This file is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or (at
+# your option) any later version.
+#
+# This file is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
+# License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this file.  If not, see <http://www.gnu.org/licenses/>.
+#
+# }}}
+#
+
+import logging
+import os
+import ssl
+import sys
+import xmlrpc.client as xmlrpc_client
+
+
+PACKAGE_VERSION = 0.1
+DEBUG = 0
+
+# rpc server
+XMLRPC_SERVER = "boss.emulab.net"
+XMLRPC_PORT   = 3069
+SERVER_PATH   = "/usr/testbed"
+URI           = "https://" + XMLRPC_SERVER + ":" + str(XMLRPC_PORT) + SERVER_PATH
+
+RESPONSE_SUCCESS     = 0
+RESPONSE_BADARGS     = 1
+RESPONSE_ERROR       = 2
+RESPONSE_FORBIDDEN   = 3
+RESPONSE_BADVERSION  = 4
+RESPONSE_SERVERERROR = 5
+RESPONSE_TOOBIG      = 6
+RESPONSE_REFUSED     = 7  # Emulab is down, try again later.
+RESPONSE_TIMEDOUT    = 8
+
+# User supplied login ID, password, and certificate
+try:
+    LOGIN_ID  = os.environ['USER']
+    PEM_PWORD = os.environ['PWORD']
+    CERT_PATH = os.environ['CERT']
+except KeyError:
+    logging.error('Missing Powder credential environment variable(s)')
+    sys.exit(1)
+
+
+def do_method(method, params):
+    ctx = ssl.SSLContext()
+    ctx.set_ciphers('ALL:@SECLEVEL=0')
+    ctx.load_cert_chain(CERT_PATH, password=PEM_PWORD)
+    ctx.check_hostname = False
+    ctx.verify_mode = ssl.CERT_NONE
+
+    # Get a handle on the server,
+    server = xmlrpc_client.ServerProxy(URI, context=ctx, verbose=DEBUG)
+
+    # Get a pointer to the function we want to invoke.
+    meth      = getattr(server, "portal." + method)
+    meth_args = [PACKAGE_VERSION, params]
+
+    # Make the call.
+    try:
+        response = meth(*meth_args)
+    except xmlrpc_client.Fault as e:
+        print(e.faultString)
+        return -1, None
+
+    rval = response["code"]
+
+    # If the code indicates failure, look for a "value". Use that as the
+    # return value instead of the code.
+    if rval != RESPONSE_SUCCESS:
+        if response["value"]:
+            rval = response["value"]
+
+    return rval, response
+
+
+def start_experiment(experiment_name, project_name, profile_name):
+    params = {
+        "name": experiment_name,
+        "proj": project_name,
+        "profile": ','.join([project_name, profile_name])
+    }
+    rval, response = do_method("startExperiment", params)
+    return rval, response
+
+
+def terminate_experiment(project_name, experiment_name):
+    params = {
+        "experiment": ','.join([project_name, experiment_name])
+    }
+    rval, response = do_method("terminateExperiment", params)
+    return rval, response
+
+
+def get_experiment_status(project_name, experiment_name):
+    params = {
+        "experiment": ','.join([project_name, experiment_name])
+    }
+    rval, response = do_method("experimentStatus", params)
+    return rval, response
+
+
+def get_experiment_manifests(project_name, experiment_name):
+    params = {
+        "experiment": ','.join([project_name, experiment_name])
+    }
+    rval, response = do_method("experimentManifests", params)
+    return rval, response