From ce48babb700b2ed88e5861c19a270d4dd901e62e Mon Sep 17 00:00:00 2001 From: Brian Elliott Date: Fri, 6 Jun 2014 13:01:48 -0500 Subject: [PATCH] Add compute discovery * Also add a shell CLI for interactive sessions * Add separate admin auth cred support --- cachemonkey/auth.py | 46 ++++++++++++++++++++++-------- cachemonkey/cacher.py | 23 +++++++++++++-- cachemonkey/cmd/shell.py | 37 +++++++++++++++++++++++++ cachemonkey/discover.py | 60 ++++++++++++++++++++++++++++++++++++++++ setup.cfg | 1 + 5 files changed, 154 insertions(+), 13 deletions(-) create mode 100644 cachemonkey/cmd/shell.py create mode 100644 cachemonkey/discover.py diff --git a/cachemonkey/auth.py b/cachemonkey/auth.py index aec0ec0..eaa61d1 100644 --- a/cachemonkey/auth.py +++ b/cachemonkey/auth.py @@ -26,19 +26,32 @@ opts = [ cfg.StrOpt('url', help='Auth system endpoint URL'), cfg.StrOpt('username', help='Username for auth'), cfg.StrOpt('password', help='Password for auth'), + cfg.StrOpt('tenant', help='Tenant name'), cfg.StrOpt('region', help='Region'), + cfg.BoolOpt('insecure', default=False, + help='Skip SSL certification validation') ] +# register 2 groups: one for a non-priviledged user, and one for an admin user CONF.register_opts(opts, group='auth') +CONF.register_opts(opts, group='admin_auth') class Client(object): - def __init__(self): - url, username, password, region = self._config() - self.keystoneclient = client.Client(auth_url=url, username=username, - password=password, - region_name=region) + def __init__(self, group='auth'): + self.group = group + cfg_group = getattr(CONF, group) + + kwargs = self._config(cfg_group) + + if cfg_group.tenant: + kwargs['tenant_id'] = cfg_group.tenant + + LOG.warn(kwargs) + self.keystoneclient = client.Client(insecure=cfg_group.insecure, + debug=True, + **kwargs) def auth(self): if not self.keystoneclient.authenticate(): @@ -48,28 +61,39 @@ class Client(object): def catalog(self): return self.keystoneclient.service_catalog + @property + def tenant(self): + cfg_group = getattr(CONF, self.group) + return cfg_group.tenant + @property def token(self): return self.keystoneclient.auth_token - def _config(self): + def _config(self, group='auth'): # check for presence of required config options - url = CONF.auth.url + kwargs = {} + + url = group.url if not url: raise ValueError('Missing required url for auth') + kwargs['auth_url'] = url - username = CONF.auth.username + username = group.username if not username: raise ValueError('Missing required username for auth') + kwargs['username'] = username - password = CONF.auth.password + password = group.password if not password: raise ValueError('Missing required password for auth') + kwargs['password'] = password # the region scopes the catalog object for easier endpoint # identification - region = CONF.auth.region + region = group.region if not region: raise ValueError('Missing required region for auth') + kwargs['region_name'] = region - return url, username, password, region + return kwargs diff --git a/cachemonkey/cacher.py b/cachemonkey/cacher.py index 7c54bb8..a53162d 100644 --- a/cachemonkey/cacher.py +++ b/cachemonkey/cacher.py @@ -17,6 +17,7 @@ import os from oslo.config import cfg +from cachemonkey import discover from cachemonkey.openstack.common import importutils from cachemonkey.openstack.common import log as logging @@ -30,6 +31,9 @@ opts = [ cfg.StrOpt('fetcher_class', default='cachemonkey.fetcher.glance.GlanceFetcher', help='Class to determine how to fetch images.'), + cfg.StrOpt('distributor_class', + default='cachemonkey.distributor.glance.GlanceFetcher', + help='Class to determine how to fetch images.'), cfg.StrOpt('data_dir', default='/var/lib/cachemonkey', help='Directory containing image data'), @@ -45,11 +49,26 @@ class Cacher(object): self.fetcher = importutils.import_object( CONF.cachemonkey.fetcher_class) + self.discoverer = discover.ComputeDiscoverer() + self.images = [] + def cache(self): + self.images = [] images = self.lister.images() + for image in images: - self._get(image) - # TODO(belliott) distribute to hosts + filename = self._get(image) + image = {'meta': image, 'filename': filename} + self.images.append(image) + + # HACK(belliott) - just process first image for testing + break + + # update set of known computes + self.discoverer.discover() + + # TODO(belliott) prep for distribution and distribute + #self.distributor.distribute(image, filename) def _get(self, image): # first see if the image was previously downloaded diff --git a/cachemonkey/cmd/shell.py b/cachemonkey/cmd/shell.py new file mode 100644 index 0000000..d8635ec --- /dev/null +++ b/cachemonkey/cmd/shell.py @@ -0,0 +1,37 @@ +# Copyright 2014 Rackspace Hosting +# All Rights Reserved. +# +# 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 sys + +from oslo.config import cfg +import pbr.version + +from cachemonkey.openstack.common import log as logging + +project = 'cachemonkey' + + +def _version(): + vinfo = pbr.version.VersionInfo(project) + return vinfo.version_string() + + +def main(): + version = _version() + cfg.CONF(sys.argv[1:], project=project, version=version) + logging.setup(project, version=version) + + from IPython import embed + embed() diff --git a/cachemonkey/discover.py b/cachemonkey/discover.py new file mode 100644 index 0000000..b656135 --- /dev/null +++ b/cachemonkey/discover.py @@ -0,0 +1,60 @@ +# Copyright 2014 Rackspace Hosting +# All Rights Reserved. +# +# 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 +import requests + +from cachemonkey import auth +from cachemonkey.openstack.common import log as logging + +LOG = logging.getLogger(__name__) +CONF = cfg.CONF + +opts = [ + cfg.StrOpt('admin_auth_group', + default='admin_auth', + help='Config group to obtain compute admin credentials from'), +] + +CONF.register_opts(opts, group='cachemonkey') + + +class ComputeDiscoverer(object): + + def __init__(self): + self.authclient = auth.Client(CONF.cachemonkey.admin_auth_group) + #self.authclient.auth() + + def discover(self): + # do a nova service-list + endpoints = self.authclient.catalog.get_endpoints() + endpoints = endpoints['compute'] + if len(endpoints) > 1: + raise ValueError('More than one compute endpoint? %s' % endpoints) + + endpoint = endpoints[0]['publicURL'] + url = '%s/os-services' % endpoint + headers = { + 'Content-type': 'application/json', + 'Accept': 'application/json', + 'X-Auth-Token': self.authclient.token, + } + r = requests.get(url, headers=headers, verify=False) + LOG.debug("Service list response code: %d" % r.status_code) + LOG.debug("Servicer list response: %s" % r.text) + + # TODO(belliott) parse response, handle errors + return [] + diff --git a/setup.cfg b/setup.cfg index 02f40ab..49934ca 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,3 +34,4 @@ upload-dir = doc/build/html [entry_points] console_scripts = cachemonkey-server = cachemonkey.cmd.server:main + cachemonkey-shell = cachemonkey.cmd.shell:main