class Heat(SimpleBase): def __init__(self): self.data_key = 'heat' self.data = { } self.services = [ 'heat-api', 'heat-api-cfn', 'heat-engine', ] def init_before(self): self.package = env['cluster']['os_package_map']['heat'] self.prefix = self.package.get('prefix', '/opt/heat') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], }) def setup(self): data = self.init() if self.is_tag('package'): self.python.setup() self.python.setup_package(**self.package) if self.is_tag('conf'): # setup conf files is_updated = filer.template( '/etc/heat/heat.conf', src='{0}/heat.conf.j2'.format(data['version']), data=data, ) if self.is_tag('data') and env.host == env.hosts[0]: utils.oscmd('/opt/heat/bin/heat-keystone-setup-domain \ --stack-user-domain-name {0} \ --stack-domain-admin {1} \ --stack-domain-admin-password {2}'.format( self.data['stack_user_domain_name'], self.data['stack_domain_admin'], self.data['stack_domain_admin_password'])) sudo('{0}/bin/heat-manage db_sync'.format(self.prefix)) if self.is_tag('conf', 'service'): self.enable_services().start_services(pty=False) if is_updated: self.restart_services(pty=False) def cmd(self, cmd): return utils.oscmd('heat {0}'.format(cmd))
class Aodh(SimpleBase): def __init__(self, enable_services=['.*']): self.data_key = 'aodh' self.data = { } default_services = [ 'aodh-api', 'aodh-evaluator', 'aodh-notifier', 'aodh-listener', ] self.services = [] for service in default_services: for enable_service in enable_services: if re.search(enable_service, service): self.services.append(service) break def init_before(self): self.package = env['cluster']['os_package_map']['aodh'] self.prefix = self.package.get('prefix', '/opt/aodh') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], }) def setup(self): data = self.init() if self.is_tag('package'): self.python.setup() self.python.setup_package(**self.package) if self.is_tag('conf'): if filer.template( '/etc/aodh/aodh.conf', src='{0}/aodh.conf.j2'.format(data['version']), data=data, ): self.handlers['restart_aodh-*'] = True if self.is_tag('data') and env.host == env.hosts[0]: sudo('{0}/bin/aodh-dbsync'.format(self.prefix)) if self.is_tag('conf', 'service'): self.enable_services().start_services(pty=False) self.exec_handlers() def cmd(self, cmd): return utils.oscmd('aodh {0}'.format(cmd))
class Horizon(SimpleBase): def __init__(self, data=None): self.data_key = 'horizon' self.data = { 'auth_strategy': 'keystone', 'allowed_hosts': "['*']", } self.services = ['httpd'] self.packages = ['httpd', 'mod_wsgi'] def init_before(self): self.package = env['cluster']['os_package_map']['horizon'] self.prefix = self.package.get('prefix', '/usr') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], 'prefix': self.prefix, }) def setup(self): data = self.init() if self.is_tag('package'): self.install_packages() self.python.setup() self.python.setup_package(**self.package) sudo('sh -c "cd {0}/lib/horizon/ && {1} manage.py collectstatic --noinput"'.format( self.prefix, self.python.get_cmd())) sudo('sh -c "cd {0}/lib/horizon/ && {1} manage.py compress --force"'.format( self.prefix, self.python.get_cmd())) sudo('chown -R apache:apache {0}/lib/horizon'.format(self.prefix)) if self.is_tag('conf'): is_updated = filer.template( self.prefix + '/lib/horizon/openstack_dashboard/local/local_settings.py', src='{0}/local_settings.py.j2'.format(data['version']), data=data, ) is_updated = filer.template( '/etc/httpd/conf.d/horizon_httpd.conf', src='{0}/horizon_httpd.conf.j2'.format(data['version']), data=data, ) or is_updated if self.is_tag('service'): self.enable_services().start_services(pty=False) if is_updated: self.restart_services(pty=False)
class Ironic(SimpleBase): def __init__(self): self.data_key = 'ironic' self.data = { } self.services = [ 'ironic-api', 'ironic-conductor', ] def init_before(self): self.package = env['cluster']['os_package_map']['ironic'] self.prefix = self.package.get('prefix', '/opt/ironic') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], 'neutron': env.cluster['neutron'], 'my_ip': env.node['ip']['default_dev']['ip'], }) def setup(self): data = self.init() if self.is_tag('package'): self.python.setup() self.python.setup_package(**self.package) if self.is_tag('conf'): # setup conf files if filer.template( '/etc/ironic/ironic.conf', src='{0}/ironic.conf.j2'.format(data['version']), data=data): self.handlers['restart_ironic-*'] = True if self.is_tag('data') and env.host == env.hosts[0]: sudo('{0}/bin/ironic-dbsync --config-file /etc/ironic/ironic.conf ' 'upgrade --revision head'.format(self.prefix)) if self.is_tag('conf', 'service'): self.enable_services().start_services(pty=False) self.exec_handlers() def cmd(self, cmd): self.init() return utils.oscmd('ironic {0}'.format(cmd))
class Rally(SimpleBase): def __init__(self): self.data_key = 'rally' self.data = { } self.services = [] def init_before(self): self.package = env['cluster']['os_package_map']['rally'] self.prefix = self.package.get('prefix', '/opt/rally') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], }) def setup(self): data = self.init() if self.is_tag('package'): self.python.setup() self.python.setup_package(**self.package) if self.is_tag('conf'): # setup conf files filer.template( '/etc/rally/rally.conf', src='{0}/rally.conf.j2'.format(data['version']), data=data, ) filer.template( '/etc/rally/rally-existing.json', src='{0}/rally-existing.json.j2'.format(data['version']), data=data, ) if self.is_tag('data') and env.host == env.hosts[0]: sudo('rally deployment list | grep {0} || ' 'rally deployment create --file=/etc/rally/rally-existing.json --name={0}'.format( env.cluster['keystone']['service_region']))
class Glance(SimpleBase): def __init__(self): self.data_key = 'glance' self.data = { 'user': '******', 'paste_deploy': { 'flavor': 'keystone' } } self.services = [ 'glance-api', 'glance-registry', ] def init_before(self): self.package = env['cluster']['os_package_map']['glance'] self.prefix = self.package.get('prefix', '/opt/glance') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], }) def setup(self): data = self.init() if self.is_tag('package'): self.python.setup() self.python.setup_package(**self.package) filer.mkdir(data['glance_store']['filesystem_store_datadir']) if self.is_tag('conf'): # setup conf files if filer.template( '/etc/glance/glance-api.conf', src='{0}/glance-api.conf.j2'.format(data['version']), data=data): self.handlers['restart_glance-api'] = True if filer.template( '/etc/glance/glance-registry.conf', src='{0}/glance-registry.conf.j2'.format(data['version']), data=data): self.handlers['restart_glance-registry'] = True if self.is_tag('data') and env.host == env.hosts[0]: sudo('{0}/bin/glance-manage db_sync'.format(self.prefix)) if self.is_tag('conf', 'service'): self.enable_services().start_services(pty=False) self.exec_handlers() def cmd(self, cmd): self.init() return utils.oscmd('glance {0}'.format(cmd)) def create_image(self, image_name, image_url, disk_format='qcow2', container_format='bare', property='is_public=True'): self.init() result = self.cmd( "image-list 2>/dev/null | grep ' {0} ' | awk '{{print $2}}'".format(image_name)) if len(result) > 0: return result image_file = '/tmp/{0}'.format(image_name) if not filer.exists(image_file): run('wget {0} -O {1}'.format(image_url, image_file)) create_cmd = 'image-create --name "{0}" --disk-format {1}' \ + ' --container-format {2}' \ + ' --property "{3}"' \ + ' --file {4}' result = self.cmd(create_cmd.format( image_name, disk_format, container_format, property, image_file)) result = self.cmd( "image-list 2>/dev/null | grep ' {0} ' | awk '{{print $2}}'".format(image_name)) if len(result) > 0: return result raise Exception('Failed Create Image: {0}'.format(image_name))
class Swift(SimpleBase): def __init__(self): self.data_key = 'swift' self.data = { } self.packages = [ 'liberasurecode-devel', ] self.services = [ 'swift-proxy-server', 'swift-account-server', 'swift-account-auditor', 'swift-account-reaper', 'swift-account-replicator', 'swift-container-server', 'swift-container-auditor', 'swift-container-replicator', 'swift-container-updater', 'swift-object-server', 'swift-object-auditor', 'swift-object-replicator', 'swift-object-updater', ] def init_before(self): self.package = env['cluster']['os_package_map']['swift'] self.prefix = self.package.get('prefix', '/opt/swift') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], }) servers = ':11211,'.join(self.data['memcache_servers']) + ':11211' self.data['memcache_servers'] = servers def setup(self): data = self.init() if self.is_tag('package'): self.install_packages() self.python.setup() self.python.setup_package(**self.package) if self.is_tag('conf'): # setup conf files if filer.template( '/etc/swift/swift.conf', src='{0}/swift/swift.conf.j2'.format(data['version']), data=data): self.handlers['restart_swift-proxy-server'] = True if filer.template( '/etc/swift/proxy-server.conf', src='{0}/swift/proxy-server.conf.j2'.format(data['version']), data=data): self.handlers['restart_swift-proxy-server'] = True if filer.template( '/etc/swift/account-server.conf', src='{0}/swift/account-server.conf.j2'.format(data['version']), data=data): self.handlers['restart_swift-account-server'] = True if filer.template( '/etc/swift/container-server.conf', src='{0}/swift/container-server.conf.j2'.format(data['version']), data=data): self.handlers['restart_swift-container-server'] = True if filer.template( '/etc/swift/object-server.conf', src='{0}/swift/object-server.conf.j2'.format(data['version']), data=data): self.handlers['restart_swift-object-server'] = True if self.is_tag('data'): filer.mkdir('/mnt/swift/main') for ring in ['account', 'object', 'container']: port = data['{0}_port'.format(ring)] sudo('cd /etc/swift &&' '[ -e {0}.builder ] || swift-ring-builder {0}.builder create 9 1 1 && ' '[ -e {0}.ring.gz ] || swift-ring-builder {0}.builder add z1-127.0.0.1:{1}/main 100 &&' # noqa '[ -e {0}.ring.gz ] || swift-ring-builder {0}.builder rebalance'.format(ring, port)) # noqa if self.is_tag('conf', 'service'): self.enable_services().start_services(pty=False) self.exec_handlers() def cmd(self, cmd): self.init() return utils.oscmd('swift {0}'.format(cmd))
class Manila(SimpleBase): def __init__(self): self.data_key = 'manila' self.data = { } self.packages = [ 'nfs-utils', 'nfs4-acl-tools', 'rpcbind', 'lvm2', ] self.services = [ 'manila-api', 'manila-scheduler', 'manila-share', 'rpcbind', 'nfs-server', # 'manila-data', ] def init_before(self): self.package = env['cluster']['os_package_map']['manila'] self.prefix = self.package.get('prefix', '/opt/manila') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], 'neutron': env.cluster['neutron'], 'my_ip': env.node['ip']['default_dev']['ip'], }) def setup(self): data = self.init() if self.is_tag('package'): self.python.setup() self.python.setup_package(**self.package) self.install_packages() # nfs-kernel-server(ubuntuのnfs-server) がないといくつかの処理が失敗する # これは、ファイルに直書きされてるので、nfs-serverからシンボリックリンクを張って代用する # https://github.com/openstack/manila/blob/fb44a0a49e53ebd449bcf2fd6871b3556a149463/manila/share/drivers/helpers.py#L273 nfs_kernel_server = '/usr/lib/systemd/system/nfs-kernel-server.service' if not filer.exists(nfs_kernel_server): sudo('ln -s /usr/lib/systemd/system/nfs-server.service {0}'.format( nfs_kernel_server)) if self.is_tag('conf'): # setup conf files if filer.template( '/etc/manila/manila.conf', src='{0}/manila.conf.j2'.format(data['version']), data=data): self.handlers['restart_manila-*'] = True if self.is_tag('data') and env.host == env.hosts[0]: sudo('{0}/bin/manila-manage --config-file /etc/manila/manila.conf ' 'db sync'.format(self.prefix)) self.setup_lvm() if self.is_tag('conf', 'service'): self.enable_services().start_services(pty=False) self.exec_handlers() if self.is_tag('data') and env.host == env.hosts[0]: with api.warn_only(): result = self.cmd('type-list | grep default_share_type') if result.return_code != 0: self.cmd('type-create default_share_type false') def cmd(self, cmd): self.init() return utils.oscmd('manila {0}'.format(cmd)) def setup_lvm(self): data = self.init() lvm_backend = None for backend in data['backends'].values(): if backend['type'] == 'lvm': lvm_backend = backend if len(lvm_backend) == 0: return volume_group = lvm_backend['volume_group'] Service('lvm2-lvmetad').start().enable() volume_path = '/tmp/{0}'.format(volume_group) if not filer.exists(volume_path): sudo('dd if=/dev/zero of={0} bs=1 count=0 seek=8G'.format(volume_path)) free_loopdev = sudo('losetup -f') sudo('losetup -a | grep {0} || losetup {1} {0}'.format(volume_path, free_loopdev)) loopdev = "`losetup -a | grep {0} | awk -F : '{{print $1}}'`".format(volume_path) sudo("pvscan | grep {0} || pvcreate {0}".format(loopdev)) sudo('pvscan | grep {0} || vgcreate {0} {1}'.format(volume_group, loopdev))
class Cinder(SimpleBase): def __init__(self): self.data_key = "cinder" self.data = {"user": "******"} self.services = ["cinder-api", "cinder-volume", "cinder-scheduler", "target"] self.packages = ["targetcli", "qemu-kvm", "lvm2"] def init_before(self): self.package = env["cluster"]["os_package_map"]["cinder"] self.prefix = self.package.get("prefix", "/opt/cinder") self.python = Python(self.prefix) def init_after(self): self.data.update({"keystone": env.cluster["keystone"]}) def setup(self): data = self.init() self.install_packages() self.python.setup() self.python.setup_package(**self.package) self.setup_lvm() # setup conf files is_updated = filer.template( "/etc/cinder/cinder.conf", src="{0}/cinder.conf.j2".format(self.package["version"]), data=data ) sudo("{0}/bin/cinder-manage db sync".format(self.prefix)) self.enable_services().start_services(pty=False) if is_updated: self.restart_services(pty=False) def cmd(self, cmd): return utils.oscmd("cinder {0}".format(cmd)) def setup_lvm(self): data = self.init() lvm_backend = None for backend in data["backends"].values(): if backend["type"] == "lvm": lvm_backend = backend if len(lvm_backend) == 0: return volume_group = lvm_backend["volume_group"] filer.template("/etc/cinder/lvm.conf", data={"volume_group": volume_group}) Service("lvm2-lvmetad").start().enable() volume_path = "/tmp/{0}".format(volume_group) if not filer.exists(volume_path): sudo("dd if=/dev/zero of={0} bs=1 count=0 seek=8G".format(volume_path)) free_loopdev = sudo("losetup -f") # if re.search(' {0} '.format(volume_group), result) == -1: sudo("losetup -a | grep {0} || losetup {1} {0}".format(volume_path, free_loopdev)) loopdev = "`losetup -a | grep {0} | awk -F : '{{print $1}}'`".format(volume_path) sudo("pvscan | grep {0} || pvcreate {0}".format(loopdev)) sudo("pvscan | grep {0} || vgcreate {0} {1}".format(volume_group, loopdev))
class Nova(SimpleBase): def __init__(self, enable_services=['.*']): self.data_key = 'nova' self.data = { 'debug': 'true', 'verbose': 'true', 'timeout_nbd': 1, 'is_nova-api': False, 'is_master': False, } default_services = [ 'nova-api', 'nova-scheduler', 'nova-conductor', 'nova-consoleauth', 'nova-novncproxy', 'nova-compute', ] self.packages = [] self.services = [] for service in default_services: for enable_service in enable_services: if re.search(enable_service, service): self.services.append(service) break if 'nova-api' in self.services: self.data['is_nova-api'] = True if 'nova-novncproxy' in self.services: self.packages.append('novnc') if 'nova-compute' in self.services: self.services.extend([ 'libvirtd', 'messagebus', 'nova-compute', ]) self.packages.extend([ 'libvirt', 'sysfsutils', 'qemu-kvm', 'libvirt-python', 'libvirt-devel', 'dbus', ]) def init_before(self): self.package = env['cluster']['os_package_map']['nova'] self.prefix = self.package.get('prefix', '/usr') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'user': '******', 'timeout_nbd': 1, 'sudoers_cmd': '/usr/bin/nova-rootwrap /etc/nova/rootwrap.conf *', 'lock_path': '/var/lock/subsys/nova', 'my_ip': env.node['ip']['default_dev']['ip'], 'vncserver_listen': env.node['ip']['default_dev']['ip'], 'vncserver_proxyclient_address': env.node['ip']['default_dev']['ip'], 'keystone': env.cluster['keystone'], }) if env.host == env.hosts[0] and self.data['is_nova-api']: self.data['is_master'] = True else: self.data['is_master'] = False def setup(self): data = self.init() if self.is_tag('package'): self.install_packages() self.python.setup() self.python.setup_package(**self.package) # for cinder if not filer.exists('/usr/bin/scsi_id'): sudo('ln -s /lib/udev/scsi_id /usr/bin/') if self.is_tag('conf'): # sudoersファイルは最後に改行入れないと、シンタックスエラーとなりsudo実行できなくなる # sudo: >>> /etc/sudoers.d/nova: syntax error near line 2 <<< # この場合は以下のコマンドでvisudoを実行し、編集する # $ pkexec visudo -f /etc/sudoers.d/nova if filer.template( '/etc/sudoers.d/nova', data=data, src='sudoers.j2', ): self.handlers['restart_nova'] = True if filer.template( '/etc/nova/nova.conf', src='{0}/nova.conf.j2'.format(data['version']), data=data, ): self.handlers['restart_nova'] = True if self.is_tag('data') and env.host == env.hosts[0]: if data['is_master']: sudo('nova-manage db sync') if data['version'] in ['mitaka']: sudo('nova-manage api_db sync') if self.is_tag('service'): self.enable_services().start_services(pty=False) self.exec_handlers() if self.is_tag('data') and env.host == env.hosts[0]: if data['is_master']: self.sync_flavors() return 0 def cmd(self, cmd): self.init() return utils.oscmd('nova {0}'.format(cmd)) def check(self): self.nova_api.status() self.nova_cert.status() self.nova_consoleauth.status() self.nova_scheduler.status() self.nova_conductor.status() self.nova_novncproxy.status() def enable_nova_services(self): result = sudo("nova-manage service list 2>/dev/null | grep disabled | awk '{print $1,$2}'") services = result.split('\r\n') services = map(lambda s: s.split(' '), services) for service in services: sudo("nova-manage service enable --service {0} --host {1}".format( service[0], service[1])) def sync_flavors(self): data = self.init() result = self.cmd("flavor-list 2>/dev/null | grep '| ' | grep -v '| ID' | awk '{print $4}'") flavor_list = result.split('\r\n') sub_set = set(flavor_list) - set(data['flavors'].keys()) for flavor_name in sub_set: if len(flavor_name) == 0: continue self.cmd("flavor-delete {0}".format(flavor_name)) for flavor_name, flavor in data['flavors'].items(): if flavor_name not in flavor_list: flavor = map(lambda f: str(f), flavor) options = ' '.join(flavor) self.cmd("flavor-create --is-public true {0} auto {1}".format(flavor_name, options)) def create_flavor(self, name, ram, disk, vcpu): with api.warn_only(): result = self.cmd("flavor-list 2>/dev/null | grep ' {0} '".format(name)) if result.return_code == 0: return else: self.cmd("flavor-create --is-public true {0} auto {1} {2} {3}".format( name, ram, disk, vcpu))
class Ceilometer(SimpleBase): def __init__(self, enable_services=['.*']): self.data_key = 'ceilometer' self.data = { } default_services = [ 'ceilometer-api', 'ceilometer-collector', 'ceilometer-agent-notification', 'ceilometer-agent-compute', 'ceilometer-agent-central', # 'ceilometer-alarm-evaluator', # liberty # 'ceilometer-alarm-notifier', # liberty ] self.services = [] for service in default_services: for enable_service in enable_services: if re.search(enable_service, service): self.services.append(service) break def init_before(self): self.package = env['cluster']['os_package_map']['ceilometer'] self.prefix = self.package.get('prefix', '/opt/ceilometer') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], }) def setup(self): data = self.init() if self.is_tag('package'): self.python.setup() self.python.setup_package(**self.package) if self.is_tag('conf'): is_updated = filer.template( '/etc/ceilometer/ceilometer.conf', src='{0}/ceilometer.conf.j2'.format(data['version']), data=data, ) is_updated = filer.template( '/etc/ceilometer/pipeline.yaml', src='{0}/pipeline.yaml'.format(data['version']), data=data, ) or is_updated if self.is_tag('data') and env.host == env.hosts[0]: sudo('{0}/bin/ceilometer-dbsync'.format(self.prefix)) if self.is_tag('conf', 'service'): self.enable_services().start_services(pty=False) if is_updated: self.restart_services(pty=False) def cmd(self, cmd): return utils.oscmd('ceilometer {0}'.format(cmd))
class Keystone(SimpleBase): def __init__(self, data=None): self.data_key = 'keystone' self.data = { 'user': '******', 'admin_token': 'ADMIN', 'token': { 'provider': 'keystone.token.providers.uuid.Provider', 'driver': 'keystone.token.persistence.backends.sql.Token', }, } self.packages = { 'CentOS Linux 7.*': [ 'httpd', 'mod_wsgi', ] } self.services = ['httpd'] def init_before(self): self.package = env['cluster']['os_package_map']['keystone'] self.prefix = self.package.get('prefix', '/opt/keystone') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'tmp_admin_token': 'admin_token = {0}'.format(self.data['admin_token']), }) if self.data['version'] == 'juno': self.client = 'keystone' else: self.client = 'openstack' def setup(self): data = self.init() version = data['version'] if self.is_tag('package'): self.python.setup() self.python.setup_package(**self.package) self.install_packages() if self.is_tag('conf'): if filer.template( '/etc/keystone/keystone.conf', src='{0}/keystone.conf.j2'.format(version), data=data, ): self.handlers['restart_httpd'] = True data.update({ 'httpd_port': data['public_port'], 'prefix': self.prefix, 'wsgi_name': 'keystone-public', 'wsgi_script_alias': '{0}/bin/keystone-wsgi-public'.format(self.prefix), 'wsgi_script_dir': '{0}/bin/'.format(self.prefix), 'log_name': 'keystone' }) if filer.template( '/etc/httpd/conf.d/wsgi-keystone-public.conf', src='wsgi-httpd.conf', data=data, ): self.handlers['restart_httpd'] = True data.update({ 'httpd_port': data['admin_port'], 'wsgi_name': 'keystone-admin', 'wsgi_script_alias': '{0}/bin/keystone-wsgi-admin'.format(self.prefix), }) if filer.template( '/etc/httpd/conf.d/wsgi-keystone-admin.conf', src='wsgi-httpd.conf', data=data, ): self.handlers['restart_httpd'] = True if self.is_tag('data'): if env.host == env.hosts[0]: sudo('{0}/bin/keystone-manage db_sync'.format(self.prefix)) if self.is_tag('service'): self.enable_services().start_services(pty=False) self.exec_handlers() if self.is_tag('data') and env.host == env.hosts[0]: time.sleep(3) self.create_tenant('admin', 'Admin Project') self.create_role('admin') self.create_role('_member_') self.create_user(data['admin_user'], data['admin_password'], [['admin', 'admin'], ['admin', '_member_']]) self.create_tenant(data['service_tenant_name'], 'Service Project') self.create_user(data['service_user'], data['service_password'], [['service', 'admin']]) for name, service in data['services'].items(): self.create_service(name, service) if self.is_tag('conf'): self.disable_admin_token() def disable_admin_token(self): data = self.init() data.update({ 'tmp_admin_token': '# admin_token =' }) filer.template( '/etc/keystone/keystone.conf', src='{0}/keystone.conf.j2'.format(data['version']), data=data, ) self.restart_services(pty=False) def cmd(self, cmd, use_admin_token=True): self.init() # create users, roles, services if use_admin_token: endpoint = '{0}/v2.0'.format(self.data['admin_endpoint']) with api.shell_env( OS_SERVICE_TOKEN=self.data['admin_token'], OS_SERVICE_ENDPOINT=endpoint, OS_TOKEN=self.data['admin_token'], OS_URL=endpoint, ): return run('openstack {0}'.format(cmd)) else: return utils.oscmd('openstack {0}'.format(cmd)) def create_tenant(self, name, description): self.init() tenant_list = self.cmd('project list', True) if ' {0} '.format(name) not in tenant_list: self.cmd('project create --description="{1}" {0}'.format( name, description)) def create_role(self, name): self.init() role_list = self.cmd('role list', True) if ' {0} '.format(name) not in role_list: self.cmd('role create {0}'.format(name)) def create_user(self, name, password, tenant_roles, use_admin_token=True): self.init() user_list = self.cmd('user list', use_admin_token) if ' {0} '.format(name) not in user_list: self.cmd('user create --password={1} {0}'.format(name, password), use_admin_token) for tenant_role in tenant_roles: self.cmd('role add --user={0} --project={1} {2}'.format( name, tenant_role[0], tenant_role[1]), use_admin_token) def create_service(self, name, service): self.init() service_list = self.cmd('service list') endpoint_list = self.cmd('endpoint list') if ' {0} '.format(name) not in service_list: self.cmd('service create --name={0} --description="{1[description]}" {1[type]}'.format(name, service)) # noqa if ' {0} '.format(name) not in endpoint_list: self.cmd('''endpoint create \\ --publicurl={0[publicurl]} \\ --internalurl={0[internalurl]} \\ --adminurl={0[adminurl]} \\ --region {0[region]} \\ {0[type]}'''.format(service))
class Bootstrap(SimpleBase): def __init__(self): # 'https://repos.fedorapeople.org/repos/openstack/openstack-mitaka/rdo-release-mitaka-5.noarch.rpm' # 'https://repos.fedorapeople.org/repos/openstack/openstack-liberty/rdo-release-liberty-3.noarch.rpm' self.packages = { 'CentOS Linux 7.*': [ { 'name': 'rdo-release-mitaka-5.noarch', 'path': 'https://repos.fedorapeople.org/repos/openstack/openstack-mitaka/rdo-release-mitaka-5.noarch.rpm', # noqa }, 'epel-release', 'mysql-devel', 'vim', ] } def init_before(self): self.package = env['cluster']['os_package_map']['os-tools'] self.prefix = self.package.get('prefix', '/opt/os-tools') self.python = Python(self.prefix) def setup(self): self.init() sudo('setenforce 0') Editor('/etc/selinux/config').s('SELINUX=enforcing', 'SELINUX=disable') Service('firewalld').stop().disable() if self.is_tag('package'): self.install_packages() self.python.setup() self.python.setup_package(**self.package) if self.is_tag('conf'): self.dump_openstackrc def dump_openstackrc(self): keystone_data = env.cluster['keystone'] sudo('''cat << _EOT_ > /root/openstackrc export OS_USERNAME=admin export OS_PASSWORD={0} export OS_TENANT_NAME=admin export OS_AUTH_URL={1}'''.format( keystone_data['admin_password'], keystone_data['services']['keystone']['adminurl'])) sudo('''cat << _EOT_ > /root/openstackrcv3 export OS_USERNAME=admin export OS_PASSWORD={0} export OS_TENANT_NAME=admin export OS_AUTH_URL={1}/v3 export OS_REGION_NAME={2} export OS_VOLUME_API_VERSION=2 export OS_IDENTITY_API_VERSION=3 export OS_USER_DOMAIN_NAME=${{OS_USER_DOMAIN_NAME:-"Default"}} export OS_PROJECT_DOMAIN_NAME=${{OS_PROJECT_DOMAIN_NAME:-"Default"}}'''.format( keystone_data['admin_password'], keystone_data['endpoint'], keystone_data['service_region']))
class Neutron(SimpleBase): def __init__(self, enable_services=['.*']): self.data_key = 'neutron' self.data = { 'sudoers_cmd': 'ALL', 'debug': True, 'verbose': True, 'user': '******', 'auth_strategy': 'keystone', 'core_plugin': 'ml2', 'is_neutron-server': False, 'is_master': False, } self.packages = ['openvswitch', 'haproxy', 'ebtables'] default_services = [ 'neutron-server', 'neutron-linuxbridge-agent', 'neutron-openvswitch-agent', 'neutron-dhcp-agent', 'neutron-l3-agent', 'neutron-metadata-agent', 'neutron-lbaasv2-agent', ] self.services = [] for service in default_services: for enable_service in enable_services: if re.search(enable_service, service): self.services.append(service) break if 'neutron-server' in self.services: self.data['is_neutron-server'] = True def init_before(self): self.package = env['cluster']['os_package_map']['neutron'] self.prefix = self.package.get('prefix', '/opt/neutron') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], 'my_ip': env.node['ip']['default_dev']['ip'], }) if env.host == env.hosts[0] and self.data['is_neutron-server']: self.data['is_master'] = True else: self.data['is_master'] = False def setup(self): data = self.init() if self.is_tag('package'): self.python.setup() self.install_packages() self.python.setup_package(**self.package) sudo('modprobe tun') # for vhost_net self.setup_network_bridge() if self.is_tag('conf'): filer.template( '/etc/sudoers.d/neutron', data=data, src='sudoers.j2', ) if filer.template( '/etc/neutron/neutron.conf', src='{0}/neutron.conf.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True if filer.template( '/etc/neutron/plugins/ml2/ml2_conf.ini', src='{0}/ml2_conf.ini.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True if self.data['version'] == 'kilo': linuxbridge_conf = '/etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini' elif self.data['version'] in ['liberty', 'mitaka', 'master']: linuxbridge_conf = '/etc/neutron/plugins/ml2/linuxbridge_agent.ini' if filer.template( linuxbridge_conf, src='{0}/linuxbridge_conf.ini.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True if self.data['version'] == 'kilo': ovs_conf = '/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini' elif self.data['version'] in ['liberty', 'mitaka', 'master']: ovs_conf = '/etc/neutron/plugins/ml2/openvswitch_agent.ini' if 'openvswitch' in self.data['ml2']['mechanism_drivers']: if filer.template( ovs_conf, src='{0}/ovs_neutron_plugin.ini.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True if filer.template( '/etc/neutron/l3_agent.ini', src='{0}/l3_agent.ini.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True else: sudo('echo '' > {0}'.format(ovs_conf)) if filer.template( '/etc/neutron/dhcp_agent.ini', src='{0}/dhcp_agent.ini.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True if filer.template( '/etc/neutron/metadata_agent.ini', src='{0}/metadata_agent.ini.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True # lbaas if filer.template( '/etc/neutron/services_lbaas.conf', src='{0}/services_lbaas.conf.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True if filer.template( '/etc/neutron/neutron_lbaas.conf', src='{0}/neutron_lbaas.conf.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True if filer.template( '/etc/neutron/lbaas_agent.ini', src='{0}/lbaas_agent.ini.j2'.format(data['version']), data=data, ): self.handlers['restart_neutron-*'] = True if self.is_tag('data') and env.host == env.hosts[0]: if data['is_master']: option = '--config-file /etc/neutron/neutron.conf' run('{0}/bin/neutron-db-manage {1} upgrade head'.format(self.prefix, option)) run('{0}/bin/neutron-db-manage {1} --service lbaas upgrade head'.format( self.prefix, option)) if self.is_tag('service'): self.enable_services().start_services(pty=False) self.exec_handlers() if self.is_tag('data') and env.host == env.hosts[0]: if data['is_master']: time.sleep(5) self.create_nets() self.create_routers() return 0 def cmd(self, cmd): return utils.oscmd('neutron {0}'.format(cmd)) def create_nets(self): data = self.init() result = self.cmd("net-list 2>/dev/null | grep '| ' | grep -v '| id' | awk '{print $4}'") net_list = result.split('\r\n') result = self.cmd("subnet-list 2>/dev/null | grep '| ' | grep -v '| id' | awk '{print $4}'") subnet_list = result.split('\r\n') for network in data.get('networks'): if network['name'] not in net_list: tmp_options = map(lambda opt: '--' + opt, network.get('options', [])) options = ' '.join(tmp_options) self.cmd('net-create {0} {1}'.format(options, network['name'])) for subnet in network['subnets']: if subnet['name'] not in subnet_list: tmp_options = map(lambda opt: '--' + opt, subnet.get('options', [])) options = ' '.join(tmp_options) self.cmd('subnet-create {0} {1} --name {2} {3}'.format( network['name'], subnet['cidr'], subnet['name'], options)) def create_routers(self): data = self.init() with api.warn_only(): for router in data.get('routers', []): result = self.cmd('router-show {0}'.format(router['name'])) if result.return_code == 0: continue self.cmd('router-create {0}'.format(router['name'])) self.cmd('router-gateway-set {0} {1}'.format(router['name'], router['gateway'])) for interface in router['interfaces']: self.cmd('router-interface-add {0} {1}'.format(router['name'], interface)) def setup_network_bridge(self): data = self.init() if 'linuxbridge' in data['ml2']['mechanism_drivers']: sudo('modprobe bridge') elif 'openvswitch' in data['ml2']['mechanism_drivers']: sudo('modprobe -r bridge') Service('openvswitch').start().enable() sudo('ovs-vsctl br-exists {0} || ovs-vsctl add-br {0}'.format( data['ovs']['integration_bridge'])) filer.template( '/etc/sysconfig/network-scripts/ifcfg-{0}'.format( data['ovs']['integration_bridge']), src='network/ovs-ifcfg-br.j2', data=data) for mapping in data['ovs']['bridge_mappings']: pair = mapping.split(':') ovs_interface = pair[1] sudo('ovs-vsctl br-exists {0} || ovs-vsctl add-br {0}'.format(ovs_interface)) for mapping in data['ovs']['physical_interface_mappings']: pair = mapping.split(':') ovs_interface = pair[0] physical_interface = pair[1] backup_default_dev_file = '/etc/sysconfig/network-scripts/bk-ifcfg-defualt' if filer.exists(backup_default_dev_file): default = run('cat {0}'.format(backup_default_dev_file)) dev, ip, subnet, gateway = default.split(':') data['default_dev'] = { 'dev': dev, 'ip': ip, 'subnet': subnet, 'gateway': gateway, } else: sudo("echo '{0[dev]}:{0[ip]}:{0[subnet]}:{1}' > {2}".format( env.node['ip']['default_dev'], env.node['ip']['default']['ip'], backup_default_dev_file)) data['default_dev'] = env.node['ip']['default_dev'] data['default_dev']['gateway'] = env.node['ip']['default']['ip'] data['default_dev']['netmask'] = self.cidr( data['default_dev']['subnet'].split('/')[1]) if physical_interface == data['default_dev']['dev']: # create backup for default interface data['ovs_interface'] = ovs_interface filer.template( '/etc/sysconfig/network-scripts/ifcfg-{0}'.format(physical_interface), src='network/ovs-ifcfg-flat.j2', data=data) filer.template( '/etc/sysconfig/network-scripts/ifcfg-{0}'.format(ovs_interface), src='network/ovs-ifcfg-br-flat.j2', data=data) result = sudo('ovs-vsctl list-ports {0}'.format(ovs_interface)) if result.find(data['default_dev']['dev']) == -1: with api.warn_only(): api.reboot(180) def cidr(self, prefix): prefix = int(prefix) return socket.inet_ntoa(struct.pack(">I", (0xffffffff << (32 - prefix)) & 0xffffffff))
class Trove(SimpleBase): def __init__(self): self.data_key = 'trove' self.data = { } self.services = [ 'trove-api', 'trove-taskmanager', 'trove-conductor', ] def init_before(self): self.package = env['cluster']['os_package_map']['trove'] self.prefix = self.package.get('prefix', '/opt/trove') self.python = Python(self.prefix) def init_after(self): self.data.update({ 'keystone': env.cluster['keystone'], 'neutron': env.cluster['neutron'], 'my_ip': env.node['ip']['default_dev']['ip'], }) def setup(self): data = self.init() if self.is_tag('package'): self.python.setup() self.python.setup_package(**self.package) if self.is_tag('conf'): # setup conf files if filer.template( '/etc/trove/trove.conf', src='{0}/trove.conf.j2'.format(data['version']), data=data): self.handlers['restart_trove-*'] = True if filer.template( '/etc/trove/trove-taskmanager.conf', src='{0}/trove-taskmanager.conf.j2'.format(data['version']), data=data): self.handlers['restart_trove-*'] = True if filer.template( '/etc/trove/trove-guestagent.conf', src='{0}/trove-guestagent.conf.j2'.format(data['version']), data=data): self.handlers['restart_trove-*'] = True if self.is_tag('data') and env.host == env.hosts[0]: sudo('{0}/bin/trove-manage db_sync'.format(self.prefix)) self.register_image() if self.is_tag('conf', 'service'): self.enable_services().start_services(pty=False) self.exec_handlers() def cmd(self, cmd): self.init() return utils.oscmd('trove {0}'.format(cmd)) def register_image(self): """ trove images for ubuntu http://tarballs.openstack.org/trove/images/ubuntu/ building guest images http://docs.openstack.org/developer/trove/dev/building_guest_images.html ``` git clone https://github.com/openstack/trove-integration git clone https://github.com/openstack/tripleo-image-elements.git export PATH_TRIPLEO_ELEMENTS=$PWD/tripleo-image-elements export REDSTACK_SCRIPTS=$PWD/trove-integration/scripts export DIB_CLOUD_INIT_DATASOURCES="ConfigDrive" export ELEMENTS_PATH=$REDSTACK_SCRIPTS/files/elements:$PATH_TRIPLEO_ELEMENTS/elements disk-image-create -a amd64 -o ./ubuntu-percona.qemu ubuntu vm heat-cfntools \ cloud-init-datasources ubuntu-guest ubuntu-mysql ``` """ glance = Glance() image_id = glance.create_image( 'trove_mysql', 'http://tarballs.openstack.org/trove/images/ubuntu/mysql.qcow2') sudo("/opt/trove/bin/trove-manage --config-file /etc/trove/trove.conf datastore_update mysql ''") # noqa sudo("/opt/trove/bin/trove-manage --config-file /etc/trove/trove.conf datastore_version_update mysql mysql-5.6 mysql {0} '' 1".format(image_id)) # noqa