Skip to content

Commit 17911cb

Browse files
author
Tim Simpson
committed
Initial copy of reddwarfclient from reddwarf project.
1 parent 424c649 commit 17911cb

File tree

15 files changed

+1026
-0
lines changed

15 files changed

+1026
-0
lines changed

reddwarfclient/__init__.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Copyright (c) 2011 OpenStack, LLC.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
import time
17+
import urlparse
18+
19+
try:
20+
import json
21+
except ImportError:
22+
import simplejson as json
23+
24+
25+
from novaclient.client import HTTPClient
26+
from novaclient.v1_1.client import Client
27+
28+
29+
# To write this test from an end user perspective, we have to create a client
30+
# similar to the CloudServers one.
31+
# For now we will work on it here.
32+
33+
34+
class ReddwarfHTTPClient(HTTPClient):
35+
"""
36+
Class for overriding the HTTP authenticate call and making it specific to
37+
reddwarf
38+
"""
39+
40+
def __init__(self, user, apikey, tenant, auth_url, service_name,
41+
service_url=None, timeout=None):
42+
super(ReddwarfHTTPClient, self).__init__(user, apikey, tenant,
43+
auth_url, timeout=timeout)
44+
self.tenant = tenant
45+
self.service = service_name
46+
self.management_url = service_url
47+
48+
def authenticate(self):
49+
scheme, netloc, path, query, frag = urlparse.urlsplit(self.auth_url)
50+
path_parts = path.split('/')
51+
for part in path_parts:
52+
if len(part) > 0 and part[0] == 'v':
53+
self.version = part
54+
break
55+
56+
# Auth against Keystone version 2.0
57+
if self.version == "v2.0":
58+
req_body = {'passwordCredentials': {'username': self.user,
59+
'password': self.apikey,
60+
'tenantId': self.tenant}}
61+
self._get_token("/v2.0/tokens", req_body)
62+
# Auth against Keystone version 1.1
63+
elif self.version == "v1.1":
64+
req_body = {'credentials': {'username': self.user,
65+
'key': self.apikey}}
66+
self._get_token("/v1.1/auth", req_body)
67+
else:
68+
raise NotImplementedError("Version %s is not supported"
69+
% self.version)
70+
71+
def _get_token(self, path, req_body):
72+
"""Set the management url and auth token"""
73+
token_url = urlparse.urljoin(self.auth_url, path)
74+
resp, body = self.request(token_url, "POST", body=req_body)
75+
try:
76+
if not self.management_url:
77+
self.management_url = body['auth']['serviceCatalog'] \
78+
[self.service][0]['publicURL']
79+
self.auth_token = body['auth']['token']['id']
80+
except KeyError:
81+
raise NotImplementedError("Service: %s is not available"
82+
% self.service)
83+
84+
85+
class Dbaas(Client):
86+
"""
87+
Top-level object to access the Rackspace Database as a Service API.
88+
89+
Create an instance with your creds::
90+
91+
>>> red = Dbaas(USERNAME, API_KEY, TENANT, AUTH_URL, SERVICE_NAME,
92+
SERVICE_URL)
93+
94+
Then call methods on its managers::
95+
96+
>>> red.instances.list()
97+
...
98+
>>> red.flavors.list()
99+
...
100+
101+
&c.
102+
"""
103+
104+
def __init__(self, username, apikey, tenant=None, auth_url=None,
105+
service_name='reddwarf', service_url=None):
106+
super(Dbaas, self).__init__(self, username, apikey, tenant, auth_url)
107+
self.client = ReddwarfHTTPClient(username, apikey, tenant, auth_url,
108+
service_name, service_url)
109+
self.versions = Versions(self)
110+
self.databases = Databases(self)
111+
self.instances = Instances(self)
112+
self.users = Users(self)
113+
self.root = Root(self)
114+
self.hosts = Hosts(self)
115+
self.storage = StorageInfo(self)
116+
self.management = Management(self)
117+
self.accounts = Accounts(self)
118+
self.configs = Configs(self)
119+
self.diagnostics = Interrogator(self)
120+
121+
122+
from reddwarfclient.accounts import Accounts
123+
from reddwarfclient.config import Configs
124+
from reddwarfclient.databases import Databases
125+
from reddwarfclient.instances import Instances
126+
from reddwarfclient.hosts import Hosts
127+
from reddwarfclient.management import Management
128+
from reddwarfclient.root import Root
129+
from reddwarfclient.storage import StorageInfo
130+
from reddwarfclient.users import Users
131+
from reddwarfclient.versions import Versions
132+
from reddwarfclient.diagnostics import Interrogator

reddwarfclient/accounts.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright (c) 2011 OpenStack, LLC.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
from novaclient import base
17+
18+
class Account(base.Resource):
19+
"""
20+
Account is an opaque instance used to hold account information.
21+
"""
22+
def __repr__(self):
23+
return "<Account: %s>" % self.name
24+
25+
class Accounts(base.ManagerWithFind):
26+
"""
27+
Manage :class:`Account` information.
28+
"""
29+
30+
resource_class = Account
31+
32+
def _list(self, url, response_key):
33+
resp, body = self.api.client.get(url)
34+
if not body:
35+
raise Exception("Call to " + url + " did not return a body.")
36+
return self.resource_class(self, body[response_key])
37+
38+
def show(self, account):
39+
"""
40+
Get details of one account.
41+
42+
:rtype: :class:`Account`.
43+
"""
44+
45+
acct_name = self._get_account_name(account)
46+
return self._list("/mgmt/accounts/%s" % acct_name, 'account')
47+
48+
@staticmethod
49+
def _get_account_name(account):
50+
try:
51+
if account.name:
52+
return account.name
53+
except AttributeError:
54+
return account
55+

