#!/usr/bin/env python # # jose.lausuch@ericsson.com # valentin.boucher@orange.com # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 # import os import os.path import subprocess import sys import time from cinderclient import client as cinderclient import functest.utils.functest_logger as ft_logger import functest.utils.functest_utils as ft_utils from glanceclient import client as glanceclient from keystoneclient.v2_0 import client as keystoneclient from neutronclient.v2_0 import client as neutronclient from novaclient import client as novaclient logger = ft_logger.Logger("openstack_utils").getLogger() # ********************************************* # CREDENTIALS # ********************************************* def check_credentials(): """ Check if the OpenStack credentials (openrc) are sourced """ env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD', 'OS_TENANT_NAME'] return all(map(lambda v: v in os.environ and os.environ[v], env_vars)) def get_credentials(service): """Returns a creds dictionary filled with the following keys: * username * password/api_key (depending on the service) * tenant_name/project_id (depending on the service) * auth_url :param service: a string indicating the name of the service requesting the credentials. """ creds = {} # Check that the env vars exists: envvars = ('OS_USERNAME', 'OS_PASSWORD', 'OS_AUTH_URL', 'OS_TENANT_NAME') for envvar in envvars: if os.getenv(envvar) is None: logger.error("'%s' is not exported as an env variable." % envvar) exit(-1) # Unfortunately, each of the OpenStack client will request slightly # different entries in their credentials dict. if service.lower() in ("nova", "cinder"): password = "api_key" tenant = "project_id" else: password = "password" tenant = "tenant_name" # The most common way to pass these info to the script is to do it through # environment variables. creds.update({ "username": os.environ.get("OS_USERNAME"), password: os.environ.get("OS_PASSWORD"), "auth_url": os.environ.get("OS_AUTH_URL"), tenant: os.environ.get("OS_TENANT_NAME") }) if os.getenv('OS_ENDPOINT_TYPE') is not None: creds.update({ "endpoint_type": os.environ.get("OS_ENDPOINT_TYPE") }) if os.getenv('OS_REGION_NAME') is not None: creds.update({ "region_name": os.environ.get("OS_REGION_NAME") }) cacert = os.environ.get("OS_CACERT") if cacert is not None: # each openstack client uses differnt kwargs for this creds.update({"cacert": cacert, "ca_cert": cacert, "https_ca_cert": cacert, "https_cacert": cacert, "ca_file": cacert}) creds.update({"insecure": "True", "https_insecure": "True"}) if not os.path.isfile(cacert): logger.info("WARNING: The 'OS_CACERT' environment variable is " "set to %s but the file does not exist." % cacert) return creds def source_credentials(rc_file): pipe = subprocess.Popen(". %s; env" % rc_file, stdout=subprocess.PIPE, shell=True) output = pipe.communicate()[0] env = dict((line.split("=", 1) for line in output.splitlines())) os.environ.update(env) return env def get_credentials_for_rally(): creds = get_credentials("keystone") admin_keys = ['username', 'tenant_name', 'password'] endpoint_types = [('internalURL', 'internal'), ('publicURL', 'public'), ('adminURL', 'admin')] if 'endpoint_type' in creds.keys(): for k, v in endpoint_types: if creds['endpoint_type'] == k: creds['endpoint_type'] = v rally_conf = {"type": "ExistingCloud", "admin": {}} for key in creds: if key in admin_keys: rally_conf['admin'][key] = creds[key] else: rally_conf[key] = creds[key] return rally_conf # ********************************************* # CLIENTS # ********************************************* def get_keystone_client(): creds_keystone = get_credentials("keystone") return keystoneclient.Client(**creds_keystone) def get_nova_client(): creds_nova = get_credentials("nova") return novaclient.Client('2', **creds_nova) def get_cinder_client(): creds_cinder = get_credentials("cinder") creds_cinder.update({ "service_type": "volume" }) return cinderclient.Client('2', **creds_cinder) def get_neutron_client(): creds_neutron = get_credentials("neutron") return neutronclient.Client(**creds_neutron) def get_glance_client(): keystone_client = get_keystone_client() glance_endpoint_type = 'publicURL' os_endpoint_type = os.getenv('OS_ENDPOINT_TYPE') if os_endpoint_type is not None: glance_endpoint_type = os_endpoint_type glance_endpoint = keystone_client.service_catalog.url_for( service_type='image', endpoint_type=glance_endpoint_type) return glanceclient.Client(1, glance_endpoint, token=keystone_client.auth_token) # ********************************************* # NOVA # ********************************************* def get_instances(nova_client): try: instances = nova_client.servers.list(search_opts={'all_tenants': 1}) return instances except Exception, e: logger.error("Error [get_instances(nova_client)]: %s" % e) return None def get_instance_status(nova_client, instance): try: instance = nova_client.servers.get(instance.id) return instance.status except Exception, e: logger.error("Error [get_instance_status(nova_client)]: %s" % e) return None def get_instance_by_name(nova_client, instance_name): try: instance = nova_client.servers.find(name=instance_name) return instance except Exception, e: logger.error("Error [get_instance_by_name(nova_client, '%s')]: %s" % (instance_name, e)) return None def get_flavor_id(nova_client, flavor_name): flavors = nova_client.flavors.list(detailed=True) id = '' for f in flavors: if f.name == flavor_name: id = f.id break return id def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram): flavors = nova_client.flavors.list(detailed=True) id = '' for f in flavors: if min_ram <= f.ram and f.ram <= max_ram: id = f.id break return id def create_flavor(nova_client, flavor_name, ram, disk, vcpus, public=True): try: flavor = nova_client.flavors.create( flavor_name, ram, vcpus, disk, is_public=public) try: extra_specs = ft_utils.get_functest_config( 'general.flavor_extra_specs') flavor.set_keys(extra_specs) except ValueError: # flavor extra specs are not configured, therefore skip the update pass except Exception, e: logger.error("Error [create_flavor(nova_client, '%s', '%s', '%s', " "'%s')]: %s" % (flavor_name, ram, disk, vcpus, e)) return None return flavor.id def get_or_create_flavor(flavor_name, ram, disk, vcpus, public=True): flavor_exists = False nova_clie
# Copyright 2016 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# == Class: tripleo::profile::base::nova
#
# Nova base profile for tripleo
#
# === Parameters
#
# [*bootstrap_node*]
# (Optional) The hostname of the node responsible for bootstrapping tasks
# Defaults to hiera('bootstrap_nodeid')
#
# [*libvirt_enabled*]
# (Optional) Whether or not Libvirt is enabled.
# Defaults to false
#
# [*manage_migration*]
# (Optional) Whether or not manage Nova Live migration
# Defaults to false
#
# [*messaging_driver*]
# Driver for messaging service.
# Defaults to hiera('messaging_service_name', 'rabbit')
#
# [*messaging_hosts*]
# list of the messaging host fqdns
# Defaults to hiera('rabbitmq_node_names')
#
# [*messaging_password*]
# Password for messaging nova queue
# Defaults to hiera('nova::rabbit_password')
#
# [*messaging_port*]
# IP port for messaging service
# Defaults to hiera('nova::rabbit_port', 5672)
#
# [*messaging_username*]
# Username for messaging nova queue
# Defaults to hiera('nova::rabbit_userid', 'guest')
#
# [*messaging_use_ssl*]
# Flag indicating ssl usage.
# Defaults to hiera('nova::rabbit_use_ssl', '0')
#
# [*nova_compute_enabled*]
# (Optional) Whether or not nova-compute is enabled.
# Defaults to false
#
# [*step*]
# (Optional) The current step of the deployment
# Defaults to hiera('step')
#
class tripleo::profile::base::nova (
$bootstrap_node = hiera('bootstrap_nodeid', undef),
$libvirt_enabled = false,
$manage_migration = false,
$messaging_driver = hiera('messaging_service_name', 'rabbit'),
$messaging_hosts = any2array(hiera('rabbitmq_node_names', undef)),
$messaging_password = hiera('nova::rabbit_password'),
$messaging_port = hiera('nova::rabbit_port', '5672'),
$messaging_username = hiera('nova::rabbit_userid', 'guest'),
$messaging_use_ssl = hiera('nova::rabbit_use_ssl', '0'),
$nova_compute_enabled = false,
$step = hiera('step'),
) {
if $::hostname == downcase($bootstrap_node) {
$sync_db = true
} else {
$sync_db = false
}
if hiera('nova::use_ipv6', false) {
$memcache_servers = suffix(hiera('memcached_node_ips_v6'), ':11211')
} else {
$memcache_servers = suffix(hiera('memcached_node_ips'), ':11211')
}
if $step >= 4 or ($step >= 3 and $sync_db) {
$messaging_use_ssl_real = sprintf('%s', bool2num(str2bool($messaging_use_ssl)))
# TODO(ccamacho): remove sprintf once we properly type the port, needs
# to be a string for the os_transport_url function.
class { '::nova' :
default_transport_url => os_transport_url({
'transport' => $messaging_driver,
'hosts' => $messaging_hosts,
'port' => sprintf('%s', $messaging_port),
'username' => $messaging_username,
'password' => $messaging_password,
'ssl' => $messaging_use_ssl_real,
}),
}
include ::nova::config
class { '::nova::cache':
enabled => true,
backend => 'oslo_cache.memcache_pool',
memcache_servers => $memcache_servers,
}
}
if $step >= 4 {
include ::nova::placement
if $manage_migration {
class { '::nova::migration::libvirt':
configure_libvirt => $libvirt_enabled,
configure_nova => $nova_compute_enabled,
}
}
}
}