diff --git a/README.md b/README.md index 8004546..5c226a6 100644 --- a/README.md +++ b/README.md @@ -339,10 +339,15 @@ im_client.py [-u|--xmlrpc-url ] [-r|--restapi-url ] [-v|--verify-ssl] It has an optional parameter ``maxTime`` with the max time to wait. It returns 0 if the infrastructure ends with a "configured" state or 1 otherwise. - ``create_wait_outputs inputfile`` + ``create_wait_outputs `` This operation is a combination of the create, wait and getoutputs functions. First it creates the infrastructure using the specified ``inputfile``, then waits for it to be configured, and finally gets the TOSCA outputs. In case of failure in then infrastructure creation step only the error message will be returned. The results will be returned to stdout in json format:: {"infid": "ID", "error": "Error message"} + + ``change_auth [overwrite]`` + This operation enables to change the owner of infrastructure with ID ``infId`` using the authentication + data from file ``newAuthFile``. The ``overwrite`` parameter is optional and is a flag to specify if the + authentication data will be overwrited or will be appended. The default value is 0. diff --git a/im_client.py b/im_client.py index 6fd96a0..221e459 100755 --- a/im_client.py +++ b/im_client.py @@ -249,11 +249,14 @@ def __init__(self, options, auth_data, args): self.options = options self.auth_data = auth_data if options.restapi and auth_data: - for item in auth_data: - for key, value in item.items(): - value = value.replace("\n", "\\\\n") - self.rest_auth_data += "%s = %s;" % (key, value) - self.rest_auth_data += "\\n" + if isinstance(auth_data, str): + self.rest_auth_data = auth_data + else: + for item in auth_data: + for key, value in item.items(): + value = value.replace("\n", "\\\\n") + self.rest_auth_data += "%s = %s;" % (key, value) + self.rest_auth_data += "\\n" elif options.xmlrpc: if options.xmlrpc.startswith("https") and not options.verify: @@ -264,6 +267,22 @@ def __init__(self, options, auth_data, args): pass self.server = ServerProxy(options.xmlrpc, allow_none=True) + @staticmethod + def replace_auth_values(value): + # Enable to specify a commnad and set the contents of the output + if value.startswith("command(") and value.endswith(")"): + command = value[8:-1] + return IMClient._run_command(command) + # Enable to specify a filename and set the contents of it + elif value.startswith("file(") and value.endswith(")"): + try: + with open(value[5:-1], 'r') as f: + data = f.read() + return data.strip() + except Exception: + pass + return value + # From IM.auth @staticmethod def read_auth_data(filename): @@ -276,6 +295,10 @@ def read_auth_data(filename): res = [] + if len(lines) == 1 and lines[0].startswith("Bearer "): + token = lines[0].strip()[7:] + return "Bearer %s" % IMClient.replace_auth_values(token) + for line in lines: line = line.strip() if len(line) > 0 and not line.startswith("#"): @@ -288,21 +311,7 @@ def read_auth_data(filename): else: key = key_value[0].strip() value = key_value[1].strip().replace("\\n", "\n") - # Enable to specify a commnad and set the contents of the output - if value.startswith("command(") and value.endswith(")"): - command = value[8:len(value) - 1] - value = IMClient._run_command(command) - # Enable to specify a filename and set the contents of it - elif value.startswith("file(") and value.endswith(")"): - filename = value[5:len(value) - 1] - try: - value_file = open(filename, 'r') - value = value_file.read() - value_file.close() - except Exception: - pass - - auth[key] = value + auth[key] = IMClient.replace_auth_values(value) res.append(auth) return res @@ -885,6 +894,44 @@ def wait(self): else: return False, "The infrastructure is in state: %s" % state + def change_auth(self): + inf_id = self.get_inf_id() + if len(self.args) >= 2: + if not os.path.isfile(self.args[1]): + return False, "New auth file '" + self.args[1] + "' does not exist" + else: + return False, "JSON file to create inf. not specified" + + new_auth_data = [] + for elem in IMClient.read_auth_data(self.args[1]): + if "type" in elem and elem["type"] == "InfrastructureManager": + new_auth_data.append(elem) + break + + if not new_auth_data: + return False, "No new InfrastructureManager auth provided." + + overwrite = False + if len(self.args) >= 3: + if self.args[2] in ["0", "1"]: + overwrite = bool(int(self.args[2])) + else: + return False, "The overwrite flag must be 0 or 1" + + if self.options.restapi: + headers = {"Authorization": self.rest_auth_data} + url = "%s/infrastructures/%s/authorization" % (self.options.restapi, inf_id) + if overwrite: + url += "?overwrite=1" + resp = requests.request("POST", url, verify=self.options.verify, + headers=headers, data=json.dumps(new_auth_data[0])) + success = resp.status_code == 200 + info = resp.text + else: + (success, info) = self.server.ChangeInfrastructureAuth(inf_id, new_auth_data[0], overwrite, self.auth_data) + + return success, info + def main(operation, options, args, parser): """ @@ -898,7 +945,7 @@ def main(operation, options, args, parser): if (operation not in ["removeresource", "addresource", "create", "destroy", "getinfo", "list", "stop", "start", "alter", "getcontmsg", "getvminfo", "reconfigure", "getradl", "getvmcontmsg", "stopvm", "startvm", "sshvm", "ssh", "getstate", "getversion", "export", "import", "getoutputs", - "rebootvm", "cloudusage", "cloudimages", "wait", "create_wait_outputs"]): + "rebootvm", "cloudusage", "cloudimages", "wait", "create_wait_outputs", "change_auth"]): parser.error("operation not recognised. Use --help to show all the available operations") auth_data = None @@ -1202,6 +1249,15 @@ def main(operation, options, args, parser): print('{"infid": "%s", "error": "%s"}' % (inf_id, outputs)) return False + elif operation == "change_auth": + success, error = imclient.change_auth() + if success: + if not options.quiet: + print("Auth data successfully changed.") + else: + print("ERROR changing auth data: " + error) + return success + def get_parser(): """ @@ -1273,6 +1329,7 @@ def get_parser(): parser.add_operation_help('getversion', '') parser.add_operation_help('wait', ' ') parser.add_operation_help('create_wait_outputs', '') + parser.add_operation_help('change_auth', ' ') return parser diff --git a/test/files/auth_new.dat b/test/files/auth_new.dat new file mode 100644 index 0000000..58d6e18 --- /dev/null +++ b/test/files/auth_new.dat @@ -0,0 +1 @@ +type = InfrastructureManager; username = user1; password = pass1 diff --git a/test/unit/test_client.py b/test/unit/test_client.py index fc88090..59ee50f 100755 --- a/test/unit/test_client.py +++ b/test/unit/test_client.py @@ -116,6 +116,9 @@ def get_response(method, url, verify, cert=None, headers=None, data=None): resp.status_code = 200 resp.text = ('{ "uri-list": [ { "uri" : "http://localhost/infid/vms/1" }]}') resp.json.return_value = json.loads(resp.text) + elif url == "/infrastructures/infid/authorization": + resp.status_code = 200 + resp.text = "" else: resp.status_code = 404 elif method == "DELETE": @@ -1191,6 +1194,21 @@ def test_create_wait_outputs(self, requests): self.assertEqual(output, {"infid": "inf1", "output1": "value1" , "output2": "value2"}) sys.stdout = oldstdout + @patch('requests.request') + def test_change_user(self, requests): + """ + Test create_wait_outputs operation + """ + requests.side_effect = self.get_response + options = MagicMock() + options.auth_file = get_abs_path("../../auth.dat") + options.restapi = "https://localhost:8800" + options.xmlrpc = None + options.quiet = True + parser = MagicMock() + + res = main("change_auth", options, ["infid", get_abs_path("../files/auth_new.dat")], parser) + self.assertEquals(res, True) if __name__ == '__main__':