예제 #1
0
    def __init__(self, mode, response_file):
        if mode != Prompts.PROMPT_MODE and mode != Prompts.RECORD_MODE and mode != Prompts.HEADLESS_MODE:
            raise InstallException('Invalid prompt mode %s' % str(mode))

        self.response_file = None
        self.mode = mode
        self.recorded_options = dict()
        self.headless_parser = None

        if mode == Prompts.HEADLESS_MODE:
            if response_file is None:
                raise InstallException(
                    'In order to run in headless mode, you must supply a response file.'
                )
            if not os.path.exists(response_file):
                raise InstallException(
                    'In order to run in headless mode, you must supply an existing response file. %s does not exist.'
                    % response_file)
            self.headless_parser = Parser.get_properties_parser(response_file)
            Log.info(
                'Installer prompts have been initialized in headless mode.')
        elif mode == Prompts.RECORD_MODE:
            if response_file is None:
                raise InstallException(
                    'In order to run in record mode, you must supply a response file destination.'
                )
            dirname = os.path.dirname(response_file)
            if not os.path.exists(dirname):
                raise InstallException(
                    'In order to run in record mode, the directory for the response file must exist.'
                )
            self.response_file = open(response_file, 'w')
            Log.info(
                'Installer prompts have been initialized in record mode. response file: {0}'
                .format(response_file))
예제 #2
0
 def invoke_gcloud(cmd):
     response, status = OSCommand.run2("gcloud {0}".format(cmd))
     if status != 0:
         Log.error("Could not create GKE Cluster: {0}: {1}".format(
             status, response))
         BootstrapBase.exit_application(101)
     return response, status
예제 #3
0
    def prompt_file(self,
                    prompt_text,
                    default=None,
                    newline=False,
                    key_name=None):
        while True:
            result = self.prompt(prompt_text,
                                 default,
                                 newline=newline,
                                 key_name=key_name)
            if result is None:
                if self.mode == Prompts.HEADLESS_MODE:
                    raise InstallException(
                        'File path cannot be blank for key %s.' % key_name)

                Log.warning('Path cannot be blank.')
                continue

            if not os.path.exists(result):
                if self.mode == Prompts.HEADLESS_MODE:
                    raise InstallException(
                        'File path %s does not exist for key %s.' %
                        (result, key_name))

                Log.warning('Path to %s does not exist' % result)
                continue

            break

        return result
예제 #4
0
 def _create_update_resource_group(self):
     Log.info(
         "Creating or updating resource group: {0}...".format(
             self.context.resource_group), True)
     resource = ResourceGroup(location=self.context.location)
     self.resource_client.resource_groups.create_or_update(
         self.context.resource_group, resource)
