예제 #1
0
    def yes(self, answer: str) -> None:
        log.info('Configuring nova control plane services ...')

        if not call('openstack', 'user', 'show', 'nova'):
            check('openstack', 'user', 'create', '--domain', 'default',
                  '--password',
                  shell.config_get('config.credentials.nova-password'), 'nova')
            check('openstack', 'role', 'add', '--project', 'service', '--user',
                  'nova', 'admin')
            # Assign the reader role to the nova user so that read-only
            # application credentials can be created.
            check('openstack', 'role', 'add', '--project', 'service', '--user',
                  'nova', 'reader')

        log.info('Running Nova API DB migrations'
                 ' (this may take a lot of time)...')
        check('snap-openstack', 'launch', 'nova-manage', 'api_db', 'sync')

        if 'cell0' not in check_output('snap-openstack', 'launch',
                                       'nova-manage', 'cell_v2', 'list_cells'):
            check('snap-openstack', 'launch', 'nova-manage', 'cell_v2',
                  'map_cell0')

        if 'cell1' not in check_output('snap-openstack', 'launch',
                                       'nova-manage', 'cell_v2', 'list_cells'):

            check('snap-openstack', 'launch', 'nova-manage', 'cell_v2',
                  'create_cell', '--name=cell1', '--verbose')

        log.info('Running Nova DB migrations'
                 ' (this may take a lot of time)...')
        check('snap-openstack', 'launch', 'nova-manage', 'db', 'sync')

        enable('nova-api')
        restart('nova-compute')

        for service in [
                'nova-api-metadata',
                'nova-conductor',
                'nova-scheduler',
        ]:
            enable(service)

        nc_wait(_env['compute_ip'], '8774')

        sleep(5)  # TODO: log_wait

        if not call('openstack', 'service', 'show', 'compute'):
            check('openstack', 'service', 'create', '--name', 'nova',
                  '--description', '"Openstack Compute"', 'compute')
            for endpoint in ['public', 'internal', 'admin']:
                call('openstack', 'endpoint', 'create', '--region',
                     'microstack', 'compute', endpoint,
                     'http://{control_ip}:8774/v2.1'.format(**_env))

        log.info('Creating default flavors...')

        self._flavors()
예제 #2
0
    def yes(self, answer: bool):
        log.info('Configuring clustering ...')

        role_question = clustering.Role()
        if not (self.interactive and self.role_interactive):
            role_question.interactive = False
        role_question.ask()

        questions = [
            # Skipped for the compute role and is automatically taken
            # from the connection string.
            clustering.ControlIp(),
            # Skipped for the control role since it is identical to the
            # control node IP.
            clustering.ComputeIp(),
        ]
        for question in questions:
            if not self.interactive:
                question.interactive = False
            question.ask()

        connection_string_question = clustering.ConnectionString()
        if not (self.interactive and self.connection_string_interactive):
            connection_string_question.interactive = False
        connection_string_question.ask()

        role = shell.config_get('config.cluster.role')

        if role == 'compute':
            log.info('Setting up as a compute node.')
            # Gets config info and sets local env vals.
            check_output('microstack_join')
            shell.config_set(
                **{
                    'config.services.control-plane': 'false',
                    'config.services.hypervisor': 'true',
                })

        if role == 'control':
            log.info('Setting up as a control node.')
            shell.config_set(
                **{
                    'config.services.control-plane': 'true',
                    'config.services.hypervisor': 'true',
                })
            # Generate a self-signed certificate for the clustering service.
            cluster_tls.generate_selfsigned()

        # Write templates
        check('snap-openstack', 'setup')
예제 #3
0
    def yes(self, answer: str) -> None:
        """Since this is an auto question, we always execute yes."""
        log.info('Loading config and writing templates ...')

        log.info('Validating config ...')
        for key in ['ospassword', 'extgateway', 'extcidr', 'dns']:
            val = check_output('snapctl', 'get', key)
            if not val:
                raise ConfigError(
                    'Expected config value {} is not set.'.format(key))
            _env[key] = val

        log.info('Writing out templates ...')
        check('snap-openstack', 'setup')

        # Parse microstack.rc, and load into _env
        # TODO: write something more robust (this breaks on comments
        # at end of line.)
        mstackrc = '{SNAP_COMMON}/etc/microstack.rc'.format(**_env)
        with open(mstackrc, 'r') as rc_file:
            for line in rc_file.readlines():
                if not line.startswith('export'):
                    continue
                key, val = line[7:].split('=')
                _env[key.strip()] = val.strip()
