示例#1
0
 def _login(self, api_url, api_key):
     cmd = ['ssh', '-i', os.path.expanduser('~/.ssh/id_maas'),
            '-o', 'UserKnownHostsFile=/dev/null',
            '-o', 'StrictHostKeyChecking=no',
            '-o', 'LogLevel=quiet',
            '{}@{}'.format(self.ssh_user, self.maas_ip),
            'maas', 'login', 'maas', api_url, api_key]
     execc(cmd, stdin=self.cmd_stdin)
示例#2
0
    def configure_maas(self, client, maas_config):
        """Configures the MAAS instance."""
        nodegroup = self.get_nodegroup(client, maas_config)
        self.update_nodegroup(client, nodegroup, maas_config)
        self.create_nodegroup_interfaces(client, nodegroup, maas_config)

        nodes = maas_config.get('nodes', [])
        self._create_maas_nodes(client, nodes)

        self._render_environments_yaml()
        log.debug("Uploading Juju environments.yaml to MAAS vm")

        target = '.juju/'
        script = """
        sudo -u juju mkdir -p /home/juju/%s
        """ % (target)
        util.exec_script_remote(maas_config['user'], self.ip_addr, script)

        cmd = self.get_scp_cmd(maas_config['user'], self.ip_addr,
                               JUJU_ENV_YAML)
        util.execc(cmd)

        script = """
        chown juju: %s; sudo mv %s /home/juju/%s
        """ % (JUJU_ENV_YAML, JUJU_ENV_YAML,  target)
        util.exec_script_remote(maas_config['user'], self.ip_addr, script)

        if os.path.exists(util.USER_PRESEED_DIR) and \
           os.path.isdir(util.USER_PRESEED_DIR):
            log.debug('Copying over custom preseed files.')
            cmd = self.get_scp_cmd(maas_config['user'], self.ip_addr,
                                   util.USER_PRESEED_DIR, scp_opts=['-r'])
            util.execc(cmd)

            # Move them to the maas dir
            script = """
            chown maas:maas preseeds/*
            sudo mv preseeds/* /etc/maas/preseeds/
            rmdir preseeds
            """
            util.exec_script_remote(maas_config['user'], self.ip_addr, script)

        # Start juju domain
        juju_node = self._get_juju_nodename(nodes)
        if juju_node is not None:
            try:
                util.virsh(['start', juju_node])
            except CalledProcessError as exc:
                # Ignore already started error
                msg = 'Domain is already active'
                if msg not in exc.output:
                    raise

                log.debug(msg)

        self._wait_for_nodes_to_commission(client)
        self._claim_sticky_ip_address(client, maas_config)
        log.debug("Done")
示例#3
0
 def _login(self, api_url, api_key):
     cmd = [
         'ssh', '-i',
         os.path.expanduser('~/.ssh/id_maas'), '-o',
         'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no',
         '-o', 'LogLevel=quiet', '{}@{}'.format(self.ssh_user,
                                                self.maas_ip), 'maas',
         'login', 'maas', api_url, api_key
     ]
     execc(cmd, stdin=self.cmd_stdin)
示例#4
0
 def wait_for_vm_ready(self, user, host):
     cmd = self.get_ssh_cmd(user, host, remote_cmd=['true'])
     while True:
         try:
             util.execc(cmd, suppress_stderr=True)
             log.debug("MAAS vm started.")
             break
         except CalledProcessError:
             log.debug("Waiting for MAAS vm to start.")
             time.sleep(1)
             continue
示例#5
0
 def wait_for_vm_ready(self, user, host):
     cmd = self.get_ssh_cmd(user, host, remote_cmd=['true'])
     while True:
         try:
             util.execc(cmd, suppress_stderr=True)
             log.debug("MAAS vm started.")
             break
         except CalledProcessError:
             log.debug("Waiting for MAAS vm to start.")
             time.sleep(1)
             continue