예제 #5
0
    def build_cloud(self):
        self.cluster_name = self.prompts.prompt("Enter cluster name",
                                                self.cluster_name,
                                                key_name="GKE_CLUSTER_NAME")
        self.nodes = self.prompts.prompt_integer("Enter number of nodes",
                                                 self.nodes,
                                                 1,
                                                 key_name="GKE_NODE_COUNT")
        self.disks = self.prompts.prompt_integer(
            "Enter number of local SSD disks for MapR FS. Each disk will be a fixed 375GB",
            self.disks,
            1,
            key_name="GKE_NUM_DISKS")
        self.instance_type = self.prompts.prompt("GKE compute instance type?",
                                                 self.instance_type,
                                                 key_name="GKE_INSTANCE_TYPE")
        if self.alpha:
            self.k8s_version = self.prompts.prompt("Kubernetes version?",
                                                   self.k8s_alpha_version,
                                                   key_name="GKE_K8S_VERSION")
        else:
            self.k8s_version = self.prompts.prompt("Kubernetes version?",
                                                   self.k8s_version,
                                                   key_name="GKE_K8S_VERSION")
        self.zone = self.prompts.prompt("GCE Zone to deploy into?",
                                        self.zone,
                                        key_name="GKE_ZONE")
        self.project = self.prompts.prompt("GCE project id?",
                                           self.project,
                                           key_name="GKE_PROJECT_ID")
        self.user = self.prompts.prompt("GCE user id?",
                                        self.user,
                                        key_name="GKE_USER")
        # self.image_type = self.prompts.prompt("GKE image type?", self.image_type)
        Log.info("Using GKE compute image type: {0}".format(self.image_type),
                 True)
        if self.alpha:
            Log.info("Using alpha Kubernetes version", True)
        else:
            Log.info("Using non-alpha Kubernetes version", True)

        if not self.prompts.prompt_boolean(
                "Ready to create Google GKS cluster. Do you want to continue?",
                True,
                key_name="GKE_CREATE"):
            Log.error("Exiiting since user is not ready to continue")
            BootstrapBase.exit_application(100)

        before = time.time()
        self.create_k8s_cluster()
        after = time.time()
        diff = int(after - before)
        Log.info(
            "Cluster creation took {0}m {1}s".format(diff / 60, diff % 60),
            True)
 def confirm_delete_installation(self):
     print(os.linesep)
     Log.info(
         "This will uninstall ALL MapR operators from your Kubernetes environment. This will cause all Compute Spaces to be destroyed. They cannot be recovered!",
         True)
     agree = self._prompts.prompt_boolean("Do you agree?",
                                          False,
                                          key_name="AGREEMENT")
     if not agree:
         Log.info("Very wise decision. Exiting uninstall...", True)
         BootstrapBase.exit_application(2)
예제 #7
0
 def check_if_storage(self):
     print(os.linesep)
     agree = self._prompts.prompt_boolean("Install MapR Data Platform?",
                                          True,
                                          key_name="CREATE_STORAGE")
     Log.info(
         "Attention: MapR Data Platform on Kubernetes is PRE-ALPHA Software. Please DO NOT store critical data in clusters you create with this "
         "operator. You WILL lose data and these clusters WILL NOT be upgradable.",
         stdout=True)
     print("")
     return agree
예제 #8
0
    def check_available():
        available_instances = dict()
        for cloud_name, cloud_instance in Cloud._cloud_instances.items():
            if cloud_instance.is_available():
                Log.debug("{0} cloud is available".format(cloud_name))
                available_instances[cloud_name] = cloud_instance
            else:
                Log.warning(
                    "{0} cloud was enabled but did not pass availability tests"
                    .format(cloud_name))

        Cloud._cloud_instances = available_instances
예제 #9
0
    def prompt_not_none(self,
                        prompt_text,
                        default=None,
                        password=False,
                        newline=False,
                        key_name=None):
        while True:
            result = self.prompt(prompt_text, default, password, newline,
                                 key_name)
            if result is not None:
                result = result.strip()
                if len(result) > 0:
                    return result

            Log.warning('Invalid: %s. Please re enter a non empty value.' %
                        prompt_text)
예제 #10
0
    def process_labels(self):
        self._get_json()

        nodes_not_set = self.get_mapr_use_node_labels(NodeLabels.MAPR_LABEL)
        if nodes_not_set is not None and len(nodes_not_set) > 0:
            Log.info("Setting MapR usage tag {0} for {1} nodes...".format(NodeLabels.MAPR_LABEL, len(nodes_not_set)),
                     stdout=True)
            for node_not_set in nodes_not_set:
                self.k8s.run_label_mapr_node(node_not_set, NodeLabels.MAPR_LABEL, True)

        nodes_not_set = self.get_mapr_use_node_labels(NodeLabels.EXCLUSIVE_LABEL)
        if nodes_not_set is not None and len(nodes_not_set) > 0:
            Log.info("Setting MapR usage tag {0} for {1} nodes...".format(NodeLabels.EXCLUSIVE_LABEL, len(nodes_not_set)),
                     stdout=True)
            for node_not_set in nodes_not_set:
                self.k8s.run_label_mapr_node(node_not_set, NodeLabels.EXCLUSIVE_LABEL, "None")
