Esempio n. 1
0
 def _install_upstream_deb(self):
     log.info("Found upstream deb, installing that instead")
     filename = os.path.basename(self.config.getopt("upstream_deb"))
     try:
         Container.run(
             self.container_name,
             "dpkg -i /home/ubuntu/.cloud-install/{}".format(filename),
             output_cb=self.set_progress_output,
         )
     except:
         # Make sure deps are installed if any new ones introduced by
         # the upstream packaging.
         Container.run(self.container_name, "apt-get install -qyf", output_cb=self.set_progress_output)
Esempio n. 2
0
 def _install_upstream_deb(self):
     log.info('Found upstream deb, installing that instead')
     filename = os.path.basename(self.config.getopt('upstream_deb'))
     try:
         Container.run(
             self.container_name,
             'dpkg -i /home/ubuntu/.cloud-install/{}'.format(filename),
             output_cb=self.set_progress_output)
     except:
         # Make sure deps are installed if any new ones introduced by
         # the upstream packaging.
         Container.run(self.container_name,
                       'apt-get install -qyf',
                       output_cb=self.set_progress_output)
Esempio n. 3
0
 def read_juju_log(self):
     try:
         return Container.run(self.container_name, 'tail -n 10 '
                              '/var/log/juju-ubuntu-local'
                              '/all-machines.log')
     except Exception:
         return "Waiting..."
Esempio n. 4
0
    def cloud_init_finished(self, tries, maxlenient=20):
        """checks cloud-init result.json in container to find out status

        For the first `maxlenient` tries, it treats a container with
        no IP and SSH errors as non-fatal, assuming initialization is
        still ongoing. Afterwards, will raise exceptions for those
        errors, so as not to loop forever.

        returns True if cloud-init finished with no errors, False if
        it's not done yet, and raises an exception if it had errors.

        """
        cmd = 'sudo cat /run/cloud-init/result.json'
        try:
            result_json = Container.run(self.container_name, cmd)

        except NoContainerIPException as e:
            log.debug("Container has no IPs according to lxc-info. "
                      "Will retry.")
            return False

        except ContainerRunException as e:
            _, returncode = e.args
            if returncode == 255:
                if tries < maxlenient:
                    log.debug("Ignoring initial SSH error.")
                    return False
                raise e
            if returncode == 1:
                # the 'cat' did not find the file.
                if tries < 1:
                    log.debug("Waiting for cloud-init status result")
                return False
            else:
                log.debug("Unexpected return code from reading "
                          "cloud-init status in container.")
                raise e

        if result_json == '':
            return False

        try:
            ret = json.loads(result_json)
        except Exception as e:
            if tries < maxlenient + 10:
                log.debug("exception trying to parse '{}'"
                          " - retrying".format(result_json))
                return False

            log.error(str(e))
            log.debug("exception trying to parse '{}'".format(result_json))
            raise e

        errors = ret['v1']['errors']
        if len(errors):
            log.error("Container cloud-init finished with "
                      "errors: {}".format(errors))
            raise Exception("Top-level container OS did not initialize "
                            "correctly.")
        return True
Esempio n. 5
0
 def test_bootstrap_succeeded(self):
     """ Verifies a local bootstrap happened
     """
     cmd = "JUJU_HOME=~/.cloud-install/juju juju stat --format yaml"
     out = Container.run(self.CONFIG["container_name"], cmd, use_ssh=True)
     out = out.split("\n")[0].strip()
     assert "environment: local" in out
 def read_juju_log(self):
     try:
         return Container.run(self.container_name, 'tail -n 10 '
                              '/var/log/juju-ubuntu-local'
                              '/all-machines.log')
     except Exception:
         return "Waiting..."
    def cloud_init_finished(self, tries, maxlenient=20):
        """checks cloud-init result.json in container to find out status

        For the first `maxlenient` tries, it treats a container with
        no IP and SSH errors as non-fatal, assuming initialization is
        still ongoing. Afterwards, will raise exceptions for those
        errors, so as not to loop forever.

        returns True if cloud-init finished with no errors, False if
        it's not done yet, and raises an exception if it had errors.

        """
        cmd = 'sudo cat /run/cloud-init/result.json'
        try:
            result_json = Container.run(self.container_name, cmd)

        except NoContainerIPException as e:
            log.debug("Container has no IPs according to lxc-info. "
                      "Will retry.")
            return False

        except ContainerRunException as e:
            _, returncode = e.args
            if returncode == 255:
                if tries < maxlenient:
                    log.debug("Ignoring initial SSH error.")
                    return False
                raise e
            if returncode == 1:
                # the 'cat' did not find the file.
                if tries < 1:
                    log.debug("Waiting for cloud-init status result")
                return False
            else:
                log.debug("Unexpected return code from reading "
                          "cloud-init status in container.")
                raise e

        if result_json == '':
            return False

        try:
            ret = json.loads(result_json)
        except Exception as e:
            if tries < maxlenient + 10:
                log.debug("exception trying to parse '{}'"
                          " - retrying".format(result_json))
                return False

            log.error(str(e))
            log.debug("exception trying to parse '{}'".format(result_json))
            raise e

        errors = ret['v1']['errors']
        if len(errors):
            log.error("Container cloud-init finished with "
                      "errors: {}".format(errors))
            raise Exception("Top-level container OS did not initialize "
                            "correctly.")
        return True
