Add nfdeployment handlers
[pti/o2.git] / helm_sdk / utils.py
diff --git a/helm_sdk/utils.py b/helm_sdk/utils.py
new file mode 100644 (file)
index 0000000..6561ba1
--- /dev/null
@@ -0,0 +1,166 @@
+########
+# Copyright (c) 2019 Cloudify Platform Ltd. All rights reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+#    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    * See the License for the specific language governing permissions and
+#    * limitations under the License.
+
+import os
+import copy
+import threading
+import subprocess
+
+from helm_sdk.filters import obfuscate_passwords
+
+from helm_sdk._compat import StringIO, text_type
+from helm_sdk.exceptions import CloudifyHelmSDKError
+
+FLAGS_LIST_TO_VALIDATE = ['kube-apiserver', 'kube-token', 'kubeconfig']
+
+
+def run_subprocess(command,
+                   logger,
+                   cwd=None,
+                   additional_env=None,
+                   additional_args=None,
+                   return_output=False):
+    if additional_args is None:
+        additional_args = {}
+    args_to_pass = copy.deepcopy(additional_args)
+    if additional_env:
+        passed_env = args_to_pass.setdefault('env', {})
+        passed_env.update(os.environ)
+        passed_env.update(additional_env)
+
+    logger.info(
+        "Running: command={cmd}, cwd={cwd}, additional_args={args}".format(
+            cmd=obfuscate_passwords(command),
+            cwd=cwd,
+            args=obfuscate_passwords(args_to_pass)))
+
+    process = subprocess.Popen(
+        args=command,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        stdin=None,
+        cwd=cwd,
+        **args_to_pass)
+
+    if return_output:
+        stdout_consumer = CapturingOutputConsumer(
+            process.stdout)
+    else:
+        stdout_consumer = LoggingOutputConsumer(
+            process.stdout, logger, "<out> ")
+    stderr_consumer = LoggingOutputConsumer(
+        process.stderr, logger, "<err> ")
+
+    return_code = process.wait()
+    stdout_consumer.join()
+    stderr_consumer.join()
+
+    if return_code:
+        raise subprocess.CalledProcessError(return_code,
+                                            [obfuscate_passwords(cmd_element)
+                                             for cmd_element in command])
+
+    output = stdout_consumer.buffer.getvalue() if return_output else None
+    logger.info("Returning output:\n{0}".format(
+        obfuscate_passwords(output) if output is not None else '<None>'))
+
+    return output
+
+
+# Stolen from the script plugin, until this class
+# moves to a utils module in cloudify-common.
+class OutputConsumer(object):
+    def __init__(self, out):
+        self.out = out
+        self.consumer = threading.Thread(target=self.consume_output)
+        self.consumer.daemon = True
+
+    def consume_output(self):
+        for line in self.out:
+            self.handle_line(line)
+        self.out.close()
+
+    def handle_line(self, line):
+        raise NotImplementedError("Must be implemented by subclass.")
+
+    def join(self):
+        self.consumer.join()
+
+
+class LoggingOutputConsumer(OutputConsumer):
+    def __init__(self, out, logger, prefix):
+        OutputConsumer.__init__(self, out)
+        self.logger = logger
+        self.prefix = prefix
+        self.consumer.start()
+
+    def handle_line(self, line):
+        self.logger.info(
+            "{0}{1}".format(text_type(self.prefix),
+                            obfuscate_passwords(
+                                line.decode('utf-8').rstrip('\n'))))
+
+
+class CapturingOutputConsumer(OutputConsumer):
+    def __init__(self, out):
+        OutputConsumer.__init__(self, out)
+        self.buffer = StringIO()
+        self.consumer.start()
+
+    def handle_line(self, line):
+        self.buffer.write(line.decode('utf-8'))
+
+    def get_buffer(self):
+        return self.buffer
+
+
+def prepare_parameter(arg_dict):
+    """
+    Prepare single parameter.
+    :param arg_dict: dictionary with the name of the flag and value(optional)
+    :return: "--name=value" or -"-name"
+    """
+    try:
+        param_string = "--" + arg_dict["name"]
+        return param_string + '=' + arg_dict.get("value") if arg_dict.get(
+            "value") else param_string
+    except KeyError:
+        raise CloudifyHelmSDKError("Parameter name doesen't exist.")
+
+
+def prepare_set_parameters(set_values):
+    """
+    Prepare set parameters for install command.
+    :param set_values: list of dictionaries with the name of the variable to
+    set command and its value.
+    :return list like: ["--set", "name=value","--set",
+    """
+    set_list = []
+    for set_dict in set_values:
+        set_list.append('--set')
+        try:
+            set_list.append(set_dict["name"] + "=" + set_dict["value"])
+        except KeyError:
+            raise CloudifyHelmSDKError(
+                "\"set\" parameter name or value is missing.")
+    return set_list
+
+
+def validate_no_collisions_between_params_and_flags(flags):
+    if [flag for flag in flags if flag['name'] in FLAGS_LIST_TO_VALIDATE]:
+        raise CloudifyHelmSDKError(
+            'Please do not pass {flags_list} under "flags" property,'
+            'each of them has a known property.'.format(
+                flags_list=FLAGS_LIST_TO_VALIDATE))