示例#6
0
    def configure_maas_virsh_control(self, maas_config):
        """Configure the virsh control SSH keys"""
        virsh_info = maas_config.get('virsh')
        if not virsh_info:
            log.debug('No virsh settings specified in maas_config.')
            return

        KEY_TO_FILE_MAP = {
            'rsa_priv_key': 'id_rsa',
            'rsa_pub_key': 'id_rsa.pub',
            'dsa_priv_key': 'id_dsa',
            'dsa_pub_key': 'id_dsa.pub',
        }

        # First, make the remote directory.
        remote_cmd = ['mkdir', '-p', 'virsh-keys']
        cmd = self.get_ssh_cmd(maas_config['user'],
                               self.ip_addr,
                               remote_cmd=remote_cmd)
        util.execc(cmd)

        for key, value in virsh_info.iteritems():
            # not a key of interest
            if not key.endswith('_key'):
                continue

            src = os.path.expanduser(value)
            if not os.path.isfile(src):
                raise MAASDeployerValueError("Virsh SSH key '%s' not found" %
                                             (src))

            dst = 'virsh-keys/%s' % KEY_TO_FILE_MAP[key]
            cmd = self.get_scp_cmd(maas_config['user'], self.ip_addr, src, dst)
            util.execc(cmd)

        # Now move them over to the maas user.
        script = """
        maas_home=$(echo ~maas)
        sudo mkdir -p $maas_home/.ssh
        sudo mv ~/virsh-keys/* $maas_home/.ssh
        sudo chown -R maas:maas $maas_home/.ssh
        sudo chmod 700 $maas_home/.ssh
        sudo find $maas_home/.ssh -name id* | xargs sudo chmod 600
        rmdir ~/virsh-keys
        """
        util.exec_script_remote(maas_config['user'], self.ip_addr, script)
示例#7
0
    def configure_maas_virsh_control(self, maas_config):
        """Configure the virsh control SSH keys"""
        virsh_info = maas_config.get('virsh')
        if not virsh_info:
            log.debug('No virsh settings specified in maas_config.')
            return

        KEY_TO_FILE_MAP = {
            'rsa_priv_key': 'id_rsa',
            'rsa_pub_key': 'id_rsa.pub',
            'dsa_priv_key': 'id_dsa',
            'dsa_pub_key': 'id_dsa.pub',
        }

        # First, make the remote directory.
        remote_cmd = ['mkdir', '-p', 'virsh-keys']
        cmd = self.get_ssh_cmd(maas_config['user'], self.ip_addr,
                               remote_cmd=remote_cmd)
        util.execc(cmd)

        for key in virsh_info:
            # not a key of interest
            if not key.endswith('_key'):
                continue

            value = virsh_info[key]
            src = os.path.expanduser(value)
            if not os.path.isfile(src):
                raise MAASDeployerValueError("Virsh SSH key '%s' not found"
                                             % (src))

            dst = 'virsh-keys/%s' % KEY_TO_FILE_MAP[key]
            cmd = self.get_scp_cmd(maas_config['user'], self.ip_addr, src, dst)
            util.execc(cmd)

        # Now move them over to the maas user.
        script = """
        maas_home=$(echo ~maas)
        sudo mkdir -p $maas_home/.ssh
        sudo mv ~/virsh-keys/* $maas_home/.ssh
        sudo chown -R maas:maas $maas_home/.ssh
        sudo chmod 700 $maas_home/.ssh
        sudo find $maas_home/.ssh -name id* | xargs sudo chmod 600
        rmdir ~/virsh-keys
        """
        util.exec_script_remote(maas_config['user'], self.ip_addr, script)