reddwarfclient/base.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
def isid(obj):
3+
"""
4+
Returns true if the given object can be converted to an ID, false otherwise.
5+
"""
6+
if hasattr(obj, "id"):
7+
return True
8+
else:
9+
try:
10+
int(obj)
11+
except ValueError:
12+
return False
13+
else:
14+
return True
15+

reddwarfclient/common.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Copyright 2011 OpenStack LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
import os
16+
import pickle
17+
import sys
18+
19+
20+
from reddwarfclient import Dbaas
21+
import exceptions
22+
23+
24+
APITOKEN = os.path.expanduser("~/.apitoken")
25+
26+
27+
def get_client():
28+
"""Load an existing apitoken if available"""
29+
try:
30+
with open(APITOKEN, 'rb') as token:
31+
apitoken = pickle.load(token)
32+
dbaas = Dbaas(apitoken._user, apitoken._apikey, apitoken._tenant,
33+
apitoken._auth_url, apitoken._service_name,
34+
apitoken._service_url)
35+
dbaas.client.auth_token = apitoken._token
36+
return dbaas
37+
except IOError:
38+
print "ERROR: You need to login first and get an auth token\n"
39+
sys.exit(1)
40+
except:
41+
print "ERROR: There was an error using your existing auth token, " \
42+
"please login again.\n"
43+
sys.exit(1)
44+
45+
46+
def methods_of(obj):
47+
"""Get all callable methods of an object that don't start with underscore
48+
returns a list of tuples of the form (method_name, method)"""
49+
result = {}
50+
for i in dir(obj):
51+
if callable(getattr(obj, i)) and not i.startswith('_'):
52+
result[i] = getattr(obj, i)
53+
return result
54+
55+
56+
def check_for_exceptions(resp, body):
57+
if resp.status in (400, 422, 500):
58+
raise exceptions.from_response(resp, body)
59+
60+
61+
def print_actions(cmd, actions):
62+
"""Print help for the command with list of options and description"""
63+
print ("Available actions for '%s' cmd:") % cmd
64+
for k, v in actions.iteritems():
65+
print "\t%-20s%s" % (k, v.__doc__)
66+
sys.exit(2)
67+
68+
69+
def print_commands(commands):
70+
"""Print the list of available commands and description"""
71+
72+
print "Available commands"
73+
for k, v in commands.iteritems():
74+
print "\t%-20s%s" % (k, v.__doc__)
75+
sys.exit(2)
76+
77+
78+
class APIToken(object):
79+
"""A token object containing the user, apikey and token which
80+
is pickleable."""
81+
82+
def __init__(self, user, apikey, tenant, token, auth_url, service_name,
83+
service_url):
84+
self._user = user
85+
self._apikey = apikey
86+
self._tenant = tenant
87+
self._token = token
88+
self._auth_url = auth_url
89+
self._service_name = service_name
90+
self._service_url = service_url
91+
92+
93+
class Auth(object):
94+
"""Authenticate with your username and api key"""
95+
96+
def __init__(self):
97+
pass
98+
99+
def login(self, user, apikey, tenant="dbaas", auth_url="http://localhost:5000/v1.1",
100+
service_name="reddwarf", service_url=None):
101+
"""Login to retrieve an auth token to use for other api calls"""
102+
try:
103+
dbaas = Dbaas(user, apikey, tenant, auth_url=auth_url,
104+
service_name=service_name, service_url=service_url)
105+
dbaas.authenticate()
106+
apitoken = APIToken(user, apikey, tenant, dbaas.client.auth_token,
107+
auth_url, service_name, service_url)
108+
109+
with open(APITOKEN, 'wb') as token:
110+
pickle.dump(apitoken, token, protocol=2)
111+
print apitoken._token
112+
except:
113+
print sys.exc_info()[1]

reddwarfclient/config.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Copyright (c) 2011 OpenStack, LLC.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
from novaclient import base
17+
18+
19+
class Config(base.Resource):
20+
"""
21+
A configuration entry
22+
"""
23+
def __repr__(self):
24+
return "<Config: %s>" % self.key
25+
26+
27+
class Configs(base.ManagerWithFind):
28+
"""
29+
Manage :class:`Configs` resources.
30+
"""
31+
resource_class = Config
32+
33+
def create(self, configs):
34+
"""
35+
Create the configuration entries
36+
"""
37+
body = {"configs": configs}
38+
url = "/mgmt/configs"
39+
resp, body = self.api.client.post(url, body=body)
40+
41+
def delete(self, config):
42+
"""
43+
Delete an existing configuration
44+
"""
45+
url = "/mgmt/configs/%s"% config
46+
self._delete(url)
47+
48+
def list(self):
49+
"""
50+
Get a list of all configuration entries
51+
"""
52+
resp, body = self.api.client.get("/mgmt/configs")
53+
if not body:
54+
raise Exception("Call to /mgmt/configs did not return a body.")
55+
return [self.resource_class(self, res) for res in body['configs']]
56+
57+
def get(self, config):
58+
"""
59+
Get the specified configuration entry
60+
"""
61+
url = "/mgmt/configs/%s" % config
62+
resp, body = self.api.client.get(url)
63+
if not body:
64+
raise Exception("Call to %s did not return a body." % url)
65+
return self.resource_class(self, body['config'])
66+
67+
def update(self, config):
68+
"""
69+
Update the configuration entries
70+
"""
71+
body = {"config": config}
72+
url = "/mgmt/configs/%s" % config['key']
73+
resp, body = self.api.client.put(url, body=body)

0 commit comments

Comments
 (0)