Ejemplo n.º 1
0
    def create_base_image(self, builder, template, parameters):
        """
        Create a JEOS image and install any packages specified in the template.

        @param builder The Builder object coordinating image creation.
        @param template A Template object.
        @param parameters Dictionary of target specific parameters.

        @return A BaseImage object.
        """
        self.log.info(
            'create_base_image() called for Nova plugin - creating a BaseImage'
        )

        self.log.debug('Nova.create_base_image() called by builder (%s)' %
                       builder)
        if not parameters:
            parameters = {}
        self.log.debug('parameters set to %s' % parameters)

        builder.base_image.update(
            5, 'PENDING',
            'Collecting build arguments to pass to Nova Image Builder...')
        # Derive the OSInfo OS short_id from the os_name and os_version in template
        if template.os_version:
            if template.os_name[-1].isdigit():
                install_os = '%s.%s' % (template.os_name, template.os_version)
            else:
                install_os = '%s%s' % (template.os_name, template.os_version)
        else:
            install_os = template.os_name

        install_os = install_os.lower()

        install_location = template.install_location
        # TDL uses 'url' but Nova Image Builder uses 'tree'
        install_type = 'tree' if template.install_type == 'url' else template.install_type
        install_script = parameters.get('install_script')
        install_config = {
            'admin_password': parameters.get('admin_password'),
            'license_key': parameters.get('license_key'),
            'arch': template.os_arch,
            'disk_size': parameters.get('disk_size'),
            'flavor': parameters.get('flavor'),
            'storage': parameters.get('storage'),
            'name': template.name,
            'direct_boot': parameters.get('direct_boot', False),
            'timeout': parameters.get('timeout', 1800),
            'public': parameters.get('public', False),
            'floating_ip': parameters.get('request_floating_ip', False)
        }

        builder.base_image.update(10, 'BUILDING',
                                  'Created Nova Image Builder instance...')
        self.nib = Builder(install_os, install_location, install_type,
                           install_script, install_config)
        self.nib.run()

        builder.base_image.update(
            10, 'BUILDING', 'Waiting for Nova Image Builder to complete...')
        jeos_image_id = self.nib.wait_for_completion(180)
        if jeos_image_id:
            builder.base_image.update(
                30, 'BUILDING',
                'JEOS image in glance with id (%s), starting customization...'
                % jeos_image_id)

            self.log.debug(
                'Launching Nova instance with image (%s) for customization & icicle generation.'
                % jeos_image_id)
            img_name = self.nib.env.glance.images.get(jeos_image_id).name
            jeos_instance = self.nib.env.launch_instance(
                name='Customize %s and Generate ICICLE' % img_name,
                root_disk=jeos_image_id,
                flavor=parameters.get('flavor', None))
            if not jeos_instance:
                raise ImageFactoryException(
                    'Reached timeout waiting for customization instance...')

            self.log.debug(
                'Launched Nova instance (id: %s) for customization & icicle generation.'
                % jeos_instance.id)
            if not jeos_instance.open_ssh(
            ):  # Add a security group for ssh access
                raise ImageFactoryException(
                    'Failed to add security group for ssh, cannot continue...')

            user = parameters.get('default_user')
            private_key_file = jeos_instance.key_dir + jeos_instance.key_pair.name
            # Get an IP address to use below for ssh connections to the instance.
            if self._networking_is_active_for_instance(jeos_instance):
                if install_config['floating_ip']:
                    jeos_instance_addr = self._create_ipaddr_for_instance(
                        jeos_instance)
                else:
                    jeos_instance_addr = self._get_ipaddr_for_instance(
                        jeos_instance, user, private_key_file)
                if not jeos_instance_addr:
                    jeos_instance_addr = self._create_ipaddr_for_instance(
                        jeos_instance)
            else:
                raise ImageFactoryException(
                    'Networking not active for instance %s, cannot continue!' %
                    jeos_instance.id)
            if not jeos_instance_addr:
                raise ImageFactoryException(
                    'Unable to obtain an IP address for instance %s' %
                    jeos_instance.id)

            # Enable root for customization steps
            cmd_prefix = parameters.get('command_prefix')
            if user and user != 'root':
                if self._enable_root_from_user_with_command_prefix(
                        user, cmd_prefix, jeos_instance_addr,
                        private_key_file):
                    self.log.debug(
                        'Temporarily enabled root user for image customization steps...'
                    )
                else:
                    raise ImageFactoryException(
                        'Unable to access %s as root. Cannot continue...' %
                        jeos_instance_addr)

            oz_config = self._oz_config(private_key_file)
            if not oz_config:
                raise ImageFactoryException(
                    'No Oz config file found. Cannot continue.')

            oz_guest = oz.GuestFactory.guest_factory(tdl=TDL(str(template)),
                                                     config=oz_config,
                                                     auto=None)

            if self._confirm_ssh_access(oz_guest, jeos_instance_addr):
                self.log.debug('Starting base image customization.')
                oz_guest.do_customize(jeos_instance_addr)
                self.log.debug('Completed base image customization.')

                self.log.debug('Starting ICICLE generation.')
                builder.base_image.update(
                    90, 'BUILDING',
                    'Starting ICICLE generation (glance: %s)...' %
                    jeos_image_id)
                builder.base_image.icicle = oz_guest.do_icicle(
                    jeos_instance_addr)
                self.log.debug('Completed ICICLE generation')

                # Disable ssh access for root
                if user and user != 'root':
                    disable_root(jeos_instance_addr, private_key_file, user,
                                 cmd_prefix)
                    self.log.debug(
                        'Disabling root ssh access now that customization is complete...'
                    )

                jeos_instance.close_ssh(
                )  # Remove security group for ssh access

            else:
                raise ImageFactoryException('Unable to reach %s via ssh.' %
                                            jeos_instance_addr)

            if jeos_instance.shutoff():
                base_image_id = jeos_instance.create_snapshot(template.name +
                                                              '-base')
                builder.base_image.properties[
                    PROPERTY_NAME_GLANCE_ID] = base_image_id
                builder.base_image.update(
                    100, 'COMPLETE',
                    'Image stored in glance with id (%s)' % base_image_id)
                jeos_instance.terminate()
            else:
                raise ImageFactoryException(
                    'JEOS build instance (%s) never shutdown in Nova.' %
                    jeos_instance.id)

        else:
            exc_msg = 'Nova Image Builder failed to return a Glance ID, failing...'
            builder.base_image.update(status='FAILED', error=exc_msg)
            self.log.exception(exc_msg)
            raise ImageFactoryException(exc_msg)
