Last active
August 29, 2015 14:09
-
-
Save sbotman/d8634359c030fc76ca7a to your computer and use it in GitHub Desktop.
Cloudinit patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright 2014 Cloudbase Solutions Srl | |
# | |
# 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 oslo.config import cfg | |
from six.moves import urllib | |
from cloudbaseinit.metadata.services import base | |
from cloudbaseinit.openstack.common import log as logging | |
from cloudbaseinit.osutils import factory as osutils_factory | |
LOG = logging.getLogger(__name__) | |
OPTS = [ | |
cfg.StrOpt('cloudstack_metadata_ip', default="10.1.1.1", | |
help='The IP adress where the service looks for metadata'), | |
] | |
CONF = cfg.CONF | |
CONF.register_opts(OPTS) | |
class CloudStack(base.BaseMetadataService): | |
URI_TEMPLATE = 'http://%s/latest/meta-data/' | |
def __init__(self): | |
super(CloudStack, self).__init__() | |
self.osutils = osutils_factory.get_os_utils() | |
self._metadata_uri = None | |
self._router_ip = None | |
def _test_api(self, ip_address): | |
"""Test if the CloudStack API is responding properly.""" | |
self._metadata_uri = self.URI_TEMPLATE % ip_address | |
try: | |
response = self._http_request(self._metadata_uri) | |
self._get_data('service-offering') | |
except urllib.error.HTTPError as exc: | |
LOG.debug('Error response code: %s', exc.code) | |
return False | |
except base.NotExistingMetadataException: | |
LOG.debug('Invalid service response.') | |
return False | |
except Exception as exc: | |
LOG.debug('Something went wrong.') | |
LOG.exception(exc) | |
return False | |
LOG.debug('Available services: %s', response) | |
self._router_ip = ip_address | |
return True | |
def load(self): | |
"""Obtain all the required informations.""" | |
super(CloudStack, self).load() | |
if self._test_api(CONF.cloudstack_metadata_ip): | |
return True | |
dhcp_servers = self.osutils.get_dhcp_hosts_in_use() | |
if not dhcp_servers: | |
LOG.debug('No DHCP server was found.') | |
return False | |
for _, ip_address in dhcp_servers: | |
LOG.debug('Testing: %s', ip_address) | |
if self._test_api(ip_address): | |
return True | |
return False | |
def _http_request(self, url, **kwargs): | |
"""Get content for received url.""" | |
LOG.debug('Getting metadata from: %s', url) | |
request = urllib.request.Request(url, **kwargs) | |
response = urllib.request.urlopen(request) | |
return response.read() | |
def _get_data(self, path): | |
"""Getting required metadata using CloudStack metadata API.""" | |
metadata_uri = urllib.parse.urljoin(self._metadata_uri, path) | |
try: | |
content = self._http_request(metadata_uri) | |
except urllib.error.HTTPError as exc: | |
if exc.code == 404: | |
raise base.NotExistingMetadataException() | |
raise | |
return content | |
def get_instance_id(self): | |
"""Instance name of the virtual machine.""" | |
return self._get_cache_data('instance-id') | |
def get_host_name(self): | |
"""Hostname of the virtual machine.""" | |
return self._get_cache_data('local-hostname') | |
def get_user_data(self): | |
"""User data for this virtual machine.""" | |
return self._get_cache_data('../user-data') | |
def get_public_keys(self): | |
"""Available ssh public keys.""" | |
return self._get_cache_data('public-keys') | |
def get_admin_password(self): | |
"""Administrator password.""" | |
url = "http://%s:8080" % self._router_ip | |
headers = urllib.parse.urlencode({'DomU_Request': 'send_my_password'}) | |
LOG.debug('Getting Administrator password from %s', url) | |
for _ in range(CONF.retry_count): | |
try: | |
password = self._http_request(url, headers=headers) | |
except urllib.error.HTTPError: | |
continue | |
if not password: | |
LOG.debug("Web service did not have any password for the VM.") | |
continue | |
elif password == "bad_request": | |
LOG.debug("VM sent an invalid request to the web service.") | |
continue | |
elif password == "saved_password": | |
LOG.debug("The VM already saved a password from web service.") | |
break | |
else: | |
return password.strip() | |
LOG.debug('Administrator password not found.') | |
return None | |
def get_service_offering(self): | |
"""A description of the virtual machine's service offering.""" | |
return self._get_cache_data('service-offering') | |
def get_availability_zone(self): | |
"""The zone name.""" | |
return self._get_cache_data('availability-zone') | |
def get_local_ipv4(self): | |
"""The guest IP of the virtual machine.""" | |
return self._get_cache_data('local-ipv4') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# vim: tabstop=4 shiftwidth=4 softtabstop=4 | |
# Copyright 2012 Cloudbase Solutions Srl | |
# | |
# 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 oslo.config import cfg | |
from cloudbaseinit import exception | |
from cloudbaseinit.openstack.common import log as logging | |
from cloudbaseinit.utils import classloader | |
opts = [ | |
cfg.ListOpt( | |
'metadata_services', | |
default=[ | |
'cloudbaseinit.metadata.services.cloudstack.CloudStack', | |
'cloudbaseinit.metadata.services.httpservice.HttpService', | |
'cloudbaseinit.metadata.services.configdrive.ConfigDriveService', | |
'cloudbaseinit.metadata.services.ec2service.EC2Service', | |
'cloudbaseinit.metadata.services.maasservice.MaaSHttpService' | |
], | |
help='List of enabled metadata service classes, ' | |
'to be tested fro availability in the provided order. ' | |
'The first available service will be used to retrieve ' | |
'metadata') | |
] | |
CONF = cfg.CONF | |
CONF.register_opts(opts) | |
LOG = logging.getLogger(__name__) | |
def get_metadata_service(): | |
# Return the first service that loads correctly | |
cl = classloader.ClassLoader() | |
for class_path in CONF.metadata_services: | |
service = cl.load_class(class_path)() | |
try: | |
if service.load(): | |
return service | |
except Exception as ex: | |
LOG.error("Failed to load metadata service '%s'" % class_path) | |
LOG.exception(ex) | |
raise exception.CloudbaseInitException("No available service found") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment