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:
Monty Taylor 2015-11-18 14:37:42 -05:00
parent 8b3bb61ae7
commit e14471dcc6
3 changed files with 70 additions and 235 deletions

View File

@ -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:"

View File

@ -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'):

View File

@ -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