예제 #4
0
    def yes(self, answer: str) -> None:
        log.info('Configuring the Cinder services...')

        if not call('openstack', 'user', 'show', 'cinder'):
            check('openstack', 'user', 'create', '--domain', 'default',
                  '--password',
                  shell.config_get('config.credentials.cinder-password'),
                  'cinder')
            check('openstack', 'role', 'add', '--project', 'service', '--user',
                  'cinder', 'admin')

        control_ip = _env['control_ip']
        for endpoint in ['public', 'internal', 'admin']:
            for api_version in ['v2', 'v3']:
                if not call('openstack', 'service', 'show',
                            f'cinder{api_version}'):
                    check('openstack', 'service', 'create', '--name',
                          f'cinder{api_version}', '--description',
                          f'"Cinder {api_version} API"',
                          f'volume{api_version}')
                if not check_output('openstack', 'endpoint', 'list',
                                    '--service', f'volume{api_version}',
                                    '--interface', endpoint):
                    check(
                        'openstack', 'endpoint', 'create', '--region',
                        'microstack', f'volume{api_version}', endpoint,
                        f'http://{control_ip}:8776/{api_version}/'
                        '$(project_id)s')
        log.info('Running Cinder DB migrations...')
        check('snap-openstack', 'launch', 'cinder-manage', 'db', 'sync')

        enable('cinder-uwsgi')
        enable('cinder-scheduler')
예제 #5
0
 def _wait(self) -> None:
     enable('mysqld')
     mysql_port = check_output('snapctl', 'get',
                               'config.network.ports.mysql')
     nc_wait(_env['control_ip'], mysql_port)
     log_wait('{SNAP_COMMON}/log/mysql/error.log'.format(**_env),
              'mysqld: ready for connections.')
예제 #6
0
    def yes(self, answer: str) -> None:

        if 'microstack' not in check_output('openstack', 'keypair', 'list'):
            log.info('Creating microstack keypair (~/.ssh/{})'.format(answer))
            check('mkdir', '-p', '{HOME}/.ssh'.format(**_env))
            check('chmod', '700', '{HOME}/.ssh'.format(**_env))
            id_ = check_output('openstack', 'keypair', 'create', 'microstack')
            id_path = '{HOME}/.ssh/{answer}'.format(HOME=_env['HOME'],
                                                    answer=answer)

            with open(id_path, 'w') as file_:
                file_.write(id_)
            check('chmod', '600', id_path)
            # TODO: too many assumptions in the below. Make it portable!
            user = _env['HOME'].split("/")[2]
            check('chown', '{}:{}'.format(user, user), id_path)
예제 #7
0
 def _wait(self) -> None:
     enable('rabbitmq-server')
     rabbit_port = check_output('snapctl', 'get',
                                'config.network.ports.rabbit')
     nc_wait(_env['control_ip'], rabbit_port)
     log_file = '{SNAP_COMMON}/log/rabbitmq/startup_log'.format(**_env)
     log_wait(log_file, 'completed')
예제 #8
0
    def wrapper(*args, **kwargs):
        if int(check_output('id', '-u')):
            log.error("This script must be run with root privileges. "
                      "Please re-run with sudo.")
            sys.exit(1)

        return func(*args, **kwargs)
예제 #9
0
    def yes(self, answer: str) -> None:
        # Create security group rules
        log.info('Creating security group rules ...')
        group_id = check_output('openstack', 'security', 'group', 'list',
                                '--project', 'admin', '-f', 'value', '-c',
                                'ID')
        rules = check_output('openstack', 'security', 'group', 'rule', 'list',
                             '--format', 'json')
        ping_rule = False
        ssh_rule = False

        for rule in json.loads(rules):
            if rule['Security Group'] == group_id:
                if rule['IP Protocol'] == 'icmp':
                    ping_rule = True
                if rule['IP Protocol'] == 'tcp':
                    ssh_rule = True

        if not ping_rule:
            check('openstack', 'security', 'group', 'rule', 'create', group_id,
                  '--proto', 'icmp')
        if not ssh_rule:
            check('openstack', 'security', 'group', 'rule', 'create', group_id,
                  '--proto', 'tcp', '--dst-port', '22')
