def build(self, update_application=False, quiet=False): """ Create a virtual machine image of the configured host. Args: update_application (bool): If applicable, update the application definition Yaml file to use this image as host base for the selected provider. Warning, this will reset any yaml file formatting and comments. quiet (bool): If True, hide outputs. Returns: str: Image ID or path (Depending provider) """ manifest = self._packer.build(quiet=quiet) image = self._packer.get_artifact(manifest) if update_application: provider = json_read(self._user_parameters_json)['provider'] try: section = self._application['package'][0][provider] except KeyError: section = self._application['package'][0][provider] = dict() section['type'] = 'vm_image' section['name'] = image self._application.save() return image
def test_json_read_write(tmpdir): """ Test json_read/json_write Args: tmpdir (py.path.local) tmpdir pytest fixture """ from accelpy._common import json_write, json_read from accelpy.exceptions import ConfigurationException json_file = tmpdir.join('file.json') # Test: correct file data = {'key': 'value'} json_write(data, json_file) assert json_read(json_file) == data # Test: badly formatted file json_file.write('{key: ') with pytest.raises(ConfigurationException): json_read(json_file)
def _get_last_version(cls): """ Get last version information from HashiCorp checkpoint API. Returns: dict: Last version information. """ info_cache = join(cls._install_dir(), 'info.json') # Get Last version information from HashiCorp checkpoint API if not isfile(info_cache) or getmtime(info_cache) < time() - 3600.0: # Lazy import: Only used on update from platform import machine, system # Update from the web last_release = cls._download( 'https://checkpoint-api.hashicorp.com/v1/check/' + cls._name()).json() current_version = last_release['current_version'] download_url = last_release['current_download_url'].rstrip('/') # Define platform specific utility executable and archive name arch = machine().lower() arch = {'x86_64': 'amd64'}.get(arch, arch) last_release['archive_name'] = archive_name = \ f"{cls._name()}_{current_version}_{system().lower()}_{arch}.zip" last_release['executable_name'] = \ f'{cls._name()}.exe' if system() == 'Windows' else cls._name() # Define download URL last_release['archive_url'] = f"{download_url}/{archive_name}" last_release['checksum_url'] = checksum_url = \ f"{download_url}/{cls._name()}_{current_version}_SHA256SUMS" last_release['signature_url'] = f"{checksum_url}.sig" # Cache result makedirs(cls._install_dir(), exist_ok=True) json_write(last_release, info_cache) else: # Get cached version last_release = json_read(info_cache) return last_release
def create_configuration(self, provider=None, application_type=None, variables=None, user_config=None): """ Generate packer configuration file. Args: provider (str): Provider name. user_config (path-like object): User configuration directory. vars (dict): Terraform input variables. """ # Lazy import, may not be used from jinja2 import Environment # Get template from this package and user directories sources = dict(vars=dict(variables=variables or dict())) for name, src_path in self._list_sources( provider, application_type, user_config): sources[name] = json_read(src_path) # Generate the Packer template file template = dict() for key in sorted(sources): recursive_update(template, sources[key]) # Evaluate variables that contain Jinja templates variables = template['variables'] env = Environment(extensions=['jinja2.ext.loopcontrols']) to_clean = set() for key in sorted(variables): value = variables[key] if isinstance(value, str) and '{' in value: variables[key] = env.from_string(value).render(variables) # Mark for deletion, Packer does not accept non string as variables elif not isinstance(value, str): to_clean.add(key) for key in to_clean: del variables[key] # Save template json_write(template, self._template)
def create_configuration(self): """ Generate packer configuration file. """ # Lazy import: Only used on new configuration creation from accelpy._ansible import Ansible # Get template from this package and user directories self._variables['ansible'] = Ansible.playbook_exec() sources = dict(vars=dict(variables=self._variables)) for name, src_path in self._list_sources(): sources[name] = json_read(src_path) # Generate the Packer template file template = dict() for key in sorted(sources): recursive_update(template, sources[key]) json_write(template, self._template)
def build(self, quiet=False): """ Build image. Args: quiet (bool): If True, hide outputs. Returns: dict: Packer manifest (Last build only). """ # Build self._exec('build', '-color=false', self._template, pipe_stdout=quiet) # Read manifest file manifest = json_read(join(self._config_dir, 'packer-manifest.json')) last_run_uuid = manifest['last_run_uuid'] for build in manifest['builds']: if build['packer_run_uuid'] == last_run_uuid: return build else: # Should never raise raise RuntimeError( f'No packer manifest for run with UUID {last_run_uuid}')
def __init__(self, name=None, application=None, provider=None, user_config=None, destroy_on_exit=False, keep_config=True): # Initialize some futures values self._ansible_config = None self._packer_config = None self._terraform_config = None self._terraform_output = None self._application_definition = None # If true, Terraform infrastructure is destroyed on exit self._destroy_on_exit = destroy_on_exit self._keep_config = keep_config # Define name if not name: from uuid import uuid1 name = str(uuid1()).replace('-', '') self._name = name # Define configuration directory en files self._config_dir = join(CONFIG_DIR, name) user_parameters_json = join(self._config_dir, 'user_parameters.json') self._output_json = join(self._config_dir, 'output.json') self._accelize_drm_conf_json = join(self._config_dir, 'accelize_drm_conf.json') self._accelize_drm_cred_json = join(self._config_dir, 'cred.json') # Create a new configuration config_exists = isdir(self._config_dir) if not config_exists and application: # Ensure config is cleaned on creation error self._keep_config = False # Create target configuration directory and remove access to other # users since Terraform state files may content sensible data and # directory may contain SSH private key makedirs(self._config_dir, exist_ok=True) chmod(self._config_dir, 0o700) # Get user parameters used self._provider = provider self._user_config = fsdecode(user_config or HOME_DIR) # Save user parameters json_write( dict(provider=self._provider, user_config=self._user_config), user_parameters_json) # Get application and add it as link with configuration self._application_yaml = realpath(fsdecode(application)) # Check Accelize Requirements self._init_accelize_drm() # Add link to configuration symlink(self._application_yaml, join(self._config_dir, 'application.yml')) # Initialize Terraform and Ansible configuration self._terraform.create_configuration() self._ansible.create_configuration() self._packer.create_configuration() self._keep_config = keep_config # Load an existing configuration elif config_exists: # Retrieve application parameters self._application_yaml = realpath( join(self._config_dir, 'application.yml')) # Retrieve user parameters user_parameters = json_read(user_parameters_json) self._provider = user_parameters['provider'] self._user_config = user_parameters['user_config'] # Unable to create configuration else: raise ConfigurationException( 'Require at least an existing host name, or an ' 'application to create a new host.')