Example #1
0
    def deploy(self, openstack_auth: Dict[str, str], reset=False):
        'Deploying a Rally environment'
        logging.info(f"Deploy: Rally environment {self.env_name}")

        with elib.play_on(roles=self.rsc, gather_facts=False) as yaml:
            # Creates the rally database if it does not exist
            yaml.command(
                f'{VENV}/bin/rally db ensure',
                **title('ensure database exists'))

            if not self.env_exists() or reset:
                # Set the tracker of done tasks to 0
                self._tasks = []

                # Creates the rally environment and check that provided
                # `openstack_auth` are correct credentials
                yaml.command(
                    f"{VENV}/bin/rally env delete"
                    f"  --env='{self.env_name}' --force",
                    **title(f'delete environment {self.env_name}'),
                    ignore_errors=True)
                yaml.command(
                    f"{VENV}/bin/rally env create"
                    "   --from-sysenv --no-use"
                    f"  --name='{self.env_name}'",
                    **title(f'create environment {self.env_name}'),
                    environment=openstack_auth)
                yaml.command(
                    f"{VENV}/bin/rally env check "
                    f"  --env='{self.env_name}'",
                    **title('ensure OpenStack credentials are correct'))
Example #2
0
    def pull(agents: List[elib_t.Host]):
        'Pulling the docker image of Shaker '
        logging.info("Pull: get docker image for Shaker")

        with elib.play_on(roles={'all': agents}, gather_facts=False) as yaml:
            yaml.docker_image(**title(f'pulling docker image {IMG}'),
                              name=IMG,
                              source='pull',
                              state='present')
Example #3
0
    def run_scenario(self,
                     scenario: Path,
                     arguments: Dict[str, Any],
                     plugin: Optional[Path] = None,
                     pattern_hosts: str = "all"):
        'Execute the Rally local `scenario` with `arguments`.'
        logging.info(f"Running rally {scenario} in env {self.env_name}")

        scenario_name = scenario.name
        scenario_local_path = str(scenario)
        scenario_remote_path = f'~/{scenario_name}'
        plugin_remote_path = '~/plugin'
        _tag = scenario_name + '-' + str(uuid.uuid4())

        # Executing the scenario
        logging.debug(f'Executing scenario {scenario_name} with tag {_tag}...')
        with elib.play_on(roles=self.rsc,
                          pattern_hosts=pattern_hosts,
                          gather_facts=False) as yaml:
            # Setup the scenario
            yaml.copy(
                **title(f'copy {scenario_name}'),
                src=scenario_local_path,
                dest=scenario_remote_path)

            # Copy plugin if any
            if plugin:
                yaml.copy(**title(f'copy rally plugin {plugin}'),
                          src=str(plugin),
                          dest=plugin_remote_path)

            # Run the scenario
            yaml.command(
                (f'{VENV}/bin/rally'
                 + (f' --plugin-paths {plugin_remote_path}' if plugin else '')
                 + f' task start {scenario_remote_path}'
                 + f' --task-args={shlex.quote(json.dumps(arguments))}'
                 + f' --tag="{_tag}"'
                 + f' --deployment="{self.env_name}"'),
                ignore_errors=True,
                **title(f'execute {scenario_name} (may take a while...)'))

        # Get the uuid and mark the scenario done in the tasks tracker
        uuid_by_hosts = {
            host: values['stdout']
            for host, values
            in elib.run_command(
                f'{VENV}/bin/rally task list --uuids-only'
                f'  --deployment="{self.env_name}"'
                f'  --tag {_tag}',
                roles=self.rsc,
                pattern_hosts=pattern_hosts).get('ok', {}).items()}

        logging.info(f"Scenario finished with uuid {uuid_by_hosts}")
        self._tasks.append((scenario_name, uuid_by_hosts))
Example #4
0
 def env_exists(self) -> bool:
     'Test whether the Rally environment exists or not'
     try:
         with elib.play_on(roles=self.rsc,
                           gather_facts=False,
                           on_error_continue=False) as yaml:
             yaml.raw(f"{VENV}/bin/rally env show '{self.env_name}'")
     except elib.errors.EnosFailedHostsError:
         logging.error('...ignoring')
         return False
     else:
         return True