예제 #10
0
    def _is_hw_virt_supported():
        # Sample lscpu outputs: util-linux/tests/expected/lscpu/
        cpu_info = json.loads(check_output('lscpu', '-J'))['lscpu']
        architecture = next(
            filter(lambda x: x['field'] == 'Architecture:', cpu_info),
            None)['data'].split()
        flags = next(filter(lambda x: x['field'] == 'Flags:', cpu_info), None)
        if flags is not None:
            flags = flags['data'].split()

        vendor_id = next(
            filter(lambda x: x['field'] == 'Vendor ID:', cpu_info), None)
        if vendor_id is not None:
            vendor_id = vendor_id['data']

        # Mimic virt-host-validate code (from libvirt) and assume nested
        # support on ppc64 LE or BE.
        if architecture in ['ppc64', 'ppc64le']:
            return True
        elif vendor_id is not None and flags is not None:
            if vendor_id == 'AuthenticAMD' and 'svm' in flags:
                return True
            elif vendor_id == 'GenuineIntel' and 'vmx' in flags:
                return True
            elif vendor_id == 'IBM/S390' and 'sie' in flags:
                return True
            elif vendor_id == 'ARM':
                # ARM 8.3-A added nested virtualization support but it is yet
                # to land upstream https://lwn.net/Articles/812280/ at the time
                # of writing (Nov 2020).
                log.warning('Nested virtualization is not supported on ARM'
                            ' - will use emulation')
                return False
            else:
                log.warning('Unable to determine hardware virtualization'
                            f' support by CPU vendor id "{vendor_id}":'
                            ' assuming it is not supported.')
                return False
        else:
            log.warning('Unable to determine hardware virtualization support'
                        ' by the output of lscpu: assuming it is not'
                        ' supported')
            return False
예제 #11
0
    def _load(self):
        """Get the current value of the answer to this question.

        Useful for loading defaults during init, and for loading
        operator specified settings during updates.

        """
        # Translate the CamelCase name of this class to the dash
        # seperated name of a key in the snapctl config.
        key = inflection.dasherize(
            inflection.underscore(self.__class__.__name__))

        answer = shell.check_output('snapctl', 'get',
                                    'questions.{key}'.format(key=key))
        # Convert boolean values in to human friendly "yes" or "no"
        # values.
        if answer.strip().lower() == 'true':
            answer = 'yes'
        if answer.strip().lower() == 'false':
            answer = 'no'

        return answer
예제 #12
0
    def yes(self, answer: str) -> None:
        """Possibly force us to use qemu emulation rather than kvm."""

        cpuinfo = check_output('cat', '/proc/cpuinfo')
        if 'vmx' in cpuinfo or 'svm' in cpuinfo:
            # We have processor extensions installed. No need to Force
            # Qemu emulation.
            return

        _path = '{SNAP_COMMON}/etc/nova/nova.conf.d/hypervisor.conf'.format(
            **_env)

        with open(_path, 'w') as _file:
            _file.write("""\
[DEFAULT]
compute_driver = libvirt.LibvirtDriver

[workarounds]
disable_rootwrap = True

[libvirt]
virt_type = qemu
cpu_mode = host-model
""")
예제 #13
0
    def _load(self):
        """Get the current value of the answer to this question.

        Useful for loading defaults during init, and for loading
        operator specified settings during updates.

        """
        if self._type == 'auto':
            return

        answer = shell.check_output('snapctl', 'get',
                                    '{key}'.format(key=self.config_key))
        # Convert boolean values in to human friendly "yes" or "no"
        # values.
        if answer.strip().lower() == 'true':
            answer = 'yes'
        if answer.strip().lower() == 'false':
            answer = 'no'

        # Convert null to None
        if answer.strip().lower() == 'null':
            answer = None

        return answer
