Wireframe for Heat usage

This commit is contained in:
Ilya Shakhat 2015-01-30 19:57:37 +03:00
parent 25b666782c
commit 4a9c87b0cf
11 changed files with 304 additions and 15 deletions

17
bin/functions.sh Executable file

@ -0,0 +1,17 @@
#!/bin/bash
error() {
printf "\e[31mError: %s\e[0m\n" "${*}" >&2
exit 1
}
message() {
printf "\e[33m%s\e[0m\n" "${1}"
}
remote_shell() {
host=$1
key=$2
command=$3
ssh -i ${key} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu@${host} "$command"
}

36
bin/install.sh → bin/prepare.sh Normal file → Executable file

@ -10,9 +10,12 @@ setup_image() {
message "Installing Shaker image, will take some time"
message "Downloading Ubuntu cloud image"
IMG_FILE="ubuntu-cloud.img"
wget -O ${IMG_FILE} ${UBUNTU_CLOUD_IMAGE_URL}
glance image-create --name ${IMG_FILE} --disk-format qcow2 --container-format bare --is-public True --file ${IMG_FILE}
IMG_FILE="shaker-template-image"
glance image-create --name ${IMG_FILE} --disk-format qcow2 --container-format bare --is-public True --copy-from ${UBUNTU_CLOUD_IMAGE_URL}
until [ -n "$(glance image-show ${IMG_FILE} | grep status | grep active)" ]; do
sleep 5
done
message "Creating security group"
SEC_GROUP="shaker-access"
@ -25,9 +28,10 @@ setup_image() {
nova flavor-create --is-public true m1.mini 6 1024 10 1
message "Creating key pair"
KEY="shaker-key"
nova keypair-add ${KEY} > ${KEY}.pem
chmod og-rw ${KEY}.pem
KEY_NAME="shaker-key"
KEY="`mktemp`"
nova keypair-add ${KEY_NAME} > ${KEY_NAME}
chmod og-rw ${KEY}
message "Booting VM"
NETWORK_ID=`neutron net-show net04 -f value -c id`
@ -36,17 +40,27 @@ setup_image() {
message "Associating a floating IP with VM"
FLOATING_IP=`neutron floatingip-create -f value -c floating_ip_address net04_ext | tail -1`
FLOATING_IP="172.18.161.251"
nova floating-ip-associate ${VM} ${FLOATING_IP}
message "Waiting for VM to boot up"
until remote_shell ${FLOATING_IP} ${KEY} "echo"; do
sleep 5
done
message "Installing packages into VM"
ssh -i ${KEY}.pem ubuntu@${FLOATING_IP} "sudo apt-add-repository \"deb http://nova.clouds.archive.ubuntu.com/ubuntu/ trusty multiverse\""
ssh -i ${KEY}.pem ubuntu@${FLOATING_IP} "sudo apt-get update"
ssh -i ${KEY}.pem ubuntu@${FLOATING_IP} "sudo apt-get -y install iperf netperf python-pip"
ssh -i ${KEY}.pem ubuntu@${FLOATING_IP} "sudo pip install netperf-wrapper"
remote_shell ${FLOATING_IP} ${KEY} "sudo apt-add-repository \"deb http://nova.clouds.archive.ubuntu.com/ubuntu/ trusty multiverse\""
remote_shell ${FLOATING_IP} ${KEY} "sudo apt-get update"
remote_shell ${FLOATING_IP} ${KEY} "sudo apt-get -y install iperf netperf python-pip python-dev"
remote_shell ${FLOATING_IP} ${KEY} "sudo pip install netperf-wrapper numpy"
message "Making VM snapshot"
nova image-create --poll ${VM} ${IMAGE_NAME}
message "Destroy VM"
nova delete ${VM}
FP_ID=`neutron floatingip-list -f csv -c id -c floating_ip_address --quote none | grep ${FLOATING_IP} | awk -F "," '{print $1}'`
neutron floatingip-delete ${FP_ID}
}
main() {

@ -8,4 +8,6 @@ oslo.config>=1.4.0 # Apache-2.0
oslo.i18n>=1.0.0 # Apache-2.0
oslo.serialization>=1.0.0 # Apache-2.0
oslo.utils>=1.1.0 # Apache-2.0
python-keystoneclient
python-heatclient
PyYAML>=3.1.0

@ -0,0 +1,5 @@
deploy:
scenarios/deploy_two_vms.sh
tests:
- netperf: tcp_bidirectional
- dummy-type: nope

@ -24,4 +24,4 @@ packages =
[entry_points]
console_scripts =
shaker = shaker.server:main
shaker = shaker.engine.main:main

@ -14,10 +14,21 @@
# limitations under the License.
from oslo.config import cfg
from shaker.engine import utils
OPTS = [
cfg.StrOpt('scenario',
required=True,
help='Scenario to run'),
cfg.StrOpt('os-auth-url', metavar='<auth-url>',
default=utils.env('OS_AUTH_URL'),
help='Authentication URL, defaults to env[OS_AUTH_URL].'),
cfg.StrOpt('os-tenant-name', metavar='<auth-tenant-name>',
default=utils.env('OS_TENANT_NAME'),
help='Authentication tenant name, defaults to '
'env[OS_TENANT_NAME].'),
cfg.StrOpt('os-username', metavar='<auth-username>',
default=utils.env('OS_USERNAME'),
help='Authentication username, defaults to env[OS_USERNAME].'),
cfg.StrOpt('os-password', metavar='<auth-password>',
default=utils.env('OS_PASSWORD'),
help='Authentication password, defaults to env[OS_PASSWORD].'),
]

40
shaker/engine/heat.py Normal file

@ -0,0 +1,40 @@
# Copyright (c) 2015 Mirantis 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.
from heatclient import client as heat_client_pkg
import time
HEAT_CLIENT_VERSION = '1'
def create_heat_client(keystone_client):
orchestration_api_url = keystone_client.service_catalog.url_for(
service_type='orchestration')
client = heat_client_pkg.Client(HEAT_CLIENT_VERSION,
endpoint=orchestration_api_url,
token=keystone_client.auth_token, )
return client
def wait_stack_completion(stack):
# NOTE: expected empty status because status of stack
# maybe is not set in heat database
while stack.status in ['IN_PROGRESS', '']:
time.sleep(1)
stack.get()
if stack.status != 'COMPLETE':
raise Exception(stack.stack_status)

30
shaker/engine/keystone.py Normal file

@ -0,0 +1,30 @@
# Copyright (c) 2015 Mirantis 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.
from keystoneclient import discover as keystone_discover
from keystoneclient.v2_0 import client as keystone_v2
from keystoneclient.v3 import client as keystone_v3
def create_keystone_client(args):
discover = keystone_discover.Discover(**args)
for version_data in discover.version_data():
version = version_data["version"]
if version[0] <= 2:
return keystone_v2.Client(**args)
elif version[0] == 3:
return keystone_v3.Client(**args)
raise Exception(
'Failed to discover keystone version for url %(auth_url)s.', **args)

@ -16,12 +16,27 @@
from oslo.config import cfg
from shaker.engine import config
from shaker.engine import heat
from shaker.engine import keystone
from shaker.openstack.common import log as logging
LOG = logging.getLogger(__name__)
def run():
keystone_kwargs = {'username': cfg.CONF.os_username,
'password': cfg.CONF.os_password,
'tenant_name': cfg.CONF.os_tenant_name,
'auth_url': cfg.CONF.os_auth_url,
}
keystone_client = keystone.create_keystone_client(keystone_kwargs)
heat_client = heat.create_heat_client(keystone_client)
for stack in heat_client.stacks.list():
LOG.info('Stacks: %s', stack)
def main():
# init conf and logging
conf = cfg.CONF
@ -32,6 +47,8 @@ def main():
logging.setup('shaker')
LOG.info('Logging enabled')
run()
if __name__ == '__main__':
main()

28
shaker/engine/utils.py Normal file

@ -0,0 +1,28 @@
# Copyright (c) 2015 Mirantis 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.
import os
def env(*_vars, **kwargs):
"""Returns the first environment variable set.
If none are non-empty, defaults to '' or keyword arg default.
"""
for v in _vars:
value = os.environ.get(v)
if value:
return value
return kwargs.get('default', '')

@ -0,0 +1,125 @@
heat_template_version: 2013-05-23
description: >
HOT template to create a new neutron network plus a router to the public
network, and for deploying two servers into the new network. The template also
assigns floating IP addresses to each server so they are routable from the
public network.
parameters:
key_name:
type: string
description: Name of keypair to assign to servers
image:
type: string
description: Name of image to use for servers
flavor:
type: string
description: Flavor to use for servers
public_net:
type: string
description: >
ID or name of public network for which floating IP addresses will be allocated
private_net_name:
type: string
description: Name of private network to be created
private_net_cidr:
type: string
description: Private network address (CIDR notation)
private_net_gateway:
type: string
description: Private network gateway address
private_net_pool_start:
type: string
description: Start of private network IP address allocation pool
private_net_pool_end:
type: string
description: End of private network IP address allocation pool
resources:
private_net:
type: OS::Neutron::Net
properties:
name: { get_param: private_net_name }
private_subnet:
type: OS::Neutron::Subnet
properties:
network_id: { get_resource: private_net }
cidr: { get_param: private_net_cidr }
gateway_ip: { get_param: private_net_gateway }
allocation_pools:
- start: { get_param: private_net_pool_start }
end: { get_param: private_net_pool_end }
router:
type: OS::Neutron::Router
properties:
external_gateway_info:
network: { get_param: public_net }
router_interface:
type: OS::Neutron::RouterInterface
properties:
router_id: { get_resource: router }
subnet_id: { get_resource: private_subnet }
server1:
type: OS::Nova::Server
properties:
name: Server1
image: { get_param: image }
flavor: { get_param: flavor }
key_name: { get_param: key_name }
networks:
- port: { get_resource: server1_port }
server1_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: private_net }
fixed_ips:
- subnet_id: { get_resource: private_subnet }
server1_floating_ip:
type: OS::Neutron::FloatingIP
properties:
floating_network: { get_param: public_net }
port_id: { get_resource: server1_port }
server2:
type: OS::Nova::Server
properties:
name: Server2
image: { get_param: image }
flavor: { get_param: flavor }
key_name: { get_param: key_name }
networks:
- port: { get_resource: server2_port }
server2_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: private_net }
fixed_ips:
- subnet_id: { get_resource: private_subnet }
server2_floating_ip:
type: OS::Neutron::FloatingIP
properties:
floating_network: { get_param: public_net }
port_id: { get_resource: server2_port }
outputs:
server1_private_ip:
description: IP address of server1 in private network
value: { get_attr: [ server1, first_address ] }
server1_public_ip:
description: Floating IP address of server1 in public network
value: { get_attr: [ server1_floating_ip, floating_ip_address ] }
server2_private_ip:
description: IP address of server2 in private network
value: { get_attr: [ server2, first_address ] }
server2_public_ip:
description: Floating IP address of server2 in public network
value: { get_attr: [ server2_floating_ip, floating_ip_address ] }