예제 #11
0
 def validate_nodes(self):
     print(os.linesep)
     Log.info(
         "We must validate and annotate your Kubernetes nodes. "
         "MapR node validation pods will be installed.",
         stdout=True)
     agree = self._prompts.prompt_boolean("Do you agree?",
                                          True,
                                          key_name="AGREEMENT_VALIDATE")
     if not agree:
         Log.error("Exiting due to non-agreement...")
         BootstrapBase.exit_application(2)
     # TODO: Add node exclusion code here
     # exclude = self._prompts.prompt_boolean("Do you want to exclude any nodes?", False, key_name="EXCLUDE_NODES")
     # if exclude:
     #    Log.error("Operation not currently supported...")
     #    BootstrapBase.exit_application(6)
     print("")
예제 #12
0
    def invoke_stable_cluster(self, args):
        cmd = "container --project {0} clusters create {1} {2}".format(
            self.project, self.cluster_name, args)

        Log.info("kubernetes version = {0}".format(self.k8s_version), True)
        Log.info(
            "Creating GKE environment via the following command: gcloud {0}".
            format(cmd), True)
        Log.info("Create log follows...")
        result, status = self.invoke_gcloud(cmd)
        Log.info(result, True)
예제 #13
0
 def configure_cloud(self):
     cmd = GoogleCloud.CMD_ROLE_BINDING.format(self.user)
     Log.info("Now we will configure RBAC for your kubernetes env...", True)
     Log.info(
         "Binding cluster-admin role to GCE user: {0}...".format(self.user),
         True)
     response, status = OSCommand.run2(cmd)
     if status != 0:
         Log.error("Could not bind cluster-admin role: {0}:{1}", status,
                   response)
     Log.info("Configured GKE permissions", True)
예제 #14
0
    def run(self):
        logdir = os.path.join(self.script_dir, "logs")
        if os.path.exists(logdir):
            if not os.path.isdir(logdir):
                print(
                    "ERROR: {0} is not a directory and cannot be used as alog directory"
                    .format(logdir))
                BootstrapBase.exit_application(1)
        else:
            os.mkdir(logdir)

        logname = os.path.join(
            logdir, BootstrapBase.NOW.strftime("bootstrap-%m-%d_%H:%M:%S.log"))
        Log.initialize(self.log_config_file, logname)

        BootstrapBase._prompts = Prompts.initialize(self.prompt_mode,
                                                    self.prompt_response_file)
        Log.info("Prompt mode: {0}, response file: {1}".format(
            self.prompt_mode, self.prompt_response_file))
예제 #15
0
 def collect(self):
     Log.debug('Checking kubectl is installed correctly...')
     response, status = OSCommand.run2("command -v kubectl")
     if status == 0:
         Log.info("Looking good... Found kubectl")
         self.operation = Validator.OPERATION_OK
     else:
         self.operation = Validator.OPERATION_INSTALL
         Log.error(
             "You will need to have kubectl installed on this machine.")
         Log.error(
             "To install kubectl please see: https://kubernetes.io/docs/tasks/tools/install-kubectl/"
         )
예제 #16
0
 def collect(self):
     Log.debug('Checking for oc (OpenShift CLI) installation...')
     response, status = OSCommand.run2("command -v oc")
     if status == 0:
         Log.info("Looking good... Found oc (OpenShift CLI) installed",
                  True)
         self.operation = Validator.OPERATION_OK
     else:
         self.operation = Validator.OPERATION_NONE
         Log.error(
             "You will need to have oc (OpenShift CLI) installed on this machine."
         )
         Log.error(
             "To install oc please see: https://docs.openshift.com/container-platform/3.11/cli_reference/get_started_cli.html"
         )