Ejemplo n.º 2
0
    def create_base_image(self, builder, template, parameters):
        """
        Create a JEOS image and install any packages specified in the template.

        @param builder The Builder object coordinating image creation.
        @param template A Template object.
        @param parameters Dictionary of target specific parameters.

        @return A BaseImage object.
        """
        self.log.info('create_base_image() called for Nova plugin - creating a BaseImage')

        self.log.debug('Nova.create_base_image() called by builder (%s)' % builder)
        if not parameters:
            parameters = {}
        self.log.debug('parameters set to %s' % parameters)

        builder.base_image.update(5, 'PENDING', 'Collecting build arguments to pass to Nova Image Builder...')
        # Derive the OSInfo OS short_id from the os_name and os_version in template
        if template.os_version:
            if template.os_name[-1].isdigit():
                install_os = '%s.%s' % (template.os_name, template.os_version)
            else:
                install_os = '%s%s' % (template.os_name, template.os_version)
        else:
            install_os = template.os_name

        install_os = install_os.lower()

        install_location = template.install_location
        # TDL uses 'url' but Nova Image Builder uses 'tree'
        install_type = 'tree' if template.install_type == 'url' else template.install_type
        install_script = parameters.get('install_script')
        install_config = {'admin_password': parameters.get('admin_password'),
                          'license_key': parameters.get('license_key'),
                          'arch': template.os_arch,
                          'disk_size': parameters.get('disk_size'),
                          'flavor': parameters.get('flavor'),
                          'storage': parameters.get('storage'),
                          'name': template.name,
                          'direct_boot': parameters.get('direct_boot', False),
                          'timeout': parameters.get('timeout', 1800),
                          'public': parameters.get('public', False),
                          'floating_ip': parameters.get('request_floating_ip', False)}

        builder.base_image.update(10, 'BUILDING', 'Created Nova Image Builder instance...')
        self.nib = Builder(install_os, install_location, install_type, install_script, install_config)
        self.nib.run()

        builder.base_image.update(10, 'BUILDING', 'Waiting for Nova Image Builder to complete...')
        jeos_image_id = self.nib.wait_for_completion(180)
        if jeos_image_id:
            builder.base_image.update(30, 'BUILDING',
                                      'JEOS image in glance with id (%s), starting customization...' % jeos_image_id)

            self.log.debug('Launching Nova instance with image (%s) for customization & icicle generation.' %
                           jeos_image_id)
            img_name = self.nib.env.glance.images.get(jeos_image_id).name
            jeos_instance = self.nib.env.launch_instance(name='Customize %s and Generate ICICLE' % img_name,
                                                         root_disk=jeos_image_id,
                                                         flavor=parameters.get('flavor', None))
            if not jeos_instance:
                raise ImageFactoryException('Reached timeout waiting for customization instance...')

            self.log.debug('Launched Nova instance (id: %s) for customization & icicle generation.' % jeos_instance.id)
            if not jeos_instance.open_ssh():  # Add a security group for ssh access
                raise ImageFactoryException('Failed to add security group for ssh, cannot continue...')

            user = parameters.get('default_user')
            private_key_file = jeos_instance.key_dir + jeos_instance.key_pair.name
            # Get an IP address to use below for ssh connections to the instance.
            if self._networking_is_active_for_instance(jeos_instance):
                if install_config['floating_ip']:
                    jeos_instance_addr = self._create_ipaddr_for_instance(jeos_instance)
                else:
                    jeos_instance_addr = self._get_ipaddr_for_instance(jeos_instance, user, private_key_file)
                if not jeos_instance_addr:
                    jeos_instance_addr = self._create_ipaddr_for_instance(jeos_instance)
            else:
                raise ImageFactoryException('Networking not active for instance %s, cannot continue!' %
                                            jeos_instance.id)
            if not jeos_instance_addr:
                raise ImageFactoryException('Unable to obtain an IP address for instance %s' % jeos_instance.id)

            # Enable root for customization steps
            cmd_prefix = parameters.get('command_prefix')
            if user and user != 'root':
                if self._enable_root_from_user_with_command_prefix(user, cmd_prefix, jeos_instance_addr,
                                                                   private_key_file):
                    self.log.debug('Temporarily enabled root user for image customization steps...')
                else:
                    raise ImageFactoryException('Unable to access %s as root. Cannot continue...' % jeos_instance_addr)

            oz_config = self._oz_config(private_key_file)
            if not oz_config:
                raise ImageFactoryException('No Oz config file found. Cannot continue.')

            oz_guest = oz.GuestFactory.guest_factory(tdl=TDL(str(template)), config=oz_config, auto=None)

            if self._confirm_ssh_access(oz_guest, jeos_instance_addr):
                self.log.debug('Starting base image customization.')
                oz_guest.do_customize(jeos_instance_addr)
                self.log.debug('Completed base image customization.')

                self.log.debug('Starting ICICLE generation.')
                builder.base_image.update(90, 'BUILDING', 'Starting ICICLE generation (glance: %s)...' % jeos_image_id)
                builder.base_image.icicle = oz_guest.do_icicle(jeos_instance_addr)
                self.log.debug('Completed ICICLE generation')

                # Disable ssh access for root
                if user and user != 'root':
                    disable_root(jeos_instance_addr, private_key_file, user, cmd_prefix)
                    self.log.debug('Disabling root ssh access now that customization is complete...')

                jeos_instance.close_ssh()  # Remove security group for ssh access

            else:
                raise ImageFactoryException('Unable to reach %s via ssh.' % jeos_instance_addr)

            if jeos_instance.shutoff():
                base_image_id = jeos_instance.create_snapshot(template.name + '-base')
                builder.base_image.properties[PROPERTY_NAME_GLANCE_ID] = base_image_id
                builder.base_image.update(100, 'COMPLETE', 'Image stored in glance with id (%s)' % base_image_id)
                jeos_instance.terminate()
            else:
                raise ImageFactoryException('JEOS build instance (%s) never shutdown in Nova.' % jeos_instance.id)

        else:
            exc_msg = 'Nova Image Builder failed to return a Glance ID, failing...'
            builder.base_image.update(status='FAILED', error=exc_msg)
            self.log.exception(exc_msg)
            raise ImageFactoryException(exc_msg)