예제 #14
0
    def yes(self, answer: str) -> None:
        log.info('Configuring nova ...')

        if not call('openstack', 'user', 'show', 'nova'):
            check('openstack', 'user', 'create', '--domain',
                  'default', '--password', 'nova', 'nova')
            check('openstack', 'role', 'add', '--project',
                  'service', '--user', 'nova', 'admin')

        if not call('openstack', 'user', 'show', 'placement'):
            check('openstack', 'user', 'create', '--domain', 'default',
                  '--password', 'placement', 'placement')
            check('openstack', 'role', 'add', '--project', 'service',
                  '--user', 'placement', 'admin')

        if not call('openstack', 'service', 'show', 'compute'):
            check('openstack', 'service', 'create', '--name', 'nova',
                  '--description', '"Openstack Compute"', 'compute')
            for endpoint in ['public', 'internal', 'admin']:
                call('openstack', 'endpoint', 'create', '--region',
                     'microstack', 'compute', endpoint,
                     'http://{extgateway}:8774/v2.1'.format(**_env))

        if not call('openstack', 'service', 'show', 'placement'):
            check('openstack', 'service', 'create', '--name',
                  'placement', '--description', '"Placement API"',
                  'placement')

            for endpoint in ['public', 'internal', 'admin']:
                call('openstack', 'endpoint', 'create', '--region',
                     'microstack', 'placement', endpoint,
                     'http://{extgateway}:8778'.format(**_env))

        # Grant nova user access to cell0
        sql(
            "GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'{extgateway}' \
            IDENTIFIED BY \'nova';".format(**_env))

        check('snap-openstack', 'launch', 'nova-manage', 'api_db', 'sync')

        if 'cell0' not in check_output('snap-openstack', 'launch',
                                       'nova-manage', 'cell_v2',
                                       'list_cells'):
            check('snap-openstack', 'launch', 'nova-manage',
                  'cell_v2', 'map_cell0')

        if 'cell1' not in check_output('snap-openstack', 'launch',
                                       'nova-manage', 'cell_v2', 'list_cells'):

            check('snap-openstack', 'launch', 'nova-manage', 'cell_v2',
                  'create_cell', '--name=cell1', '--verbose')

        check('snap-openstack', 'launch', 'nova-manage', 'db', 'sync')

        restart('nova-*')

        nc_wait(_env['extgateway'], '8774')

        sleep(5)  # TODO: log_wait

        log.info('Creating default flavors...')
        self._flavors()
예제 #15
0
    def yes(self, answer):
        log.info('Configuring networking ...')

        role = check_output('snapctl', 'get', 'config.cluster.role')

        # Enable and start the services.
        enable('ovsdb-server')
        enable('ovs-vswitchd')
        enable('ovn-ovsdb-server-sb')
        enable('ovn-ovsdb-server-nb')

        network.ExtGateway().ask()
        network.ExtCidr().ask()

        control_ip = check_output('snapctl', 'get',
                                  'config.network.control-ip')
        if role == 'control':
            nb_conn = 'unix:{SNAP_COMMON}/run/ovn/ovnnb_db.sock'.format(**_env)
            sb_conn = 'unix:{SNAP_COMMON}/run/ovn/ovnsb_db.sock'.format(**_env)
            check_output('ovs-vsctl', 'set', 'open', '.',
                         f'external-ids:ovn-encap-ip={control_ip}')
        elif role == 'compute':
            sb_conn = f'tcp:{control_ip}:6642'
            # Not used by any compute node services.
            nb_conn = ''
            compute_ip = check_output('snapctl', 'get',
                                      'config.network.compute-ip')
            # Set the IP address to be used for a tunnel endpoint.
            check_output('ovs-vsctl', 'set', 'open', '.',
                         f'external-ids:ovn-encap-ip={compute_ip}')
        else:
            raise Exception(f'Unexpected node role: {role}')

        # ovn-controller does not start unless both the ovn-encap-ip and the
        # ovn-encap-type are set.
        check_output('ovs-vsctl', 'set', 'open', '.',
                     'external-ids:ovn-encap-type=geneve')

        # Configure OVN SB and NB sockets based on the role node. For
        # single-node deployments there is no need to use a TCP socket.
        check_output('snapctl', 'set',
                     f'config.network.ovn-nb-connection={nb_conn}')
        check_output('snapctl', 'set',
                     f'config.network.ovn-sb-connection={sb_conn}')

        # Set SB database connection details for ovn-controller to pick up.
        check_output('ovs-vsctl', 'set', 'open', '.',
                     f'external-ids:ovn-remote={sb_conn}')
        check_output('ovs-vsctl', 'set', 'open', '.',
                     'external-ids:ovn-cms-options=enable-chassis-as-gw')

        # Now that we have default or overriden values, setup the
        # bridge and write all the proper values into our config
        # files.
        check('setup-br-ex')
        check('snap-openstack', 'setup')

        if role == 'control':

            enable('ovn-northd')
            enable('ovn-controller')

        network.IpForwarding().ask()