Example #5
0
    def _resolve_openstack_auth(
            self, globals_values: Dict[str, Any]) -> Dict[str, Any]:
        "Compute and returns the value of `globals_values['openstack_auth']`"

        # Get the former system paths.  We latter load kolla (required by the
        # `put_address_in_context` filter) and change that path.
        old_sys_paths = sys.path.copy()

        # Temporary file to later store the result of the rendered
        # `openstack_auth` variable by Ansible.
        _, osauth_path = tempfile.mkstemp()

        try:
            # Load kolla-ansible specific filters `KOLLA_FILTERS` since the
            # `{{openstack_auth}}` variable relies on the
            # `put_address_in_context` filter to manage IPv6.
            #
            # Note(rcherrueau): we also have to load kolla_ansible because the
            # filter in `KOLLA_FILTERS` does something like `form kolla_ansible
            # import filters`.  We load kolla_ansible from the virtual_env in
            # the system path.  In that case, pbr may complain with: Versioning
            # for this project requires either an sdist tarball, or access
            # to an upstream git repository.  We set pbr to version '1.2.3' to
            # disable all version calculation logic by pbr [0].
            # [0]https://docs.openstack.org/pbr/latest/user/packagers.html#versioning
            ansible_filter_loader.add_directory(
                str(self.venv_path / KOLLA_FILTERS))
            sys.path.append(
                str(self.venv_path / 'lib' / PY_VERSION / 'site-packages'))
            os.environ['PBR_VERSION'] = '1.2.3'

            # Render `openstack_auth` into `osauth_path`
            with elib.play_on(roles={},
                              pattern_hosts="localhost",
                              extra_vars=globals_values) as yaml:
                yaml.local_action(**title(
                    'Compute values of `openstack_auth`'),
                                  module="copy",
                                  content="{{ openstack_auth }}",
                                  dest=osauth_path)

            # Read and return the rendered values from `osauth_path`
            with open(osauth_path, 'r') as rc_yaml:
                return json.load(rc_yaml)

        finally:
            # Delete temporary `osauth_path` file
            os.unlink(osauth_path)
            # Reset system paths
            sys.path = old_sys_paths
Example #6
0
    def backup(self, destination: Path, pattern_hosts: str = "all"):
        'Backup Shaker HOME'
        logging.info(f"Backup Shaker reports for home {self.home}")

        with elib.play_on(roles=self.rsc,
                          pattern_hosts=pattern_hosts,
                          gather_facts=False) as yaml:
            yaml.archive(**title(f"archive HOME {self.home}"),
                         path=self.home,
                         dest=self.home + '.tar.gz',
                         format='gz')
            yaml.fetch(**title(f"fetch HOME {self.home}"),
                       src=self.home + '.tar.gz',
                       dest=str(destination /
                                '{{inventory_hostname}}-shaker.tar.gz'),
                       flat=True)
Example #7
0
    def deploy(self, openstack_auth: Dict[str, str], reset=False):
        'Deploying a Shaker environment'
        logging.info(f"Deploy: make shaker environment {self.home}")

        self._openstack_auth = openstack_auth.copy()

        with elib.play_on(roles=self.rsc, gather_facts=False) as yaml:
            if reset:  # Reset the environment
                yaml.file(**title(f"delete HOME {self.home}"),
                          path=self.home,
                          state="absent")

            # Create the environment
            yaml.file(**title(f"create HOME {self.home}"),
                      path=self.home,
                      state='directory')
Example #8
0
    def run_scenario(self, scenario: str, pattern_hosts: str = "all"):
        'Execute the Shaker `scenario`'
        logging.info(f"Running Shaker {scenario}")

        with elib.play_on(roles=self.rsc,
                          pattern_hosts=pattern_hosts,
                          gather_facts=False) as yaml:
            yaml.docker_container(
                **title(f"run {scenario} (may take a while...)"),
                name=str(uuid.uuid4()),
                image=IMG,
                state='started',
                ports=["11234:11234"],
                detach=False,
                volumes=[f"{self.home}:/artifacts"],
                env=self._openstack_auth,
                command=(' --flavor-name m1.medium'
                         ' --server-endpoint {{ network_interface_ip }}:11234'
                         f' --scenario {scenario}'))
Example #9
0
    def backup(self, destination: Path):
        'Backup kolla-ansible logs and conf'
        logging.info('Backup kolla-ansible logs and conf')
        with elib.play_on(inventory_path=str(self._inventory),
                          extra_vars=self.globals_values) as yaml:
            yaml.archive(
                **title('Archive kolla-ansible logs and conf'),
                format='gz',
                path=[
                    # kolla-ansible logs
                    '/var/lib/docker/volumes/kolla_logs/_data',
                    # kolla-ansible conf
                    '/etc/kolla'
                ],
                dest='/tmp/kolla-log+conf.tar.gz')

            yaml.fetch(**title('Fetch kolla-ansible logs and conf'),
                       flat=True,
                       src='/tmp/kolla-log+conf.tar.gz',
                       dest=(
                           str(destination) +
                           '/{{ inventory_hostname }}-kolla-log+conf.tar.gz'))