Ejemplo n.º 3
0
    def create_target_image(self, builder, target, base_image, parameters):
        """
        *** NOT YET IMPLEMENTED ***
        Performs cloud specific customization on the base image.

        @param builder The builder object.
        @param base_image The BaseImage to customize.
        @param target The cloud type to customize for.
        @param parameters Dictionary of target specific parameters.

        @return A TargetImage object.
        """
        self.log.info(
            'create_target_image() called for Nova plugin - creating a TargetImage'
        )

        # Merge together any TDL-style customizations requested via our plugin-to-plugin interface  with any target
        #  specific packages, repos and commands and then run a second Oz customization step.
        tdl = TDL(xmlstring=builder.target_image.template,
                  rootpw_required=self.app_config['tdl_require_root_pw'])

        # We remove any packages, commands and files from the original TDL - these have already been
        # installed/executed.  We leave the repos in place, as it is possible that the target
        # specific packages or commands may require them.
        tdl.packages = []
        tdl.commands = {}
        tdl.files = {}

        # Get user defined repositories and packages from a local config file
        repositories, packages = self._target_content(tdl, target)
        if repositories:
            tdl.merge_repositories(repositories)
        if packages:
            tdl.merge_packages(packages)

        # Content provided by the target plugin for the target plugin
        if len(self._cloud_plugin_content) > 0:
            tdl = self.merge_cloud_content_with_tdl(self._cloud_plugin_content,
                                                    tdl)

        # If there are no new commands, packages or files, we can stop here
        if (len(tdl.packages) + len(tdl.commands) + len(tdl.files)) == 0:
            self.log.debug(
                'No further modification of the TargetImage to perform in the OS Plugin - returning'
            )
            return

        base_image_id = base_image.properties[PROPERTY_NAME_GLANCE_ID]
        stack_env = StackEnvironment()
        base_instance = stack_env.launch_instance(
            name='Target Image Prep',
            root_disk=('glance', base_image_id),
            flavor=parameters.get('flavor'))
        if not base_instance:
            raise ImageFactoryException(
                'Reached timeout waiting for base instance...')
        self.log.debug(
            'Launched Nova instance (id: %s) for target specific customization.'
            % base_instance.id)

        if not base_instance.open_ssh():  # Add A security group for ssh access
            raise ImageFactoryException(
                'Failed to add security group for ssh, cannot continue...')

        user = parameters.get('default_user', 'root')
        private_key_file = base_instance.key_dir + base_instance.key_pair.name
        # Get an IP address to use for ssh connections
        if self._networking_is_active_for_instance(base_instance):
            if parameters.get('request_floating_ip', False):
                base_instance_addr = self._create_ipaddr_for_instance(
                    base_instance)
            else:
                base_instance_addr = self._get_ipaddr_for_instance(
                    base_instance, user, private_key_file)
            if not base_instance_addr:
                base_instance_addr = self._create_ipaddr_for_instance(
                    base_instance)
        else:
            raise ImageFactoryException(
                'Networking not active for instance %s, cannot continue!' %
                base_instance.id)
        if not base_instance_addr:
            raise ImageFactoryException(
                'Unable to obtain IP address for instance %s' %
                base_instance.id)

        # Enable root for target prep steps
        cmd_prefix = parameters.get('command_prefix')
        if user and user != 'root':
            if self._enable_root_from_user_with_command_prefix(
                    user, cmd_prefix, base_instance_addr, private_key_file):
                self.log.debug(
                    'Temporarily enabled root user for target preparation steps...'
                )
            else:
                raise ImageFactoryException(
                    'Unable to access %s as root. Cannot continue...' %
                    base_instance_addr)

        oz_config = self._oz_config(private_key_file)
        if not oz_config:
            raise ImageFactoryException(
                'No Oz config file found. Cannot continue.')

        oz_guest = oz.GuestFactory.guest_factory(tdl=tdl,
                                                 config=oz_config,
                                                 auto=None)

        if self._confirm_ssh_access(oz_guest, base_instance_addr):
            self.log.debug('Starting base image customization.')
            oz_guest.do_customize(base_instance_addr)
            self.log.debug('Completed base image customization.')

            self.log.debug('Starting ICICLE generation.')
            builder.target_image.update(
                85, 'BUILDING',
                'Starting ICICLE generation (glance: %s)...' % base_image_id)
            builder.target_image.icicle = oz_guest.do_icicle(
                base_instance_addr)
            self.log.debug('Completed ICICLE generation')

            # Disable ssh access for root
            if user and user != 'root':
                disable_root(base_instance_addr, private_key_file, user,
                             cmd_prefix)
                self.log.debug(
                    'Disabling root ssh access now that customization is complete...'
                )

            base_instance.close_ssh()  # Remove security group for ssh access

        else:
            raise ImageFactoryException('Unable to reach %s via ssh.' %
                                        base_instance_addr)

        if base_instance.shutoff():
            target_image_id = base_instance.create_snapshot(tdl.name + '-base')
            builder.target_image.properties[
                PROPERTY_NAME_GLANCE_ID] = target_image_id
            builder.target_image.update(
                90, 'BUILDING',
                'Target Image stored in glance with id (%s)' % target_image_id)
            base_instance.terminate()
        else:
            raise ImageFactoryException(
                'JEOS build instance (%s) never shutdown in Nova.' %
                base_instance.id)

        builder.target_image.update(95, 'BUILDING',
                                    'Downloading target image...')
        target_img_download = StackEnvironment().download_image_from_glance(
            target_image_id)
        with open(builder.target_image.data, 'wb') as target_img_file:
            shutil.copyfileobj(target_img_download, target_img_file)
            target_img_file.close()
        target_img_download.close()