예제 #17
0
    def configure_kubernetes(self):
        print(os.linesep)
        Log.info("Ensuring proper kubernetes configuration...", True)
        Log.info("Checking kubectl can connect to your kubernetes cluster...",
                 True)
        response, status = OSCommand.run2("kubectl get nodes")
        if status != 0:
            Log.error(
                "Cannot connect to Kubernetes. Make sure kubectl is pre-configured to communicate with a Kubernetes cluster."
            )
            BootstrapBase.exit_application(4)

        Log.info("Looking good... Connected to Kubernetes", True)
        if self.cloud_instance is not None:
            self.cloud_instance.configure_cloud()
예제 #18
0
 def prologue(self):
     title = os.linesep + "MapR for Kubernetes Bootstrap "
     title += "Installer" if self.is_install is True else "Uninstaller"
     title += " (Version {0})".format(BOOTSTRAP_BUILD_VERSION_NO)
     Log.info(title, True)
     Log.info("Copyright 2019 MapR Technologies, Inc., All Rights Reserved",
              True)
     Log.info("https://mapr.com/legal/eula/", True)
예제 #19
0
    def run2(statements,
             username=None,
             use_nohup=False,
             out_file=None,
             in_background=False,
             users_env=False):
        if isinstance(statements, str):
            statements = [statements]

        responses = ''
        status = 0

        for statement in statements:
            new_statement = ''
            if use_nohup:
                new_statement += 'nohup '
            if username is not None:
                new_statement += 'su '
                if users_env:
                    new_statement += '- '
                new_statement += username + ' -c \'' + statement + '\''
            else:
                new_statement += statement

            if in_background:
                if use_nohup and out_file is not None:
                    new_statement += ' > ' + out_file + ' 2>&1'
                else:
                    new_statement += ' &>/dev/null'
                new_statement += ' &'

            Log.debug('RUN: %s' % new_statement)

            process = subprocess.Popen('%s 2>&1' % new_statement,
                                       shell=True,
                                       stdout=subprocess.PIPE)
            response = process.stdout.read()
            # process.wait will only return None if the process hasn't terminated. We don't
            # need to check for None here
            status = process.wait()

            if len(response) == 0:
                response = '<no response>'
            else:
                # Python 3 returns byes or bytearray from the read() above
                if not isinstance(response, str) and isinstance(
                        response, (bytes, bytearray)):
                    response = response.decode("UTF-8")
            Log.debug('STATUS: %s' % str(status))
            Log.debug('RESPONSE: %s' % response)

            responses += response

            if status != 0:
                break

        return responses, status
예제 #20
0
    def _create_aks(self):
        with open(os.path.join(self.base_path,
                               CreateAKS.PARAMETERS_JSON)) as in_file:
            parameters = json.load(in_file)

        parameters[u"resourceName"][u"value"] = self.context.aks_name
        parameters[u"agentCount"][u"value"] = self.context.node_count
        parameters[u"agentVMSize"][u'Value'] = self.context.vm_size
        parameters[u"osDiskSizeGB"][u'Value'] = int(self.context.os_disk_size)
        parameters[u"sshRSAPublicKey"][u'Value'] = self.context.public_key
        parameters[u"servicePrincipalClientId"][
            u'Value'] = self.context.client_id
        parameters[u"servicePrincipalClientSecret"][
            u'Value'] = self.context.secret
        parameters[u"kubernetesVersion"][u'Value'] = self.context.k8s_version
        parameters[u"dnsPrefix"][u'Value'] = "{0}-maprtech".format(
            self.context.aks_name)

        with open(os.path.join(self.base_path,
                               CreateAKS.ARM_TEMPLATE_JSON)) as in_file:
            template = json.load(in_file)

        deployment_properties = DeploymentProperties()
        deployment_properties.template = template
        deployment_properties.parameters = parameters
        deployment_properties.mode = DeploymentMode.incremental

        Log.info(
            "{0}: Run K8S deployment test with {1} Nodes OS Disk Size {2}...".
            format(self.context.resource_group, self.context.node_count,
                   self.context.os_disk_size), True)
        deployment_async_operation = self.resource_client.deployments.create_or_update(
            self.context.resource_group, "maprk8s.deployment",
            deployment_properties)
        deployment_async_operation.wait()
        Log.info("K8S cluster deployment complete", True)
