Update for ansible and puppet apply
Shade supports all of the TODO items in here now, so use it. Also, we have ansible playbooks that do the work of running puppet - and since we're on puppet apply now, we can use them. Change-Id: I6f57e9a31bf835ef2e22db1f5531d92e99806cf4
This commit is contained in:
parent
8b3bb61ae7
commit
e14471dcc6
@ -82,10 +82,21 @@ def print_dns(client, name):
|
||||
server.name, ip4))
|
||||
|
||||
|
||||
def shade_print_dns(server):
|
||||
def get_href(server):
|
||||
if not hasattr(server, 'links'):
|
||||
return None
|
||||
for link in server.links:
|
||||
if link['rel'] == 'self':
|
||||
return link['href']
|
||||
|
||||
|
||||
def shade_print_dns(cloud, server):
|
||||
ip4 = server.public_v4
|
||||
ip6 = server.public_v6
|
||||
href = utils.get_href(server)
|
||||
|
||||
for raw_server in cloud.nova_client.servers.list():
|
||||
if raw_server.id == server.id:
|
||||
href = get_href(raw_server)
|
||||
|
||||
print
|
||||
print "Run the following commands to set up DNS:"
|
||||
|
@ -18,11 +18,13 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
import argparse
|
||||
|
||||
import dns
|
||||
import utils
|
||||
@ -41,8 +43,8 @@ except:
|
||||
pass
|
||||
|
||||
|
||||
def bootstrap_server(server, key, cert, environment, name,
|
||||
puppetmaster, volume, floating_ip_pool):
|
||||
def bootstrap_server(server, key, name, volume, keep):
|
||||
|
||||
ip = server.public_v4
|
||||
ssh_kwargs = dict(pkey=key)
|
||||
|
||||
@ -79,11 +81,11 @@ def bootstrap_server(server, key, cert, environment, name,
|
||||
'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')
|
||||
|
||||
certname = cert[:(0 - len('.pem'))]
|
||||
shortname = name.split('.')[0]
|
||||
with ssh_client.open('/etc/hosts', 'w') as f:
|
||||
f.write('127.0.0.1 localhost\n')
|
||||
@ -91,35 +93,38 @@ def bootstrap_server(server, key, cert, environment, name,
|
||||
with ssh_client.open('/etc/hostname', 'w') as f:
|
||||
f.write('%s\n' % (shortname,))
|
||||
ssh_client.ssh("hostname %s" % (name,))
|
||||
ssh_client.ssh("mkdir -p /var/lib/puppet/ssl/certs")
|
||||
ssh_client.ssh("mkdir -p /var/lib/puppet/ssl/private_keys")
|
||||
ssh_client.ssh("mkdir -p /var/lib/puppet/ssl/public_keys")
|
||||
ssh_client.ssh("chown -R puppet:root /var/lib/puppet/ssl")
|
||||
ssh_client.ssh("chown -R puppet:puppet /var/lib/puppet/ssl/private_keys")
|
||||
ssh_client.ssh("chmod 0771 /var/lib/puppet/ssl")
|
||||
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/',
|
||||
'/var/lib/puppet/ssl/private_keys/',
|
||||
'/var/lib/puppet/ssl/public_keys/']:
|
||||
ssh_client.scp(os.path.join(ssldir, cert),
|
||||
os.path.join(ssldir, cert))
|
||||
# Write out the private SSH key we generated
|
||||
key_file = tempfile.NamedTemporaryFile(delete=not keep)
|
||||
key.write_private_key(key_file)
|
||||
key_file.flush()
|
||||
|
||||
ssh_client.scp("/var/lib/puppet/ssl/crl.pem",
|
||||
"/var/lib/puppet/ssl/crl.pem")
|
||||
ssh_client.scp("/var/lib/puppet/ssl/certs/ca.pem",
|
||||
"/var/lib/puppet/ssl/certs/ca.pem")
|
||||
# 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()
|
||||
|
||||
(rc, output) = ssh_client.ssh(
|
||||
"puppet agent "
|
||||
"--environment %s "
|
||||
"--server %s "
|
||||
"--detailed-exitcodes "
|
||||
"--no-daemonize --verbose --onetime --pluginsync true "
|
||||
"--certname %s" % (environment, puppetmaster, certname), error_ok=True)
|
||||
utils.interpret_puppet_exitcodes(rc, output)
|
||||
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")
|
||||
@ -132,37 +137,19 @@ def bootstrap_server(server, key, cert, environment, name,
|
||||
raise
|
||||
|
||||
|
||||
def build_server(cloud, name, image, flavor, cert, environment,
|
||||
puppetmaster, volume, keep, net_label,
|
||||
floating_ip_pool, boot_from_volume,
|
||||
config_drive):
|
||||
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, config_drive=config_drive)
|
||||
reuse_ips=False, wait=True,
|
||||
boot_from_volume=boot_from_volume,
|
||||
network=network,
|
||||
config_drive=config_drive)
|
||||
|
||||
#TODO: test with rax
|
||||
#TODO: use shade
|
||||
if boot_from_volume:
|
||||
block_mapping = [{
|
||||
'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
|
||||
|
||||
#TODO: use shade
|
||||
#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
|
||||
if volume:
|
||||
create_kwargs['volumes'] = [volume]
|
||||
|
||||
key_name = 'launch-%i' % (time.time())
|
||||
key = paramiko.RSAKey.generate(2048)
|
||||
@ -183,20 +170,10 @@ def build_server(cloud, name, image, flavor, cert, environment,
|
||||
try:
|
||||
cloud.delete_keypair(key_name)
|
||||
|
||||
# TODO: use shade
|
||||
if volume:
|
||||
raise Exception("not implemented")
|
||||
#vobj = client.volumes.create_server_volume(
|
||||
# server.id, volume, None)
|
||||
#if not vobj:
|
||||
# raise Exception("Couldn't attach volume")
|
||||
|
||||
server = cloud.get_openstack_vars(server)
|
||||
bootstrap_server(server, key, cert, environment, name,
|
||||
puppetmaster, volume, floating_ip_pool)
|
||||
print('UUID=%s\nIPV4=%s\nIPV6=%s\n' % (server.id,
|
||||
server.accessIPv4,
|
||||
server.accessIPv6))
|
||||
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:
|
||||
@ -224,14 +201,6 @@ def main():
|
||||
parser.add_argument("--image", dest="image",
|
||||
default="Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)",
|
||||
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",
|
||||
help="UUID of volume to attach to the new server.",
|
||||
default=None)
|
||||
@ -243,24 +212,18 @@ def main():
|
||||
help="Don't clean up or delete the server on error.",
|
||||
action='store_true',
|
||||
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")
|
||||
parser.add_argument("--fip-pool", dest="floating_ip_pool", default=None,
|
||||
help="pool to assign floating IP from")
|
||||
parser.add_argument("--config-drive", dest="config_drive",
|
||||
help="Boot with config_drive attached.",
|
||||
action='store_true',
|
||||
default=False)
|
||||
default=True)
|
||||
options = parser.parse_args()
|
||||
|
||||
if options.cert:
|
||||
cert = options.cert
|
||||
else:
|
||||
cert = options.name + ".pem"
|
||||
|
||||
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.")
|
||||
shade.simple_logging(debug=options.verbose)
|
||||
|
||||
cloud_kwargs = {}
|
||||
if options.region:
|
||||
@ -288,17 +251,11 @@ def main():
|
||||
print i.name
|
||||
sys.exit(1)
|
||||
|
||||
if options.volume:
|
||||
print "The --volume option does not support cinder; until it does"
|
||||
print "it should not be used."
|
||||
sys.exit(1)
|
||||
|
||||
server = build_server(cloud, options.name, image, flavor, cert,
|
||||
options.environment, options.server,
|
||||
server = build_server(cloud, options.name, image, flavor,
|
||||
options.volume, options.keep,
|
||||
options.net_label, options.floating_ip_pool,
|
||||
options.boot_from_volume, options.config_drive)
|
||||
dns.shade_print_dns(server)
|
||||
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'):
|
||||
|
133
launch/utils.py
133
launch/utils.py
@ -19,16 +19,9 @@
|
||||
# limitations under the License.
|
||||
|
||||
import time
|
||||
import os
|
||||
import traceback
|
||||
import socket
|
||||
|
||||
import novaclient
|
||||
from novaclient.v1_1 import client as Client11
|
||||
try:
|
||||
from v1_0 import client as Client10
|
||||
except:
|
||||
pass
|
||||
import paramiko
|
||||
|
||||
from sshclient import SSHClient
|
||||
@ -44,108 +37,6 @@ def iterate_timeout(max_seconds, purpose):
|
||||
raise Exception("Timeout waiting for %s" % purpose)
|
||||
|
||||
|
||||
def get_client(provider):
|
||||
args = [provider.nova_username, provider.nova_api_key,
|
||||
provider.nova_project_id, provider.nova_auth_url]
|
||||
kwargs = {}
|
||||
if provider.nova_service_type:
|
||||
kwargs['service_type'] = provider.nova_service_type
|
||||
if provider.nova_service_name:
|
||||
kwargs['service_name'] = provider.nova_service_name
|
||||
if provider.nova_service_region:
|
||||
kwargs['region_name'] = provider.nova_service_region
|
||||
if provider.nova_api_version == '1.0':
|
||||
Client = Client10.Client
|
||||
elif provider.nova_api_version == '1.1':
|
||||
Client = Client11.Client
|
||||
else:
|
||||
raise Exception("API version not supported")
|
||||
if provider.nova_rax_auth:
|
||||
os.environ['NOVA_RAX_AUTH'] = '1'
|
||||
client = Client(*args, **kwargs)
|
||||
return client
|
||||
|
||||
extension_cache = {}
|
||||
|
||||
|
||||
def get_extensions(client):
|
||||
global extension_cache
|
||||
cache = extension_cache.get(client)
|
||||
if cache:
|
||||
return cache
|
||||
try:
|
||||
resp, body = client.client.get('/extensions')
|
||||
extensions = [x['alias'] for x in body['extensions']]
|
||||
except novaclient.exceptions.NotFound:
|
||||
extensions = []
|
||||
extension_cache[client] = extensions
|
||||
return extensions
|
||||
|
||||
|
||||
def get_flavor(client, min_ram):
|
||||
flavors = [f for f in client.flavors.list() if f.ram >= min_ram]
|
||||
flavors.sort(lambda a, b: cmp(a.ram, b.ram))
|
||||
return flavors[0]
|
||||
|
||||
|
||||
def get_public_ip(server, version=4, floating_ip_pool=None):
|
||||
for addr in server.addresses.get('Ext-Net', []):
|
||||
if addr.get('version') == version: # OVH
|
||||
return addr['addr']
|
||||
if 'os-floating-ips' in get_extensions(server.manager.api):
|
||||
for addr in server.manager.api.floating_ips.list():
|
||||
if addr.instance_id == server.id:
|
||||
return addr.ip
|
||||
# We don't have one - so add one please
|
||||
new_ip = server.manager.api.floating_ips.create(pool=floating_ip_pool)
|
||||
server.add_floating_ip(new_ip)
|
||||
for addr in server.manager.api.floating_ips.list():
|
||||
if addr.instance_id == server.id:
|
||||
return addr.ip
|
||||
for addr in server.addresses.get('public', []):
|
||||
if type(addr) == type(u''): # Rackspace/openstack 1.0
|
||||
return addr
|
||||
if addr['version'] == version: # Rackspace/openstack 1.1
|
||||
return addr['addr']
|
||||
for addr in server.addresses.get('private', []):
|
||||
# HP Cloud
|
||||
if addr['version'] == version and not addr['addr'].startswith('10.'):
|
||||
return addr['addr']
|
||||
return None
|
||||
|
||||
|
||||
def get_href(server):
|
||||
if not hasattr(server, 'links'):
|
||||
return None
|
||||
for link in server.links:
|
||||
if link['rel'] == 'self':
|
||||
return link['href']
|
||||
|
||||
|
||||
def add_public_ip(server):
|
||||
ip = server.manager.api.floating_ips.create()
|
||||
server.add_floating_ip(ip)
|
||||
for count in iterate_timeout(600, "ip to be added"):
|
||||
try:
|
||||
newip = ip.manager.get(ip.id)
|
||||
except:
|
||||
print "Unable to get ip details, will retry"
|
||||
traceback.print_exc()
|
||||
time.sleep(5)
|
||||
continue
|
||||
|
||||
if newip.instance_id == server.id:
|
||||
print 'ip has been added'
|
||||
return
|
||||
|
||||
|
||||
def add_keypair(client, name):
|
||||
key = paramiko.RSAKey.generate(2048)
|
||||
public_key = key.get_name() + ' ' + key.get_base64()
|
||||
kp = client.keypairs.create(name, public_key)
|
||||
return key, kp
|
||||
|
||||
|
||||
def wait_for_resource(wait_resource):
|
||||
last_progress = None
|
||||
last_status = None
|
||||
@ -190,30 +81,6 @@ def ssh_connect(ip, username, connect_kwargs={}, timeout=60):
|
||||
return None
|
||||
|
||||
|
||||
def delete_server(server):
|
||||
try:
|
||||
if 'os-floating-ips' in get_extensions(server.manager.api):
|
||||
for addr in server.manager.api.floating_ips.list():
|
||||
if addr.instance_id == server.id:
|
||||
server.remove_floating_ip(addr)
|
||||
addr.delete()
|
||||
except:
|
||||
print "Unable to remove floating IP"
|
||||
traceback.print_exc()
|
||||
|
||||
try:
|
||||
if 'os-keypairs' in get_extensions(server.manager.api):
|
||||
for kp in server.manager.api.keypairs.list():
|
||||
if kp.name == server.key_name:
|
||||
kp.delete()
|
||||
except:
|
||||
print "Unable to delete keypair"
|
||||
traceback.print_exc()
|
||||
|
||||
print "Deleting server", server.id
|
||||
server.delete()
|
||||
|
||||
|
||||
def interpret_puppet_exitcodes(rc, output):
|
||||
if rc == 0:
|
||||
# success
|
||||
|
Loading…
x
Reference in New Issue
Block a user