Ejemplo n.º 4
0
    def create_target_image(self, builder, target, base_image, parameters):
        """
        *** NOT YET IMPLEMENTED ***
        Performs cloud specific customization on the base image.

        @param builder The builder object.
        @param base_image The BaseImage to customize.
        @param target The cloud type to customize for.
        @param parameters Dictionary of target specific parameters.

        @return A TargetImage object.
        """
        self.log.info('create_target_image() called for Nova plugin - creating a TargetImage')

        # Merge together any TDL-style customizations requested via our plugin-to-plugin interface  with any target
        #  specific packages, repos and commands and then run a second Oz customization step.
        tdl = TDL(xmlstring=builder.target_image.template, rootpw_required=self.app_config['tdl_require_root_pw'])

        # We remove any packages, commands and files from the original TDL - these have already been
        # installed/executed.  We leave the repos in place, as it is possible that the target
        # specific packages or commands may require them.
        tdl.packages = []
        tdl.commands = {}
        tdl.files = {}

        # Get user defined repositories and packages from a local config file
        repositories, packages = self._target_content(tdl, target)
        if repositories:
            tdl.merge_repositories(repositories)
        if packages:
            tdl.merge_packages(packages)

        # Content provided by the target plugin for the target plugin
        if len(self._cloud_plugin_content) > 0:
            tdl = self.merge_cloud_content_with_tdl(self._cloud_plugin_content, tdl)

        # If there are no new commands, packages or files, we can stop here
        if (len(tdl.packages) + len(tdl.commands) + len(tdl.files)) == 0:
            self.log.debug('No further modification of the TargetImage to perform in the OS Plugin - returning')
            return

        base_image_id = base_image.properties[PROPERTY_NAME_GLANCE_ID]
        stack_env = StackEnvironment()
        base_instance = stack_env.launch_instance(name='Target Image Prep',
                                                  root_disk=('glance', base_image_id),
                                                  flavor=parameters.get('flavor'))
        if not base_instance:
            raise ImageFactoryException('Reached timeout waiting for base instance...')
        self.log.debug('Launched Nova instance (id: %s) for target specific customization.' % base_instance.id)

        if not base_instance.open_ssh():  # Add A security group for ssh access
            raise ImageFactoryException('Failed to add security group for ssh, cannot continue...')

        user = parameters.get('default_user', 'root')
        private_key_file = base_instance.key_dir + base_instance.key_pair.name
        # Get an IP address to use for ssh connections
        if self._networking_is_active_for_instance(base_instance):
            if parameters.get('request_floating_ip', False):
                base_instance_addr = self._create_ipaddr_for_instance(base_instance)
            else:
                base_instance_addr = self._get_ipaddr_for_instance(base_instance, user, private_key_file)
            if not base_instance_addr:
                base_instance_addr = self._create_ipaddr_for_instance(base_instance)
        else:
            raise ImageFactoryException('Networking not active for instance %s, cannot continue!' % base_instance.id)
        if not base_instance_addr:
            raise ImageFactoryException('Unable to obtain IP address for instance %s' % base_instance.id)

        # Enable root for target prep steps
        cmd_prefix = parameters.get('command_prefix')
        if user and user != 'root':
            if self._enable_root_from_user_with_command_prefix(user, cmd_prefix, base_instance_addr, private_key_file):
                self.log.debug('Temporarily enabled root user for target preparation steps...')
            else:
                raise ImageFactoryException('Unable to access %s as root. Cannot continue...' % base_instance_addr)

        oz_config = self._oz_config(private_key_file)
        if not oz_config:
            raise ImageFactoryException('No Oz config file found. Cannot continue.')

        oz_guest = oz.GuestFactory.guest_factory(tdl=tdl, config=oz_config, auto=None)

        if self._confirm_ssh_access(oz_guest, base_instance_addr):
            self.log.debug('Starting base image customization.')
            oz_guest.do_customize(base_instance_addr)
            self.log.debug('Completed base image customization.')

            self.log.debug('Starting ICICLE generation.')
            builder.target_image.update(85, 'BUILDING', 'Starting ICICLE generation (glance: %s)...' % base_image_id)
            builder.target_image.icicle = oz_guest.do_icicle(base_instance_addr)
            self.log.debug('Completed ICICLE generation')

            # Disable ssh access for root
            if user and user != 'root':
                disable_root(base_instance_addr, private_key_file, user, cmd_prefix)
                self.log.debug('Disabling root ssh access now that customization is complete...')

            base_instance.close_ssh()  # Remove security group for ssh access

        else:
            raise ImageFactoryException('Unable to reach %s via ssh.' % base_instance_addr)

        if base_instance.shutoff():
            target_image_id = base_instance.create_snapshot(tdl.name + '-base')
            builder.target_image.properties[PROPERTY_NAME_GLANCE_ID] = target_image_id
            builder.target_image.update(90, 'BUILDING', 'Target Image stored in glance with id (%s)' % target_image_id)
            base_instance.terminate()
        else:
            raise ImageFactoryException('JEOS build instance (%s) never shutdown in Nova.' % base_instance.id)

        builder.target_image.update(95, 'BUILDING', 'Downloading target image...')
        target_img_download = StackEnvironment().download_image_from_glance(target_image_id)
        with open(builder.target_image.data, 'wb') as target_img_file:
            shutil.copyfileobj(target_img_download, target_img_file)
            target_img_file.close()
        target_img_download.close()