Esempio n. 8
0
 def test_bootstrap_succeeded(self):
     """ Verifies a local bootstrap happened
     """
     cmd = ("JUJU_HOME=~/.cloud-install/juju juju stat --format yaml")
     out = Container.run(self.CONFIG['container_name'], cmd, use_ssh=True)
     out = out.split("\n")[0].strip()
     assert ('environment: local' in out)
 def read_cloud_init_output(self):
     try:
         s = Container.run(self.container_name, 'tail -n 10 '
                           '/var/log/cloud-init-output.log')
         return s.replace('\r', '')
     except Exception:
         return "Waiting..."
Esempio n. 10
0
 def test_container_ip_matches(self):
     """ Verifies container ip in config matches
     what LXC sees
     """
     saved_ip = self.CONFIG['container_ip']
     lxc_ip = Container.ip(self.CONFIG['container_name'])
     assert saved_ip == lxc_ip
Esempio n. 11
0
 def test_container_ip_matches(self):
     """ Verifies container ip in config matches
     what LXC sees
     """
     saved_ip = self.CONFIG["container_ip"]
     lxc_ip = Container.ip(self.CONFIG["container_name"])
     assert saved_ip == lxc_ip
Esempio n. 12
0
 def read_cloud_init_output(self):
     try:
         s = Container.run(self.container_name, 'tail -n 10 '
                           '/var/log/cloud-init-output.log')
         return s.replace('\r', '')
     except Exception:
         return "Waiting..."
Esempio n. 13
0
    def add_static_route(self, lxc_net):
        """ Adds static route to host system
        """
        # Store container IP in config
        ip = Container.ip(self.container_name)
        self.config.setopt("container_ip", ip)

        log.info("Adding static route for {} via {}".format(lxc_net, ip))

        out = utils.get_command_output("ip route add {} via {} dev lxcbr0".format(lxc_net, ip))
        if out["status"] != 0:
            raise Exception("Could not add static route for {}" " network: {}".format(lxc_net, out["output"]))