예제 #21
0
 def exit_application(signum, _=None):
     if signum == 0:
         Log.info("Bootstrap terminated {0}".format(signum))
     else:
         print(os.linesep)
         Log.warning("Bootstrap terminated {0}".format(signum))
     if BootstrapBase._prompts is not None:
         BootstrapBase._prompts.write_response_file()
         BootstrapBase._prompts = None
     Log.close()
     exit(signum)
예제 #22
0
    def is_available(self):
        if not self.enabled:
            return False

        if self.available is None:
            Log.info("Checking Google cloud availability. One moment...", True)
            results, status = OSCommand.run2(
                ["command -v gcloud", "gcloud compute instances list"])
            self.available = True if status == 0 else False

            if not self.available:
                Log.warning(
                    "Google Cloud SDK not found or not configured correctly. Quit bootstrapper, install and "
                    "confgure Google Cloud SDK and restart bootstrapper. See: https://cloud.google.com/sdk/. "
                    "More information on the error in the bootstrapper log here: "
                    + Log.get_log_filename())
                Log.warning(results)

        return self.available
예제 #23
0
    def prompt_choices(self,
                       prompt_text,
                       choices,
                       default=None,
                       newline=False,
                       key_name=None):
        if type(choices) is not list:
            raise InstallException('prompt_choices choice list is not a list.')

        choices_str = str(choices).replace('[', '(').replace(']', ')')
        prompt_text = '%s %s' % (prompt_text, choices_str)
        last_find = None

        if default is not None and default not in choices:
            raise InstallException(
                'The default value %s was not found in the list' % default)

        while True:
            response = self.prompt(prompt_text,
                                   default,
                                   newline=newline,
                                   key_name=key_name)
            find_count = 0

            if response is None:
                if self.mode == Prompts.HEADLESS_MODE:
                    raise InstallException(
                        '%s is not a choice in list %s for key %s.' %
                        (response, choices, key_name))

                Log.warning('Enter one of the choices in the list')
                continue

            for item in choices:
                if item.lower().find(response.lower()) >= 0:
                    find_count += 1
                    last_find = item

            if find_count == 0:
                Log.warning('You must enter one of the choices in the list')
            elif find_count >= 2:
                Log.warning('Your entry matched more than one choice')
            else:
                break

        return last_find
예제 #24
0
    def _get_json(self):
        Log.info("Retrieving node information...", stdout=True)
        result, status = self.k8s.run_get("nodes -o=json")
        if status != 0:
            return None

        self._json = json.loads(result)
        if self._json is None:
            Log.error("No JSON was returned from get nodes command")
            return

        self._items = self._json.get("items")
        if self._items is None:
            Log.error("No items dictonary in get nodes JSON")
            return

        self._node_count = len(self._items)
예제 #25
0
    def get_mapr_use_node_labels(self, label):
        nodes_set = 0
        nodes_not_set = set()

        for node in self._items:
            node_name = node["metadata"]["name"]
            mapr_usenode = node["metadata"]["labels"].get(label)

            if mapr_usenode is not None:
                nodes_set += 1
                Log.info("Node: {0} has {1} label set to: {2}".format(node_name, label, mapr_usenode))
            else:
                nodes_not_set.add(node_name)
                Log.info("Node: {0} does not have {1} label set".format(node_name, label))

        Log.info("{0} node(s) found, {1} node(s) tagged with the MapR usage tag {2} while {3} node(s) not"
                 .format(self._node_count, nodes_set, label, len(nodes_not_set)), stdout=True)
        return nodes_not_set