示例#8
0
    def wait_for_cloudinit_finished(self, maas_config, maas_ip):
        log.debug("Logging into maas host '%s'", (maas_ip))
        # Now get the api key
        msg = "MAAS controller is now configured"
        cloudinitlog = '/var/log/cloud-init-output.log'
        rcmd = ['grep "%s" %s' % (msg, cloudinitlog)]
        cmd = self.get_ssh_cmd(maas_config['user'], maas_ip, remote_cmd=rcmd)
        out, err = util.execc(cmd=cmd, fatal=False)
        if out and not err:
            self._get_api_key_from_cloudinit(maas_config['user'], maas_ip)
            return

        log.info("Waiting for cloud-init to complete - this usually takes "
                 "several minutes")
        rcmd = ['grep -m 1 "%s" <(sudo tail -n 1 -F %s)' % (msg, cloudinitlog)]
        cmd = self.get_ssh_cmd(maas_config['user'], maas_ip, remote_cmd=rcmd)
        util.execc(cmd=cmd)
        log.info("done.")
        self._get_api_key_from_cloudinit(maas_config['user'], maas_ip)
示例#9
0
    def _get_api_key_from_cloudinit(self, user, addr):
        # Now get the api key
        rcmd = [r'grep "+ apikey=" %s| tail -n 1| sed -r "s/.+=(.+)/\1/"' %
                ('/var/log/cloud-init-output.log')]
        cmd = self.get_ssh_cmd(user, addr, remote_cmd=rcmd)
        stdout, _ = util.execc(cmd=cmd)
        if stdout:
            stdout = stdout.strip()

        self.api_key = stdout
示例#10
0
    def _get_api_key_from_cloudinit(self, user, addr):
        # Now get the api key
        rcmd = [
            r'grep "+ apikey=" %s| tail -n 1| sed -r "s/.+=(.+)/\1/"' %
            ('/var/log/cloud-init-output.log')
        ]
        cmd = self.get_ssh_cmd(user, addr, remote_cmd=rcmd)
        stdout, _ = util.execc(cmd=cmd)
        if stdout:
            stdout = stdout.strip()

        self.api_key = stdout
示例#11
0
    def wait_for_cloudinit_finished(self, maas_config, maas_ip):
        log.debug("Logging into maas host '%s'", (maas_ip))
        # Now get the api key
        msg = "MAAS controller is now configured"
        cloudinitlog = '/var/log/cloud-init-output.log'
        rcmd = ['grep "%s" %s' %
                (msg, cloudinitlog)]
        cmd = self.get_ssh_cmd(maas_config['user'], maas_ip,
                               remote_cmd=rcmd)
        out, err = util.execc(cmd=cmd, fatal=False)
        if out and not err:
            self._get_api_key_from_cloudinit(maas_config['user'], maas_ip)
            return

        log.info("Waiting for cloud-init to complete - this usually takes "
                 "several minutes")
        rcmd = ['grep -m 1 "%s" <(sudo tail -n 1 -F %s)' %
                (msg, cloudinitlog)]
        cmd = self.get_ssh_cmd(maas_config['user'], maas_ip,
                               remote_cmd=rcmd)
        util.execc(cmd=cmd)
        log.info("done.")
        self._get_api_key_from_cloudinit(maas_config['user'], maas_ip)
示例#12
0
    def _get_api_key(self, maas_config):
        """Retrieves the API key"""
        if not self.api_key:
            log.debug("Fetching MAAS api key")
            user = maas_config['user']
            remote_cmd = ['sudo', 'maas-region-admin', 'apikey', '--username',
                          user]
            cmd = self.get_ssh_cmd(maas_config['user'], self.ip_addr,
                                   remote_cmd=remote_cmd)
            self.api_key, _ = util.execc(cmd)

        if self.api_key:
            self.api_key = self.api_key.strip()

        return self.api_key
示例#13
0
    def _get_api_key(self, maas_config):
        """Retrieves the API key"""
        if not self.api_key:
            log.debug("Fetching MAAS api key")
            user = maas_config['user']
            remote_cmd = [
                'sudo', 'maas-region-admin', 'apikey', '--username', user
            ]
            cmd = self.get_ssh_cmd(maas_config['user'],
                                   self.ip_addr,
                                   remote_cmd=remote_cmd)
            self.api_key, _ = util.execc(cmd)

        if self.api_key:
            self.api_key = self.api_key.strip()

        return self.api_key