Esempio n. 14
0
    def add_static_route(self, lxc_net):
        """ Adds static route to host system
        """
        # Store container IP in config
        ip = Container.ip(self.container_name)
        self.config.setopt('container_ip', ip)

        log.info("Adding static route for {} via {}".format(lxc_net, ip))

        out = utils.get_command_output(
            'ip route add {} via {} dev lxcbr0'.format(lxc_net, ip))
        if out['status'] != 0:
            raise Exception("Could not add static route for {}"
                            " network: {}".format(lxc_net, out['output']))
    def do_install(self):
        self.display_controller.status_info_message("Building environment")
        if os.path.exists(self.container_abspath):
            raise Exception("Container exists, please uninstall or kill "
                            "existing cloud before proceeding.")

        # check for deb early, will actually install it later
        upstream_deb = self.config.getopt('upstream_deb')
        if upstream_deb and not os.path.isfile(upstream_deb):
            raise Exception("Upstream deb '{}' "
                            "not found.".format(upstream_deb))

        utils.ssh_genkey()

        self.setup_apt_proxy()

        self.prep_userdata()

        utils.render_charm_config(self.config)

        self.prep_juju()

        self.set_perms()

        self.create_container_and_wait()

        # Copy over host ssh keys
        Container.cp(self.container_name,
                     os.path.join(utils.install_home(), '.ssh/id_rsa*'),
                     '.ssh/.')

        # Install local copy of openstack installer if provided
        if upstream_deb:
            shutil.copy(upstream_deb, self.config.cfg_path)
            self._install_upstream_deb()

        # Stop before we attempt to access container
        if self.config.getopt('install_only'):
            log.info("Done installing, stopping here per --install-only.")
            self.config.setopt('install_only', True)
            self.loop.exit(0)

        # Update jujus no-proxy setting if applicable
        if self.config.getopt('http_proxy') or \
           self.config.getopt('https_proxy'):
            log.info("Updating juju environments for proxy support")
            lxc_net = self.config.getopt('lxc_network')
            self.config.update_environments_yaml(
                key='no-proxy',
                val='{},localhost,{}'.format(
                    Container.ip(self.container_name),
                    netutils.get_ip_set(lxc_net)))

        # start the party
        cloud_status_bin = ['openstack-status']
        self.tasker.start_task("Bootstrapping Juju",
                               self.read_progress_output)
        Container.run(self.container_name,
                      "{0} juju --debug bootstrap".format(
                          self.config.juju_home(use_expansion=True)),
                      use_ssh=True, output_cb=self.set_progress_output)
        Container.run(
            self.container_name,
            "{0} juju status".format(
                self.config.juju_home(use_expansion=True)),
            use_ssh=True)
        self.tasker.stop_current_task()

        self.display_controller.status_info_message(
            "Starting cloud deployment")
        Container.run_status(
            self.container_name, " ".join(cloud_status_bin), self.config)
    def create_container_and_wait(self):
        """ Creates container and waits for cloud-init to finish
        """
        self.tasker.start_task("Creating Container",
                               self.read_container_status)

        Container.create(self.container_name, self.userdata)

        with open(os.path.join(self.container_abspath, 'fstab'), 'w') as f:
            f.write("{0} {1} none bind,create=dir\n".format(
                self.config.cfg_path,
                'home/ubuntu/.cloud-install'))
            f.write("/var/cache/lxc var/cache/lxc none bind,create=dir\n")
            # Detect additional charm plugins and make available to the
            # container.
            charm_plugin_dir = self.config.getopt('charm_plugin_dir')
            if charm_plugin_dir \
               and self.config.cfg_path not in charm_plugin_dir:
                plug_dir = os.path.abspath(
                    self.config.getopt('charm_plugin_dir'))
                plug_base = os.path.basename(plug_dir)
                f.write("{d} home/ubuntu/{m} "
                        "none bind,create=dir\n".format(d=plug_dir,
                                                        m=plug_base))

            extra_mounts = os.getenv("EXTRA_BIND_DIRS", None)
            if extra_mounts:
                for d in extra_mounts.split(','):
                    mountpoint = os.path.basename(d)
                    f.write("{d} home/ubuntu/{m} "
                            "none bind,create=dir\n".format(d=d,
                                                            m=mountpoint))

        # update container config
        with open(os.path.join(self.container_abspath, 'config'), 'a') as f:
            f.write("lxc.mount.auto = cgroup:mixed\n"
                    "lxc.start.auto = 1\n"
                    "lxc.start.delay = 5\n"
                    "lxc.mount = {}/fstab\n".format(self.container_abspath))

        lxc_logfile = os.path.join(self.config.cfg_path, 'lxc.log')

        Container.start(self.container_name, lxc_logfile)

        Container.wait_checked(self.container_name,
                               lxc_logfile)

        self.tasker.start_task("Initializing Container",
                               self.read_cloud_init_output)
        tries = 0
        while not self.cloud_init_finished(tries):
            time.sleep(1)
            tries += 1

        # we do this here instead of using cloud-init, for greater
        # control over ordering
        log.debug("Container started, cloud-init done.")

        lxc_network = self.write_lxc_net_config()
        self.add_static_route(lxc_network)

        self.tasker.start_task("Installing Dependencies",
                               self.read_progress_output)
        log.debug("Installing openstack & openstack-single directly, "
                  "and juju-local, libvirt-bin and lxc via deps")
        Container.run(self.container_name,
                      "env DEBIAN_FRONTEND=noninteractive apt-get -qy "
                      "-o Dpkg::Options::=--force-confdef "
                      "-o Dpkg::Options::=--force-confold "
                      "install openstack openstack-single ",
                      output_cb=self.set_progress_output)
        log.debug("done installing deps")