예제 #26
0
    def run(self):
        # vms = self.compute_client.virtual_machines.list(self.resource_group)
        # for vm in vms:
        #     nic = vm.network_profile.network_interfaces
        #     pass

        nics = self.network_client.network_interfaces.list(self.resource_group)
        for nic in nics:
            ipconfig = nic.ip_configurations[0]

            public_ip_name = "{0}-publicip".format(nic.name)
            public_ip = {
                'location': self.location,
                'public_ip_allocation_method': 'Dynamic'
            }

            if ipconfig.public_ip_address is not None:
                Log.info(
                    "{0} NIC already has a public ip address".format(nic.name),
                    True)
                continue

            Log.info(
                "Creating or updating public ip address {0}...".format(
                    public_ip_name), True)
            ip_rslt = self.network_client.public_ip_addresses.create_or_update(
                self.resource_group, public_ip_name, public_ip)
            ip_rslt.wait()

            public_ip = self.network_client.public_ip_addresses.get(
                self.resource_group, public_ip_name)
            ipconfig.public_ip_address = public_ip

            params = {
                'location': self.location,
                'ip_configurations': [ipconfig]
            }

            Log.info(
                "Associate public ip address {0} with NIC {1}".format(
                    public_ip_name, nic.name), True)
            ip_rslt = self.network_client.network_interfaces.create_or_update(
                self.resource_group, nic.name, params)
            ip_rslt.wait()
예제 #27
0
    def write_response_file(self):
        if Prompts._instance is None:
            Log.debug(
                'Cannot write a response file prompts are not initialized')
            return

        if self.mode != Prompts.RECORD_MODE:
            Log.debug('Cannot write a response file when not in record mode')
            return

        if self.response_file.closed:
            Log.warn(
                'Cannot write a response file that is not opened. Response file can only be written once'
            )
            return

        try:
            sorted_keys = sorted(self.recorded_options)
            for key in sorted_keys:
                self.response_file.write(
                    '%s=%s%s' % (key, self.recorded_options[key], os.linesep))
        finally:
            self.response_file.close()
예제 #28
0
    def __init__(self, env, compute_client):
        self.env = env
        self.compute_client = compute_client

        self.aks_rg = self.env.get("RESOURCE_GROUP")
        self.aks_name = self.env.get("AKS_NAME")
        self.location = self.env.get("LOCATION")
        self.data_disk_count = self.env.get_int("DATA_DISK_COUNT")
        self.data_disk_size = self.env.get_int("DATA_DISK_SIZE")
        self.data_disk_type = self.env.get("DATA_DISK_TYPE")

        self.resource_group = "MC_{0}_{1}_{2}".format(self.aks_rg, self.aks_name, self.location)

        if self.data_disk_type is None:
            Log.info("DATA_DISK_TYPE not supplied, using Standard_LRS", True)
            self.data_disk_type = StorageAccountTypes.standard_lrs
        elif (self.data_disk_type != "Standard_LRS") and \
             (self.data_disk_type != "StandardSSD_LRS") and \
             (self.data_disk_type != "Premium_LRS"):
            Log.info("Invalid disk type {0}, using Standard_LRS".format(self.data_disk_type), True)
            self.data_disk_type = StorageAccountTypes.standard_lrs
        else:
            Log.info("Creating data disks of type; {0}".format(self.data_disk_type), True)
예제 #29
0
 def get_clients(self):
     Log.info("Getting Azure clients...", True)
     self.resource_client = ResourceManagementClient(self.credentials, self.context.subscription_id)
     self.compute_client = ComputeManagementClient(self.credentials, self.context.subscription_id)
     self.network_client = NetworkManagementClient(self.credentials, self.context.subscription_id)
     self.monitor_client = MonitorClient(self.credentials, self.context.subscription_id)
예제 #30
0
 def pas_complete_installation():
     Log.info("PAS Installation complete")