示例#14
0
    def test_execc_piped_stderr(self):
        tmpdir = tempfile.mkdtemp()
        try:
            # expect error
            cmd1 = ['ls', os.path.join(tmpdir, '1')]
            self.assertRaises(subprocess.CalledProcessError, util.execc, cmd1)

            open(os.path.join(tmpdir, '2'), 'w')

            # expect NO error
            cmd1 = ['ls', os.path.join(tmpdir, '2')]
            util.execc(cmd1)

            # expect error
            cmd1 = ['ls', os.path.join(tmpdir, '1')]
            cmd2 = ['ls', os.path.join(tmpdir, '2')]
            open(os.path.join(tmpdir, '2'), 'w')
            self.assertRaises(subprocess.CalledProcessError, util.execc,
                              cmd1, pipedcmds=[cmd2])

            # expect NO error
            cmd1 = ['ls', os.path.join(tmpdir, '2')]
            cmd2 = ['ls', os.path.join(tmpdir, '2')]
            open(os.path.join(tmpdir, '2'), 'w')
            util.execc(cmd1, pipedcmds=[cmd2])

            # test exception params
            cmd1 = ['ls', os.path.join(tmpdir, '1')]
            cmd2 = ['ls', os.path.join(tmpdir, '2')]
            open(os.path.join(tmpdir, '2'), 'w')
            try:
                util.execc(cmd1, pipedcmds=[cmd2])
            except subprocess.CalledProcessError as exc:
                test_passed = False
                for msg in [("ls: cannot access %s: No such file or "
                             "directory\n"),
                            ("ls: cannot access '%s': No such file or "
                             "directory\n")]:
                    try:
                        self.assertEqual(exc.output,
                                         msg % (os.path.join(tmpdir, '1')))
                        test_passed = True
                        break
                    except AssertionError:
                        pass

                self.assertTrue(test_passed, exc.output)
                self.assertEqual(exc.returncode, 2)
            else:
                raise UnitTestException("Exception not raised")

        finally:
            shutil.rmtree(tmpdir)
示例#15
0
    def _maas_execute(self, cmd, *args, **kwargs):
        """
        Executes the specified subcommand. The keyword maas and the profile
        name will be prepended to the name
        """
        try:
            cmdarr = self._get_base_command()
            cmdarr.append(str(cmd))
            if args:
                for a in args:
                    cmdarr.append(str(a))
            if kwargs:
                for key in kwargs.keys():
                    value = kwargs[key]
                    if isinstance(value, list):
                        for v in value:
                            cmdarr.append("%s='%s'" % (key, str(v)))
                    else:
                        cmdarr.append("%s='%s'" % (key, str(value)))

            stdout = execc(cmdarr, stdin=self.cmd_stdin)[0]

            display_stdout = stdout
            if display_stdout and len(display_stdout) > 100:
                display_stdout = "%s..." % display_stdout[:100]

            log.debug("Command executed successfully: stdout='%s'",
                      display_stdout)

            try:
                output = json.loads(stdout)
            except ValueError:
                output = stdout

            return Response(True, output)
        except CalledProcessError as cpe:
            log.error("Command '%s' failed: rc='%s' output='%s'",
                      ' '.join(cmdarr), cpe.returncode, cpe.output)
            return Response(False, cpe.output)
        except OSError as ose:
            log.error("Command '%s' failed: error='%s'", ' '.join(cmdarr),
                      str(ose))
            return Response(False, None)