예제 #16
0
    def yes(self, answer: str) -> None:
        log.info('Configuring nova ...')

        if not call('openstack', 'user', 'show', 'nova'):
            check('openstack', 'user', 'create', '--domain', 'default',
                  '--password', 'nova', 'nova')
            check('openstack', 'role', 'add', '--project', 'service', '--user',
                  'nova', 'admin')

        if not call('openstack', 'user', 'show', 'placement'):
            check('openstack', 'user', 'create', '--domain', 'default',
                  '--password', 'placement', 'placement')
            check('openstack', 'role', 'add', '--project', 'service', '--user',
                  'placement', 'admin')

        if not call('openstack', 'service', 'show', 'compute'):
            check('openstack', 'service', 'create', '--name', 'nova',
                  '--description', '"Openstack Compute"', 'compute')
            for endpoint in ['public', 'internal', 'admin']:
                call('openstack', 'endpoint', 'create', '--region',
                     'microstack', 'compute', endpoint,
                     'http://{extgateway}:8774/v2.1'.format(**_env))

        if not call('openstack', 'service', 'show', 'placement'):
            check('openstack', 'service', 'create', '--name', 'placement',
                  '--description', '"Placement API"', 'placement')

            for endpoint in ['public', 'internal', 'admin']:
                call('openstack', 'endpoint', 'create', '--region',
                     'microstack', 'placement', endpoint,
                     'http://{extgateway}:8778'.format(**_env))

        # Grant nova user access to cell0
        sql("GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'{extgateway}' \
            IDENTIFIED BY \'nova';".format(**_env))

        # Use snapctl to start nova services.  We need to call them
        # out manually, because systemd doesn't know about them yet.
        # TODO: parse the output of `snapctl services` to get this
        # list automagically.
        for service in [
                environ['SNAP_INSTANCE_NAME'] + '.nova-api',
                environ['SNAP_INSTANCE_NAME'] + '.nova-api-metadata',
                environ['SNAP_INSTANCE_NAME'] + '.nova-compute',
                environ['SNAP_INSTANCE_NAME'] + '.nova-conductor',
                environ['SNAP_INSTANCE_NAME'] + '.nova-scheduler',
                environ['SNAP_INSTANCE_NAME'] + '.nova-uwsgi',
        ]:
            check('snapctl', 'start', service)

        check('snap-openstack', 'launch', 'nova-manage', 'api_db', 'sync')

        if 'cell0' not in check_output('snap-openstack', 'launch',
                                       'nova-manage', 'cell_v2', 'list_cells'):
            check('snap-openstack', 'launch', 'nova-manage', 'cell_v2',
                  'map_cell0')

        if 'cell1' not in check_output('snap-openstack', 'launch',
                                       'nova-manage', 'cell_v2', 'list_cells'):

            check('snap-openstack', 'launch', 'nova-manage', 'cell_v2',
                  'create_cell', '--name=cell1', '--verbose')

        check('snap-openstack', 'launch', 'nova-manage', 'db', 'sync')

        restart('nova-*')

        nc_wait(_env['extgateway'], '8774')

        sleep(5)  # TODO: log_wait

        log.info('Creating default flavors...')
        self._flavors()