Example #10
0
    def pull(agents: List[elib_t.Host]):
        'Installs Rally OpenStack'
        logging.info("Pull: installing rally in a virtual environment")

        with elib.play_on(roles={'all': agents},
                          priors=[elib.api.__python3__],
                          gather_facts=False) as yaml:
            yaml.pip(**title(f'install virtualenv {VENV}'), name='virtualenv')

            # XXX: https://cryptography.io/en/3.4.7/installation.html#rust
            yaml.pip(**title('upgrade pip for cryptography dependency'),
                     name='pip',
                     state='latest',
                     virtualenv=VENV,
                     virtualenv_python='python3')

            # XXX: We fix the version of decorator because of a bug when doing
            # `rally task ...`. See
            # https://bugs.launchpad.net/rally/+bug/1922707
            yaml.pip(**title(f'install {PKG} in {VENV}'),
                     name=[PKG, 'decorator==4.4.2'],
                     state='present',
                     virtualenv=VENV)
Example #11
0
    def pull(pip_package: str, config_dir: Path) -> Path:
        '''Install kolla-ansible in a virtual environment at `config_dir`.

        The name of the virtual environment is computed based on the
        `pip_package`, so calling that method with two different `pip_package`
        values results in two different installations.

        Args:
            pip_package: The kolla-ansible pip package to install.  Package
              could be specified using the pip package syntax.  For instance,
              a PyPi package 'kolla-ansible==2.9.0', a git repository
              'git+https://github.com/openstack/kolla-ansible.git@stable/ussuri',
              or a local editable directory '-e ~/path/to/loca/kolla-ansible'.
            config_dir:  Directory to install kolla-ansible in.
        '''
        logging.info("Installing kolla-ansible and dependencies...")

        # Generates a path for the virtual environment computing a
        # deterministic hash, See https://stackoverflow.com/a/42089311
        pip_ref_hash = int(
            hashlib.sha256(pip_package.encode('utf-8')).hexdigest(),
            16) % 10**8
        venv = (config_dir / f'kolla-ansible-venv-{pip_ref_hash}').resolve()

        # Install kolla-ansible and its dependencies
        with elib.play_on(roles={}, pattern_hosts="localhost") as yaml:
            yaml.local_action(
                **title(f'Install {pip_package} in {venv}'),
                module="pip",
                # Pin Jinja2 version to fix the renaming of `contextfilter`
                # into `pass_context.evalcontextfilter`.
                # See https://github.com/BeyondTheClouds/enos/pull/346#issuecomment-1080851796  # noqa
                name=[ANSIBLE_PKG, 'influxdb', 'Jinja2==3.0.3', pip_package],
                virtualenv=str(venv),
                virtualenv_python=PY_VERSION)

        return venv
Example #12
0
    def backup(self, destination: Path, pattern_hosts: str = "all"):
        'Generates json/html reports and backup them'
        logging.info(f"Backup Rally reports for tasks {self._tasks}")

        # Index the list of uuids by hosts
        hosts_uuids = {}
        for _, uuid_by_hosts in self._tasks:
            for host, _uuid in uuid_by_hosts.items():
                uuids = hosts_uuids.setdefault(host, [])
                uuids.append(_uuid)

        with elib.play_on(roles=self.rsc,
                          pattern_hosts=pattern_hosts,
                          gather_facts=False) as yaml:
            # Generate html and json reports for all tasks
            for host, uuids in hosts_uuids.items():
                yaml.command(
                    f'{VENV}/bin/rally task report '
                    f'  --uuid {" ".join(uuids)} --html-static'
                    f'  --out rally-report.html',
                    **title(f'generate html report for {uuids}'),
                    when=f'inventory_hostname  == "{host}"')
                yaml.command(
                    f'{VENV}/bin/rally task report '
                    f'  --uuid {" ".join(uuids)} --json'
                    f'  --out rally-report.json',
                    **title(f'generate json report for {uuids}'),
                    when=f'inventory_hostname  == "{host}"')

            # Brings reports back
            for ext in ('html', 'json'):
                yaml.fetch(
                    **title(f'fetch the {ext} rally report'),
                    src=f'rally-report.{ext}', flat=True,
                    dest=(str(destination)
                          + '/{{ inventory_hostname }}-rally-report.' + ext))
Example #13
0
def prepare(env=None, **kwargs):
    roles = env["roles"]
    with en.play_on(roles=roles) as p:
        p.debug(msg="Hello World !")