示例#16
0
    def _maas_execute(self, cmd, *args, **kwargs):
        """
        Executes the specified subcommand. The keyword maas and the profile
        name will be prepended to the name
        """
        try:
            cmdarr = self._get_base_command()
            cmdarr.append(str(cmd))
            if args:
                for a in args:
                    cmdarr.append(str(a))
            if kwargs:
                for key in kwargs.keys():
                    value = kwargs[key]
                    if isinstance(value, list):
                        for v in value:
                            cmdarr.append("%s='%s'" % (key, str(v)))
                    else:
                        cmdarr.append("%s='%s'" % (key, str(value)))

            stdout = execc(cmdarr, stdin=self.cmd_stdin)[0]

            display_stdout = stdout
            if display_stdout and len(display_stdout) > 100:
                display_stdout = "%s..." % display_stdout[:100]

            log.debug("Command executed successfully: stdout='%s'",
                      display_stdout)

            try:
                output = json.loads(stdout)
            except ValueError:
                output = stdout

            return Response(True, output)
        except CalledProcessError as cpe:
            log.error("Command '%s' failed: rc='%s' output='%s'",
                      ' '.join(cmdarr), cpe.returncode, cpe.output)
            return Response(False, cpe.output)
        except OSError as ose:
            log.error("Command '%s' failed: error='%s'", ' '.join(cmdarr),
                      str(ose))
            return Response(False, None)
示例#17
0
    def _create_new_boot_source(self, client, maas_config, url, keyring_data,
                                keyring_filename):
        log.debug("Creating new boot source url='%s'", (url))
        # If we want to supply new keyring data we have to write it to
        # a file, upload it and reference that from the cli.
        if keyring_data:
            ssh_user = maas_config['user']
            remote_host = self.ip_addr
            with tempfile.NamedTemporaryFile() as ftmp:
                with open(ftmp.name, 'w') as fd:
                    fd.write(base64.b64decode(keyring_data))

                filepath = "/tmp/maas-deployer-archive-keyring.gpg"
                util.execc(
                    self.get_scp_cmd(ssh_user, remote_host, ftmp.name,
                                     filepath))

                target = (keyring_filename or "/usr/share/keyrings/%s" %
                          (os.path.basename(filepath)))
                log.debug("Writing boot source key '%s'", (target))
                cmd = ['sudo', 'mv', filepath, target]
                util.execc(
                    self.get_ssh_cmd(ssh_user, remote_host, remote_cmd=cmd))
                cmd = ['sudo', 'chmod', '0644', target]
                util.execc(
                    self.get_ssh_cmd(ssh_user, remote_host, remote_cmd=cmd))
                cmd = ['sudo', 'chown', 'root:', target]
                util.execc(
                    self.get_ssh_cmd(ssh_user, remote_host, remote_cmd=cmd))

                keyring_filename = target

        ret = client.create_boot_source(url, keyring_filename=keyring_filename)
        if not ret:
            msg = "Failed to create boot resource url='%s'" % (url)
            log.error(msg)
            raise MAASDeployerClientError(msg)
示例#18
0
    def _create_new_boot_source(self, client, maas_config, url, keyring_data,
                                keyring_filename):
        log.debug("Creating new boot source url='%s'",  (url))
        # If we want to supply new keyring data we have to write it to
        # a file, upload it and reference that from the cli.
        if keyring_data:
            ssh_user = maas_config['user']
            remote_host = self.ip_addr
            with tempfile.NamedTemporaryFile() as ftmp:
                with open(ftmp.name, 'w') as fd:
                    fd.write(base64.b64decode(keyring_data))

                filepath = "/tmp/maas-deployer-archive-keyring.gpg"
                util.execc(self.get_scp_cmd(ssh_user, remote_host, ftmp.name,
                                            filepath))

                target = (keyring_filename or "/usr/share/keyrings/%s" %
                          (os.path.basename(filepath)))
                log.debug("Writing boot source key '%s'",  (target))
                cmd = ['sudo', 'mv', filepath, target]
                util.execc(self.get_ssh_cmd(ssh_user, remote_host,
                                            remote_cmd=cmd))
                cmd = ['sudo', 'chmod', '0644', target]
                util.execc(self.get_ssh_cmd(ssh_user, remote_host,
                                            remote_cmd=cmd))
                cmd = ['sudo', 'chown', 'root:', target]
                util.execc(self.get_ssh_cmd(ssh_user, remote_host,
                                            remote_cmd=cmd))

                keyring_filename = target

        ret = client.create_boot_source(url, keyring_filename=keyring_filename)
        if not ret:
            msg = "Failed to create boot resource url='%s'" % (url)
            log.error(msg)
            raise MAASDeployerClientError(msg)