Esempio n. 17
0
    def do_install(self):
        self.display_controller.status_info_message("Building environment")
        if os.path.exists(self.container_abspath):
            raise Exception("Container exists, please uninstall or kill "
                            "existing cloud before proceeding.")

        # check for deb early, will actually install it later
        upstream_deb = self.config.getopt('upstream_deb')
        if upstream_deb and not os.path.isfile(upstream_deb):
            raise Exception("Upstream deb '{}' "
                            "not found.".format(upstream_deb))

        utils.ssh_genkey()

        self.setup_apt_proxy()

        self.prep_userdata()

        utils.render_charm_config(self.config)

        self.prep_juju()

        self.set_perms()

        self.create_container_and_wait()

        # Copy over host ssh keys
        Container.cp(self.container_name,
                     os.path.join(utils.install_home(), '.ssh/id_rsa*'),
                     '.ssh/.')

        # Install local copy of openstack installer if provided
        if upstream_deb:
            shutil.copy(upstream_deb, self.config.cfg_path)
            self._install_upstream_deb()

        # Stop before we attempt to access container
        if self.config.getopt('install_only'):
            log.info("Done installing, stopping here per --install-only.")
            self.config.setopt('install_only', True)
            self.loop.exit(0)

        # Update jujus no-proxy setting if applicable
        if self.config.getopt('http_proxy') or \
           self.config.getopt('https_proxy'):
            log.info("Updating juju environments for proxy support")
            lxc_net = self.config.getopt('lxc_network')
            self.config.update_environments_yaml(
                key='no-proxy',
                val='{},localhost,{}'.format(Container.ip(self.container_name),
                                             netutils.get_ip_set(lxc_net)))

        # start the party
        cloud_status_bin = ['openstack-status']
        self.tasker.start_task("Bootstrapping Juju", self.read_progress_output)
        Container.run(self.container_name,
                      "{0} juju --debug bootstrap".format(
                          self.config.juju_home(use_expansion=True)),
                      use_ssh=True,
                      output_cb=self.set_progress_output)
        Container.run(self.container_name,
                      "{0} juju status".format(
                          self.config.juju_home(use_expansion=True)),
                      use_ssh=True)
        self.tasker.stop_current_task()

        self.display_controller.status_info_message(
            "Starting cloud deployment")
        Container.run_status(self.container_name, " ".join(cloud_status_bin),
                             self.config)
Esempio n. 18
0
    def create_container_and_wait(self):
        """ Creates container and waits for cloud-init to finish
        """
        self.tasker.start_task("Creating Container",
                               self.read_container_status)

        Container.create(self.container_name, self.userdata)

        with open(os.path.join(self.container_abspath, 'fstab'), 'w') as f:
            f.write("{0} {1} none bind,create=dir\n".format(
                self.config.cfg_path, 'home/ubuntu/.cloud-install'))
            f.write("/var/cache/lxc var/cache/lxc none bind,create=dir\n")
            # Detect additional charm plugins and make available to the
            # container.
            charm_plugin_dir = self.config.getopt('charm_plugin_dir')
            if charm_plugin_dir \
               and self.config.cfg_path not in charm_plugin_dir:
                plug_dir = os.path.abspath(
                    self.config.getopt('charm_plugin_dir'))
                plug_base = os.path.basename(plug_dir)
                f.write("{d} home/ubuntu/{m} "
                        "none bind,create=dir\n".format(d=plug_dir,
                                                        m=plug_base))

            extra_mounts = os.getenv("EXTRA_BIND_DIRS", None)
            if extra_mounts:
                for d in extra_mounts.split(','):
                    mountpoint = os.path.basename(d)
                    f.write("{d} home/ubuntu/{m} "
                            "none bind,create=dir\n".format(d=d, m=mountpoint))

        # update container config
        with open(os.path.join(self.container_abspath, 'config'), 'a') as f:
            f.write("lxc.mount.auto = cgroup:mixed\n"
                    "lxc.start.auto = 1\n"
                    "lxc.start.delay = 5\n"
                    "lxc.mount = {}/fstab\n".format(self.container_abspath))

        lxc_logfile = os.path.join(self.config.cfg_path, 'lxc.log')

        Container.start(self.container_name, lxc_logfile)

        Container.wait_checked(self.container_name, lxc_logfile)

        self.tasker.start_task("Initializing Container",
                               self.read_cloud_init_output)
        tries = 0
        while not self.cloud_init_finished(tries):
            time.sleep(1)
            tries += 1

        # we do this here instead of using cloud-init, for greater
        # control over ordering
        log.debug("Container started, cloud-init done.")

        lxc_network = self.write_lxc_net_config()
        self.add_static_route(lxc_network)

        self.tasker.start_task("Installing Dependencies",
                               self.read_progress_output)
        log.debug("Installing openstack & openstack-single directly, "
                  "and juju-local, libvirt-bin and lxc via deps")
        Container.run(self.container_name,
                      "env DEBIAN_FRONTEND=noninteractive apt-get -qy "
                      "-o Dpkg::Options::=--force-confdef "
                      "-o Dpkg::Options::=--force-confold "
                      "install openstack openstack-single ",
                      output_cb=self.set_progress_output)
        log.debug("done installing deps")
Esempio n. 19
0
 def read_cloud_init_output(self):
     try:
         s = Container.run(self.container_name, "tail -n 10 " "/var/log/cloud-init-output.log")
         return s.replace("\r", "")
     except Exception:
         return "Waiting..."