Retire old launch-node.py

It has served us well, but it's time for the new world order to take
over.

Change-Id: I72a9f1b1c0f1bd331b5f862f5f69966950ffe963
This commit is contained in:
Monty Taylor 2016-03-09 11:04:02 -06:00
parent e14471dcc6
commit f94594a98e
5 changed files with 129 additions and 532 deletions

View File

@ -14,42 +14,31 @@ to a group.)
To launch a node in the OpenStack CI account (production servers):: To launch a node in the OpenStack CI account (production servers)::
. ~root/ci-launch/openstackci-rs-nova.sh export OS_CLOUD=openstackci-rax
export OS_REGION=DFW
export FLAVOR="8 GB Performance" export FLAVOR="8 GB Performance"
export FQDN=servername.openstack.org export FQDN=servername.openstack.org
sudo puppet cert generate $FQDN
cd /opt/system-config/production/launch/ cd /opt/system-config/production/launch/
./launch-node.py $FQDN --flavor "$FLAVOR" ./launch-node.py $FQDN --flavor "$FLAVOR" \
--cloud=$OS_CLOUD --region=$OS_REGION
To launch a node in the OpenStack Jenkins account (slave nodes):: To launch a node in the OpenStack Jenkins account (slave nodes)::
. ~root/ci-launch/openstackjenkins-rs-nova.sh export OS_CLOUD=openstackjenkins-rax
export OS_REGION=DFW
export FQDN=slavename.slave.openstack.org export FQDN=slavename.slave.openstack.org
nova image-list openstack image list
export IMAGE='Ubuntu 12.04 LTS (Precise Pangolin) (PVHVM)' export IMAGE='Ubuntu 12.04 LTS (Precise Pangolin) (PVHVM)'
nova flavor-list openstack flavor list
export FLAVOR="8 GB Performance" export FLAVOR="8 GB Performance"
sudo puppet cert generate $FQDN ./launch-node.py $FQDN --image "$IMAGE" --flavor "$FLAVOR" \
./launch-node.py $FQDN --image "$IMAGE" --flavor "$FLAVOR" --cloud=$OS_CLOUD --region=$OS_REGION
If you are launching a replacement server, you may skip the generate
step and specify the name of an existing puppet cert (as long as the
private key is on this host).
The server name and cert names may be different and the latter can be
specified with --cert if needed, but launch-node.py will assume they
are the same unless specified.
Manually add the hostname to DNS (the launch script does not do so Manually add the hostname to DNS (the launch script does not do so
automatically). Note that this example assumes you've already automatically). Note that this example assumes you've already
exported a relevant FQDN and sourced the appropriate API credentials exported a relevant FQDN and sourced the appropriate API credentials
above. above.
When running outside the official OpenStack CI infrastructure, you
will want to pass --server puppetmaster.example.com otherwise the
new node wil try to register with puppetmaster.openstack.org - and
fail hilariously.
In order for Ansible to be able to send out the Puppet updates, In order for Ansible to be able to send out the Puppet updates,
you also need the puppetmaster to accept the root SSH key for the you also need the puppetmaster to accept the root SSH key for the
new server. So as root on the puppetmaster: new server. So as root on the puppetmaster:

View File

@ -18,68 +18,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os
import argparse import argparse
import utils
def get_client():
#TODO use shade
NOVA_USERNAME = os.environ['OS_USERNAME']
NOVA_PASSWORD = os.environ['OS_PASSWORD']
NOVA_URL = os.environ['OS_AUTH_URL']
NOVA_PROJECT_ID = os.environ['OS_TENANT_NAME']
NOVA_REGION_NAME = os.environ['OS_REGION_NAME']
args = [NOVA_USERNAME, NOVA_PASSWORD, NOVA_PROJECT_ID, NOVA_URL]
kwargs = {}
kwargs['region_name'] = NOVA_REGION_NAME
kwargs['service_type'] = 'compute'
from novaclient.v1_1.client import Client
client = Client(*args, **kwargs)
return client
def print_dns(client, name):
for server in client.servers.list():
if server.name != name:
continue
ip4 = utils.get_public_ip(server)
ip6 = utils.get_public_ip(server, 6)
href = utils.get_href(server)
print
print "Run the following commands to set up DNS:"
print
print ". ~root/rackdns-venv/bin/activate"
print
print (
"rackdns rdns-create --name %s \\\n"
" --data %s \\\n"
" --server-href %s \\\n"
" --ttl 3600" % (
server.name, ip6, href))
print
print (
"rackdns rdns-create --name %s \\\n"
" --data %s \\\n"
" --server-href %s \\\n"
" --ttl 3600" % (
server.name, ip4, href))
print
print ". ~root/ci-launch/openstack-rs-nova.sh"
print
print (
"rackdns record-create --name %s \\\n"
" --type AAAA --data %s \\\n"
" --ttl 3600 openstack.org" % (
server.name, ip6))
print
print (
"rackdns record-create --name %s \\\n"
" --type A --data %s \\\n"
" --ttl 3600 openstack.org" % (
server.name, ip4))
def get_href(server): def get_href(server):
@ -90,7 +29,7 @@ def get_href(server):
return link['href'] return link['href']
def shade_print_dns(cloud, server): def print_dns(cloud, server):
ip4 = server.public_v4 ip4 = server.public_v4
ip6 = server.public_v6 ip6 = server.public_v6
@ -137,8 +76,10 @@ def main():
parser.add_argument("name", help="server name") parser.add_argument("name", help="server name")
options = parser.parse_args() options = parser.parse_args()
client = get_client() import shade
print_dns(client, options.name) cloud = shade.openstack_cloud()
server = cloud.get_server(options.name)
print_dns(cloud, server)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

266
launch/launch-node.py Executable file → Normal file
View File

@ -18,55 +18,37 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import sys import argparse
import os import os
import subprocess
import sys
import tempfile
import time import time
import traceback import traceback
import argparse
import dns import dns
import utils import utils
NOVA_USERNAME = os.environ['OS_USERNAME'] import os_client_config
NOVA_PASSWORD = os.environ['OS_PASSWORD'] import paramiko
NOVA_URL = os.environ['OS_AUTH_URL'] import shade
NOVA_PROJECT_ID = os.environ['OS_TENANT_NAME']
NOVA_REGION_NAME = os.environ['OS_REGION_NAME']
NOVA_SERVICE_NAME = os.environ.get('OS_SERVICE_NAME')
NOVACLIENT_INSECURE = os.getenv('NOVACLIENT_INSECURE', None)
IPV6 = os.environ.get('IPV6', '0') is 1
SCRIPT_DIR = os.path.dirname(sys.argv[0]) SCRIPT_DIR = os.path.dirname(sys.argv[0])
try:
def get_client(): # This unactionable warning does not need to be printed over and over.
args = [NOVA_USERNAME, NOVA_PASSWORD, NOVA_PROJECT_ID, NOVA_URL] import requests.packages.urllib3
kwargs = {} requests.packages.urllib3.disable_warnings()
kwargs['region_name'] = NOVA_REGION_NAME except:
kwargs['service_type'] = 'compute' pass
if NOVA_SERVICE_NAME:
kwargs['service_name'] = NOVA_SERVICE_NAME
if NOVACLIENT_INSECURE:
kwargs['insecure'] = True
from novaclient.v1_1.client import Client
client = Client(*args, **kwargs)
return client
def bootstrap_server(server, admin_pass, key, cert, environment, name, def bootstrap_server(server, key, name, volume, keep):
puppetmaster, volume, floating_ip_pool):
ip = utils.get_public_ip(server, floating_ip_pool=floating_ip_pool)
if not ip:
raise Exception("Unable to find public ip of server")
ssh_kwargs = {} ip = server.public_v4
if key: ssh_kwargs = dict(pkey=key)
ssh_kwargs['pkey'] = key
else:
ssh_kwargs['password'] = admin_pass
print 'Public IP', ip
for username in ['root', 'ubuntu', 'centos', 'admin']: for username in ['root', 'ubuntu', 'centos', 'admin']:
ssh_client = utils.ssh_connect(ip, username, ssh_kwargs, timeout=600) ssh_client = utils.ssh_connect(ip, username, ssh_kwargs, timeout=600)
if ssh_client: if ssh_client:
@ -86,7 +68,7 @@ def bootstrap_server(server, admin_pass, key, cert, environment, name,
ssh_client = utils.ssh_connect(ip, 'root', ssh_kwargs, timeout=600) ssh_client = utils.ssh_connect(ip, 'root', ssh_kwargs, timeout=600)
if IPV6: if server.public_v6:
ssh_client.ssh('ping6 -c5 -Q 0x10 review.openstack.org ' ssh_client.ssh('ping6 -c5 -Q 0x10 review.openstack.org '
'|| ping6 -c5 -Q 0x10 wiki.openstack.org') '|| ping6 -c5 -Q 0x10 wiki.openstack.org')
@ -99,40 +81,50 @@ def bootstrap_server(server, admin_pass, key, cert, environment, name,
'mount_volume.sh') 'mount_volume.sh')
ssh_client.ssh('bash -x mount_volume.sh') ssh_client.ssh('bash -x mount_volume.sh')
# This next chunk should really exist as a playbook, but whatev
ssh_client.scp(os.path.join(SCRIPT_DIR, '..', 'install_puppet.sh'), ssh_client.scp(os.path.join(SCRIPT_DIR, '..', 'install_puppet.sh'),
'install_puppet.sh') 'install_puppet.sh')
ssh_client.ssh('bash -x install_puppet.sh') ssh_client.ssh('bash -x install_puppet.sh')
certname = cert[:(0 - len('.pem'))] shortname = name.split('.')[0]
ssh_client.ssh("mkdir -p /var/lib/puppet/ssl/certs") with ssh_client.open('/etc/hosts', 'w') as f:
ssh_client.ssh("mkdir -p /var/lib/puppet/ssl/private_keys") f.write('127.0.0.1 localhost\n')
ssh_client.ssh("mkdir -p /var/lib/puppet/ssl/public_keys") f.write('127.0.1.1 %s %s\n' % (name, shortname))
ssh_client.ssh("chown -R puppet:root /var/lib/puppet/ssl") with ssh_client.open('/etc/hostname', 'w') as f:
ssh_client.ssh("chown -R puppet:puppet /var/lib/puppet/ssl/private_keys") f.write('%s\n' % (shortname,))
ssh_client.ssh("chmod 0771 /var/lib/puppet/ssl") ssh_client.ssh("hostname %s" % (name,))
ssh_client.ssh("chmod 0755 /var/lib/puppet/ssl/certs")
ssh_client.ssh("chmod 0750 /var/lib/puppet/ssl/private_keys")
ssh_client.ssh("chmod 0755 /var/lib/puppet/ssl/public_keys")
for ssldir in ['/var/lib/puppet/ssl/certs/', # Write out the private SSH key we generated
'/var/lib/puppet/ssl/private_keys/', key_file = tempfile.NamedTemporaryFile(delete=not keep)
'/var/lib/puppet/ssl/public_keys/']: key.write_private_key(key_file)
ssh_client.scp(os.path.join(ssldir, cert), key_file.flush()
os.path.join(ssldir, cert))
ssh_client.scp("/var/lib/puppet/ssl/crl.pem", # Write out inventory
"/var/lib/puppet/ssl/crl.pem") inventory_file = tempfile.NamedTemporaryFile(delete=not keep)
ssh_client.scp("/var/lib/puppet/ssl/certs/ca.pem", inventory_file.write("{host} ansible_host={ip} ansible_user=root".format(
"/var/lib/puppet/ssl/certs/ca.pem") host=server.id, ip=server.interface_ip))
inventory_file.flush()
(rc, output) = ssh_client.ssh( ansible_cmd = [
"puppet agent " 'ansible-playbook',
"--environment %s " '-i', inventory_file.name, '-l', server.id,
"--server %s " '--private-key={key}'.format(key=key_file.name),
"--detailed-exitcodes " "--ssh-common-args='-o StrictHostKeyChecking=no'",
"--no-daemonize --verbose --onetime --pluginsync true " ]
"--certname %s" % (environment, puppetmaster, certname), error_ok=True)
utils.interpret_puppet_exitcodes(rc, output) # Run the remote puppet apply playbook limited to just this server
# we just created
try:
print subprocess.check_output(
ansible_cmd + [
os.path.join(
SCRIPT_DIR, '..', 'playbooks',
'remote_puppet_adhoc.yaml')],
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
print "Subprocess failed"
print e.output
raise
try: try:
ssh_client.ssh("reboot") ssh_client.ssh("reboot")
@ -145,94 +137,70 @@ def bootstrap_server(server, admin_pass, key, cert, environment, name,
raise raise
def build_server( def build_server(cloud, name, image, flavor,
client, name, image, flavor, cert, environment, puppetmaster, volume, volume, keep, network, boot_from_volume, config_drive):
keep, net_label, floating_ip_pool, boot_from_volume):
key = None key = None
server = None server = None
create_kwargs = dict(image=image, flavor=flavor, name=name) create_kwargs = dict(image=image, flavor=flavor, name=name,
reuse_ips=False, wait=True,
boot_from_volume=boot_from_volume,
network=network,
config_drive=config_drive)
if boot_from_volume: if volume:
block_mapping = [{ create_kwargs['volumes'] = [volume]
'boot_index': '0',
'delete_on_termination': True,
'destination_type': 'volume',
'uuid': image.id,
'source_type': 'image',
'volume_size': '50',
}]
create_kwargs['image'] = None
create_kwargs['block_device_mapping_v2'] = block_mapping
if net_label:
nics = []
for net in client.networks.list():
if net.label == net_label:
nics.append({'net-id': net.id})
create_kwargs['nics'] = nics
key_name = 'launch-%i' % (time.time()) key_name = 'launch-%i' % (time.time())
if 'os-keypairs' in utils.get_extensions(client): key = paramiko.RSAKey.generate(2048)
print "Adding keypair" public_key = key.get_name() + ' ' + key.get_base64()
key, kp = utils.add_keypair(client, key_name) cloud.create_keypair(key_name, public_key)
create_kwargs['key_name'] = key_name create_kwargs['key_name'] = key_name
try: try:
server = client.servers.create(**create_kwargs) server = cloud.create_server(**create_kwargs)
except Exception: except Exception:
try: try:
kp.delete() cloud.delete_keypair(key_name)
except Exception: except Exception:
print "Exception encountered deleting keypair:" print "Exception encountered deleting keypair:"
traceback.print_exc() traceback.print_exc()
raise raise
try: try:
admin_pass = server.adminPass cloud.delete_keypair(key_name)
server = utils.wait_for_resource(server)
if volume:
vobj = client.volumes.create_server_volume(
server.id, volume, None)
if not vobj:
raise Exception("Couldn't attach volume")
bootstrap_server(server, admin_pass, key, cert, environment, name, server = cloud.get_openstack_vars(server)
puppetmaster, volume, floating_ip_pool) bootstrap_server(server, key, name, volume, keep)
print('UUID=%s\nIPV4=%s\nIPV6=%s\n' % (server.id, print('UUID=%s\nIPV4=%s\nIPV6=%s\n' % (
server.accessIPv4, server.id, server.public_v4, server.public_v6))
server.accessIPv6))
if key:
kp.delete()
except Exception: except Exception:
try: try:
if keep: if keep:
print "Server failed to build, keeping as requested." print "Server failed to build, keeping as requested."
else: else:
utils.delete_server(server) cloud.delete_server(server.id, delete_ips=True)
except Exception: except Exception:
print "Exception encountered deleting server:" print "Exception encountered deleting server:"
traceback.print_exc() traceback.print_exc()
# Raise the important exception that started this # Raise the important exception that started this
raise raise
return server
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("name", help="server name") parser.add_argument("name", help="server name")
parser.add_argument("--cloud", dest="cloud", required=True,
help="cloud name")
parser.add_argument("--region", dest="region",
help="cloud region")
parser.add_argument("--flavor", dest="flavor", default='1GB', parser.add_argument("--flavor", dest="flavor", default='1GB',
help="name (or substring) of flavor") help="name (or substring) of flavor")
parser.add_argument("--image", dest="image", parser.add_argument("--image", dest="image",
default="Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)", default="Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)",
help="image name") help="image name")
parser.add_argument("--environment", dest="environment",
default="production",
help="puppet environment name")
parser.add_argument("--cert", dest="cert",
help="name of signed puppet certificate file (e.g., "
"hostname.example.com.pem)")
parser.add_argument("--server", dest="server", help="Puppetmaster to use.",
default="puppetmaster.openstack.org")
parser.add_argument("--volume", dest="volume", parser.add_argument("--volume", dest="volume",
help="UUID of volume to attach to the new server.", help="UUID of volume to attach to the new server.",
default=None) default=None)
@ -244,58 +212,50 @@ def main():
help="Don't clean up or delete the server on error.", help="Don't clean up or delete the server on error.",
action='store_true', action='store_true',
default=False) default=False)
parser.add_argument("--net-label", dest="net_label", default='', parser.add_argument("--verbose", dest="verbose", default=False,
action='store_true',
help="Be verbose about logging cloud actions")
parser.add_argument("--network", dest="network", default=None,
help="network label to attach instance to") help="network label to attach instance to")
parser.add_argument("--fip-pool", dest="floating_ip_pool", default=None, parser.add_argument("--config-drive", dest="config_drive",
help="pool to assign floating IP from") help="Boot with config_drive attached.",
action='store_true',
default=True)
options = parser.parse_args() options = parser.parse_args()
client = get_client() shade.simple_logging(debug=options.verbose)
if options.cert: cloud_kwargs = {}
cert = options.cert if options.region:
cloud_kwargs['region_name'] = options.region
cloud_config = os_client_config.OpenStackConfig().get_one_cloud(
options.cloud, **cloud_kwargs)
cloud = shade.OpenStackCloud(cloud_config)
flavor = cloud.get_flavor(options.flavor)
if flavor:
print "Found flavor", flavor.name
else: else:
cert = options.name + ".pem" print "Unable to find matching flavor; flavor list:"
for i in cloud.list_flavors():
if not os.path.exists(os.path.join("/var/lib/puppet/ssl/private_keys",
cert)):
raise Exception("Please specify the name of a signed puppet cert.")
flavors = [f for f in client.flavors.list()
if options.flavor in (f.name, f.id)]
flavor = flavors[0]
print "Found flavor", flavor
images = [i for i in client.images.list()
if (options.image.lower() in (i.id, i.name.lower()) and
not i.name.endswith('(Kernel)') and
not i.name.endswith('(Ramdisk)'))]
if len(images) > 1:
print "Ambiguous image name; matches:"
for i in images:
print i.name print i.name
sys.exit(1) sys.exit(1)
if len(images) == 0: image = cloud.get_image_exclude(options.image, 'deprecated')
if image:
print "Found image", image.name
else:
print "Unable to find matching image; image list:" print "Unable to find matching image; image list:"
for i in client.images.list(): for i in cloud.list_images():
print i.name print i.name
sys.exit(1) sys.exit(1)
image = images[0] server = build_server(cloud, options.name, image, flavor,
print "Found image", image options.volume, options.keep,
options.network, options.boot_from_volume,
if options.volume: options.config_drive)
print "The --volume option does not support cinder; until it does" dns.print_dns(cloud, server)
print "it should not be used."
sys.exit(1)
build_server(client, options.name, image, flavor, cert,
options.environment, options.server, options.volume,
options.keep, options.net_label, options.floating_ip_pool,
options.boot_from_volume)
dns.print_dns(client, options.name)
# Remove the ansible inventory cache so that next run finds the new # Remove the ansible inventory cache so that next run finds the new
# server # server
if os.path.exists('/var/cache/ansible-inventory/ansible-inventory.cache'): if os.path.exists('/var/cache/ansible-inventory/ansible-inventory.cache'):

View File

@ -1,266 +0,0 @@
#!/usr/bin/env python
# Launch a new OpenStack project infrastructure node.
# Copyright (C) 2011-2012 OpenStack LLC.
#
# 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 argparse
import os
import subprocess
import sys
import tempfile
import time
import traceback
import dns
import utils
import os_client_config
import paramiko
import shade
SCRIPT_DIR = os.path.dirname(sys.argv[0])
try:
# This unactionable warning does not need to be printed over and over.
import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()
except:
pass
def bootstrap_server(server, key, name, volume, keep):
ip = server.public_v4
ssh_kwargs = dict(pkey=key)
print 'Public IP', ip
for username in ['root', 'ubuntu', 'centos', 'admin']:
ssh_client = utils.ssh_connect(ip, username, ssh_kwargs, timeout=600)
if ssh_client:
break
if not ssh_client:
raise Exception("Unable to log in via SSH")
# cloud-init puts the "please log in as user foo" message and
# subsequent exit() in root's authorized_keys -- overwrite it with
# a normal version to get root login working again.
if username != 'root':
ssh_client.ssh("sudo cp ~/.ssh/authorized_keys"
" ~root/.ssh/authorized_keys")
ssh_client.ssh("sudo chmod 644 ~root/.ssh/authorized_keys")
ssh_client.ssh("sudo chown root.root ~root/.ssh/authorized_keys")
ssh_client = utils.ssh_connect(ip, 'root', ssh_kwargs, timeout=600)
if server.public_v6:
ssh_client.ssh('ping6 -c5 -Q 0x10 review.openstack.org '
'|| ping6 -c5 -Q 0x10 wiki.openstack.org')
ssh_client.scp(os.path.join(SCRIPT_DIR, '..', 'make_swap.sh'),
'make_swap.sh')
ssh_client.ssh('bash -x make_swap.sh')
if volume:
ssh_client.scp(os.path.join(SCRIPT_DIR, '..', 'mount_volume.sh'),
'mount_volume.sh')
ssh_client.ssh('bash -x mount_volume.sh')
# This next chunk should really exist as a playbook, but whatev
ssh_client.scp(os.path.join(SCRIPT_DIR, '..', 'install_puppet.sh'),
'install_puppet.sh')
ssh_client.ssh('bash -x install_puppet.sh')
shortname = name.split('.')[0]
with ssh_client.open('/etc/hosts', 'w') as f:
f.write('127.0.0.1 localhost\n')
f.write('127.0.1.1 %s %s\n' % (name, shortname))
with ssh_client.open('/etc/hostname', 'w') as f:
f.write('%s\n' % (shortname,))
ssh_client.ssh("hostname %s" % (name,))
# Write out the private SSH key we generated
key_file = tempfile.NamedTemporaryFile(delete=not keep)
key.write_private_key(key_file)
key_file.flush()
# Write out inventory
inventory_file = tempfile.NamedTemporaryFile(delete=not keep)
inventory_file.write("{host} ansible_host={ip} ansible_user=root".format(
host=server.id, ip=server.interface_ip))
inventory_file.flush()
ansible_cmd = [
'ansible-playbook',
'-i', inventory_file.name, '-l', server.id,
'--private-key={key}'.format(key=key_file.name),
"--ssh-common-args='-o StrictHostKeyChecking=no'",
]
# Run the remote puppet apply playbook limited to just this server
# we just created
try:
print subprocess.check_output(
ansible_cmd + [
os.path.join(
SCRIPT_DIR, '..', 'playbooks',
'remote_puppet_adhoc.yaml')],
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
print "Subprocess failed"
print e.output
raise
try:
ssh_client.ssh("reboot")
except Exception as e:
# Some init system kill the connection too fast after reboot.
# Deal with it by ignoring ssh errors when rebooting.
if e.rc == -1:
pass
else:
raise
def build_server(cloud, name, image, flavor,
volume, keep, network, boot_from_volume, config_drive):
key = None
server = None
create_kwargs = dict(image=image, flavor=flavor, name=name,
reuse_ips=False, wait=True,
boot_from_volume=boot_from_volume,
network=network,
config_drive=config_drive)
if volume:
create_kwargs['volumes'] = [volume]
key_name = 'launch-%i' % (time.time())
key = paramiko.RSAKey.generate(2048)
public_key = key.get_name() + ' ' + key.get_base64()
cloud.create_keypair(key_name, public_key)
create_kwargs['key_name'] = key_name
try:
server = cloud.create_server(**create_kwargs)
except Exception:
try:
cloud.delete_keypair(key_name)
except Exception:
print "Exception encountered deleting keypair:"
traceback.print_exc()
raise
try:
cloud.delete_keypair(key_name)
server = cloud.get_openstack_vars(server)
bootstrap_server(server, key, name, volume, keep)
print('UUID=%s\nIPV4=%s\nIPV6=%s\n' % (
server.id, server.public_v4, server.public_v6))
except Exception:
try:
if keep:
print "Server failed to build, keeping as requested."
else:
cloud.delete_server(server.id, delete_ips=True)
except Exception:
print "Exception encountered deleting server:"
traceback.print_exc()
# Raise the important exception that started this
raise
return server
def main():
parser = argparse.ArgumentParser()
parser.add_argument("name", help="server name")
parser.add_argument("--cloud", dest="cloud", required=True,
help="cloud name")
parser.add_argument("--region", dest="region",
help="cloud region")
parser.add_argument("--flavor", dest="flavor", default='1GB',
help="name (or substring) of flavor")
parser.add_argument("--image", dest="image",
default="Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)",
help="image name")
parser.add_argument("--volume", dest="volume",
help="UUID of volume to attach to the new server.",
default=None)
parser.add_argument("--boot-from-volume", dest="boot_from_volume",
help="Create a boot volume for the server and use it.",
action='store_true',
default=False)
parser.add_argument("--keep", dest="keep",
help="Don't clean up or delete the server on error.",
action='store_true',
default=False)
parser.add_argument("--verbose", dest="verbose", default=False,
action='store_true',
help="Be verbose about logging cloud actions")
parser.add_argument("--network", dest="network", default=None,
help="network label to attach instance to")
parser.add_argument("--config-drive", dest="config_drive",
help="Boot with config_drive attached.",
action='store_true',
default=True)
options = parser.parse_args()
shade.simple_logging(debug=options.verbose)
cloud_kwargs = {}
if options.region:
cloud_kwargs['region_name'] = options.region
cloud_config = os_client_config.OpenStackConfig().get_one_cloud(
options.cloud, **cloud_kwargs)
cloud = shade.OpenStackCloud(cloud_config)
flavor = cloud.get_flavor(options.flavor)
if flavor:
print "Found flavor", flavor.name
else:
print "Unable to find matching flavor; flavor list:"
for i in cloud.list_flavors():
print i.name
sys.exit(1)
image = cloud.get_image_exclude(options.image, 'deprecated')
if image:
print "Found image", image.name
else:
print "Unable to find matching image; image list:"
for i in cloud.list_images():
print i.name
sys.exit(1)
server = build_server(cloud, options.name, image, flavor,
options.volume, options.keep,
options.network, options.boot_from_volume,
options.config_drive)
dns.shade_print_dns(cloud, server)
# Remove the ansible inventory cache so that next run finds the new
# server
if os.path.exists('/var/cache/ansible-inventory/ansible-inventory.cache'):
os.unlink('/var/cache/ansible-inventory/ansible-inventory.cache')
os.system('/usr/local/bin/expand-groups.sh')
if __name__ == '__main__':
main()

View File

@ -19,7 +19,6 @@
# limitations under the License. # limitations under the License.
import time import time
import traceback
import socket import socket
import paramiko import paramiko
@ -37,32 +36,6 @@ def iterate_timeout(max_seconds, purpose):
raise Exception("Timeout waiting for %s" % purpose) raise Exception("Timeout waiting for %s" % purpose)
def wait_for_resource(wait_resource):
last_progress = None
last_status = None
# It can take a _very_ long time for Rackspace 1.0 to save an image
for count in iterate_timeout(21600, "waiting for %s" % wait_resource):
try:
resource = wait_resource.manager.get(wait_resource.id)
except:
print "Unable to list resources, will retry"
traceback.print_exc()
time.sleep(5)
continue
# In Rackspace v1.0, there is no progress attribute while queued
if hasattr(resource, 'progress'):
if (last_progress != resource.progress
or last_status != resource.status):
print resource.status, resource.progress
last_progress = resource.progress
elif last_status != resource.status:
print resource.status
last_status = resource.status
if resource.status == 'ACTIVE':
return resource
def ssh_connect(ip, username, connect_kwargs={}, timeout=60): def ssh_connect(ip, username, connect_kwargs={}, timeout=60):
# HPcloud may return errno 111 for about 30 seconds after adding the IP # HPcloud may return errno 111 for about 30 seconds after adding the IP
for count in iterate_timeout(timeout, "ssh access"): for count in iterate_timeout(timeout, "ssh access"):