示例#19
0
    def test_execc_piped_stderr(self):
        tmpdir = tempfile.mkdtemp()
        try:
            # expect error
            cmd1 = ['ls', os.path.join(tmpdir, '1')]
            self.assertRaises(subprocess.CalledProcessError, util.execc, cmd1)

            open(os.path.join(tmpdir, '2'), 'w')

            # expect NO error
            cmd1 = ['ls', os.path.join(tmpdir, '2')]
            util.execc(cmd1)

            # expect error
            cmd1 = ['ls', os.path.join(tmpdir, '1')]
            cmd2 = ['ls', os.path.join(tmpdir, '2')]
            open(os.path.join(tmpdir, '2'), 'w')
            self.assertRaises(subprocess.CalledProcessError,
                              util.execc,
                              cmd1,
                              pipedcmds=[cmd2])

            # expect NO error
            cmd1 = ['ls', os.path.join(tmpdir, '2')]
            cmd2 = ['ls', os.path.join(tmpdir, '2')]
            open(os.path.join(tmpdir, '2'), 'w')
            util.execc(cmd1, pipedcmds=[cmd2])

            # test exception params
            cmd1 = ['ls', os.path.join(tmpdir, '1')]
            cmd2 = ['ls', os.path.join(tmpdir, '2')]
            open(os.path.join(tmpdir, '2'), 'w')
            try:
                util.execc(cmd1, pipedcmds=[cmd2])
            except subprocess.CalledProcessError as exc:
                self.assertEqual(
                    exc.output, "ls: cannot access %s: No such file or "
                    "directory\n" % (os.path.join(tmpdir, '1')))
                self.assertEqual(exc.returncode, 2)
            else:
                raise UnitTestException("Exception not raised")

        finally:
            shutil.rmtree(tmpdir)
示例#20
0
    def configure_maas(self, client, maas_config):
        """Configures the MAAS instance."""
        nodegroup = self.get_nodegroup(client, maas_config)
        self.update_nodegroup(client, nodegroup, maas_config)
        self.create_nodegroup_interfaces(client, nodegroup, maas_config)

        nodes = maas_config.get('nodes', [])
        self._create_maas_nodes(client, nodes)

        self._render_environments_yaml()
        log.debug("Uploading Juju environments.yaml to MAAS vm")

        target = '.juju/'
        script = """
        sudo -u juju mkdir -p /home/juju/%s
        """ % (target)
        util.exec_script_remote(maas_config['user'], self.ip_addr, script)

        cmd = self.get_scp_cmd(maas_config['user'], self.ip_addr,
                               JUJU_ENV_YAML)
        util.execc(cmd)

        script = """
        chown juju: %s; sudo mv %s /home/juju/%s
        """ % (JUJU_ENV_YAML, JUJU_ENV_YAML, target)
        util.exec_script_remote(maas_config['user'], self.ip_addr, script)

        if os.path.exists(util.USER_PRESEED_DIR) and \
           os.path.isdir(util.USER_PRESEED_DIR):
            log.debug('Copying over custom preseed files.')
            cmd = self.get_scp_cmd(maas_config['user'],
                                   self.ip_addr,
                                   util.USER_PRESEED_DIR,
                                   scp_opts=['-r'])
            util.execc(cmd)

            # Move them to the maas dir
            script = """
            chown maas:maas preseeds/*
            sudo mv preseeds/* /etc/maas/preseeds/
            rmdir preseeds
            """
            util.exec_script_remote(maas_config['user'], self.ip_addr, script)

        # Start juju domain
        for n in nodes:
            name = n['name']
            try:
                log.info('Starting: %s' % name)
                util.virsh(['start', name])
            except CalledProcessError as exc:
                # Ignore already started error
                msg = 'Domain is already active'
                if msg not in exc.output:
                    raise

                log.debug(msg)

        self._wait_for_nodes_to_commission(client)
        self._claim_sticky_ip_address(client, maas_config)
        log.debug("Done")