envvar='OSM_HOSTNAME',
help='hostname of server. ' +
'Also can set OSM_HOSTNAME in environment')
+@click.option('--sol005/--no-sol005',
+ default=True,
+ envvar='OSM_SOL005',
+ help='Use ETSI NFV SOL005 API (default) or the previous SO API. ' +
+ 'Also can set OSM_SOL005 in environment')
+@click.option('--user',
+ default=None,
+ envvar='OSM_USER',
+ help='user (only from Release FOUR, defaults to admin). ' +
+ 'Also can set OSM_USER in environment')
+@click.option('--password',
+ default=None,
+ envvar='OSM_PASSWORD',
+ help='password (only from Release FOUR, defaults to admin). ' +
+ 'Also can set OSM_PASSWORD in environment')
+@click.option('--project',
+ default=None,
+ envvar='OSM_PROJECT',
+ help='project (only from Release FOUR, defaults to admin). ' +
+ 'Also can set OSM_PROJECT in environment')
@click.option('--so-port',
default=None,
envvar='OSM_SO_PORT',
help='hostname of RO server. ' +
'Also can set OSM_RO_HOSTNAME in environment')
@click.option('--ro-port',
- default=9090,
+ default=None,
envvar='OSM_RO_PORT',
help='hostname of RO server. ' +
'Also can set OSM_RO_PORT in environment')
-@click.option('--sol005/--no-sol005',
- default=True,
- envvar='OSM_SOL005',
- help='Use ETSI NFV SOL005 API (default) or the previous SO API')
@click.pass_context
-def cli(ctx, hostname, so_port, so_project, ro_hostname, ro_port, sol005):
+def cli(ctx, hostname, sol005, user, password, project, so_port, so_project, ro_hostname, ro_port):
if hostname is None:
print((
"either hostname option or OSM_HOSTNAME " +
kwargs['ro_host']=ro_hostname
if ro_port is not None:
kwargs['ro_port']=ro_port
+ if user is not None:
+ kwargs['user']=user
+ if password is not None:
+ kwargs['password']=password
+ if project is not None:
+ kwargs['project']=project
ctx.obj = client.Client(host=hostname, sol005=sol005, **kwargs)
print(table)
+####################
+# Project mgmt operations
+####################
+
+@cli.command(name='project-create')
+@click.argument('name')
+#@click.option('--description',
+# default='no description',
+# help='human readable description')
+@click.pass_context
+def project_create(ctx, name):
+ '''Creates a new project
+
+ NAME: name of the project
+ '''
+ project = {}
+ project['name'] = name
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ ctx.obj.project.create(name, project)
+ except ClientException as inst:
+ print(inst.message)
+
+
+@cli.command(name='project-delete')
+@click.argument('name')
+#@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
+@click.pass_context
+def project_delete(ctx, name):
+ '''deletes a project
+
+ NAME: name or ID of the project to be deleted
+ '''
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ ctx.obj.project.delete(name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
+
+@cli.command(name='project-list')
+@click.option('--filter', default=None,
+ help='restricts the list to the projects matching the filter')
+@click.pass_context
+def project_list(ctx, filter):
+ '''list all projects'''
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ resp = ctx.obj.project.list(filter)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+ table = PrettyTable(['name', 'id'])
+ for proj in resp:
+ table.add_row([proj['name'], proj['_id']])
+ table.align = 'l'
+ print(table)
+
+
+@cli.command(name='project-show')
+@click.argument('name')
+@click.pass_context
+def project_show(ctx, name):
+ '''shows the details of a project
+
+ NAME: name or ID of the project
+ '''
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ resp = ctx.obj.project.get(name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
+ table = PrettyTable(['key', 'attribute'])
+ for k, v in resp.items():
+ table.add_row([k, json.dumps(v, indent=2)])
+ table.align = 'l'
+ print(table)
+
+
+####################
+# User mgmt operations
+####################
+
+@cli.command(name='user-create')
+@click.argument('username')
+@click.option('--password',
+ prompt=True,
+ hide_input=True,
+ confirmation_prompt=True,
+ help='user password')
+@click.option('--projects',
+ default=None,
+ help='list of project ids that the user belongs to')
+#@click.option('--description',
+# default='no description',
+# help='human readable description')
+@click.pass_context
+def user_create(ctx, username, password, projects):
+ '''Creates a new user
+
+ USERNAME: name of the user
+ '''
+ user = {}
+ user['username'] = username
+ user['password'] = password
+ user['projects'] = projects
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ ctx.obj.user.create(username, user)
+ except ClientException as inst:
+ print(inst.message)
+
+
+@cli.command(name='user-delete')
+@click.argument('name')
+#@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
+@click.pass_context
+def user_delete(ctx, name):
+ '''deletes a user
+
+ NAME: name or ID of the user to be deleted
+ '''
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ ctx.obj.user.delete(name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
+
+@cli.command(name='user-list')
+@click.option('--filter', default=None,
+ help='restricts the list to the users matching the filter')
+@click.pass_context
+def user_list(ctx, filter):
+ '''list all users'''
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ resp = ctx.obj.user.list(filter)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+ table = PrettyTable(['name', 'id'])
+ for user in resp:
+ table.add_row([user['name'], user['_id']])
+ table.align = 'l'
+ print(table)
+
+
+@cli.command(name='user-show')
+@click.argument('name')
+@click.pass_context
+def user_show(ctx, name):
+ '''shows the details of a user
+
+ NAME: name or ID of the user
+ '''
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ resp = ctx.obj.user.get(name)
+ if 'password' in resp:
+ resp['password']='********'
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
+ table = PrettyTable(['key', 'attribute'])
+ for k, v in resp.items():
+ table.add_row([k, json.dumps(v, indent=2)])
+ table.align = 'l'
+ print(table)
+
+
####################
# Fault Management operations
####################
from osmclient.sol005 import package
from osmclient.sol005 import http
from osmclient.sol005 import sdncontroller
+from osmclient.sol005 import project as projectmodule
+from osmclient.sol005 import user as usermodule
from osmclient.common.exceptions import ClientException
import json
self,
host=None,
so_port=9999,
- so_project='admin',
- ro_host=None,
- ro_port=9090,
+ user='admin',
+ password='admin',
+ project='admin',
**kwargs):
- self._user = 'admin'
- self._password = 'admin'
- #self._project = so_project
- self._project = 'admin'
+ self._user = user
+ self._password = password
+ self._project = project
self._auth_endpoint = '/admin/v1/tokens'
self._headers = {}
self._host = host
self._so_port = so_port
- if ro_host is None:
- ro_host = host
- ro_http_client = http.Http('http://{}:{}/openmano'.format(ro_host, ro_port))
- ro_http_client.set_http_header(
- ['Accept: application/json',
- 'Content-Type: application/json'])
-
self._http_client = http.Http(
'https://{}:{}/osm'.format(self._host,self._so_port))
self._headers['Accept'] = 'application/json'
self.vim = vim.Vim(self._http_client, client=self)
self.sdnc = sdncontroller.SdnController(self._http_client, client=self)
self.vnf = vnf.Vnf(self._http_client, client=self)
+ self.project = projectmodule.Project(self._http_client, client=self)
+ self.user = usermodule.User(self._http_client, client=self)
'''
self.vca = vca.Vca(http_client, client=self, **kwargs)
self.utils = utils.Utils(http_client, **kwargs)
def get_token(self):
postfields_dict = {'username': self._user,
'password': self._password,
- 'project-id': self._project}
+ 'project_id': self._project}
http_code, resp = self._http_client.post_cmd(endpoint=self._auth_endpoint,
postfields_dict=postfields_dict)
if http_code not in (200, 201, 202, 204):
--- /dev/null
+#
+# Copyright 2018 Telefonica Investigacion y Desarrollo S.A.U.
+#
+# 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.
+
+"""
+OSM project mgmt API
+"""
+
+from osmclient.common import utils
+from osmclient.common.exceptions import ClientException
+from osmclient.common.exceptions import NotFound
+import json
+
+
+class Project(object):
+ def __init__(self, http=None, client=None):
+ self._http = http
+ self._client = client
+ self._apiName = '/admin'
+ self._apiVersion = '/v1'
+ self._apiResource = '/projects'
+ self._apiBase = '{}{}{}'.format(self._apiName,
+ self._apiVersion, self._apiResource)
+
+ def create(self, name, project):
+ """Creates a new OSM project
+ """
+ http_code, resp = self._http.post_cmd(endpoint=self._apiBase,
+ postfields_dict=project)
+ #print('HTTP CODE: {}'.format(http_code))
+ #print('RESP: {}'.format(resp))
+ if http_code in (200, 201, 202, 204):
+ if resp:
+ resp = json.loads(resp)
+ if not resp or 'id' not in resp:
+ raise ClientException('unexpected response from server - {}'.format(
+ resp))
+ print(resp['id'])
+ else:
+ msg = ""
+ if resp:
+ try:
+ msg = json.loads(resp)
+ except ValueError:
+ msg = resp
+ raise ClientException("failed to create project {} - {}".format(name, msg))
+
+ def update(self, name, project):
+ """Updates an OSM project identified by name
+ """
+ proj = self.get(name)
+ http_code, resp = self._http.put_cmd(endpoint='{}/{}'.format(self._apiBase,proj['_id']),
+ postfields_dict=project)
+ #print('HTTP CODE: {}'.format(http_code))
+ #print('RESP: {}'.format(resp))
+ if http_code in (200, 201, 202, 204):
+ if resp:
+ resp = json.loads(resp)
+ if not resp or 'id' not in resp:
+ raise ClientException('unexpected response from server - {}'.format(
+ resp))
+ print(resp['id'])
+ else:
+ msg = ""
+ if resp:
+ try:
+ msg = json.loads(resp)
+ except ValueError:
+ msg = resp
+ raise ClientException("failed to update project {} - {}".format(name, msg))
+
+ def delete(self, name, force=False):
+ """Deletes an OSM project identified by name
+ """
+ project = self.get(name)
+ querystring = ''
+ if force:
+ querystring = '?FORCE=True'
+ http_code, resp = self._http.delete_cmd('{}/{}{}'.format(self._apiBase,
+ project['_id'], querystring))
+ #print('HTTP CODE: {}'.format(http_code))
+ #print('RESP: {}'.format(resp))
+ if http_code == 202:
+ print('Deletion in progress')
+ elif http_code == 204:
+ print('Deleted')
+ elif resp and 'result' in resp:
+ print('Deleted')
+ else:
+ msg = ""
+ if resp:
+ try:
+ msg = json.loads(resp)
+ except ValueError:
+ msg = resp
+ raise ClientException("failed to delete project {} - {}".format(name, msg))
+
+ def list(self, filter=None):
+ """Returns the list of OSM projects
+ """
+ filter_string = ''
+ if filter:
+ filter_string = '?{}'.format(filter)
+ resp = self._http.get_cmd('{}{}'.format(self._apiBase,filter_string))
+ #print('RESP: {}'.format(resp))
+ if resp:
+ return resp
+ return list()
+
+ def get(self, name):
+ """Returns a specific OSM project based on name or id
+ """
+ if utils.validate_uuid4(name):
+ for proj in self.list():
+ if name == proj['_id']:
+ return proj
+ else:
+ for proj in self.list():
+ if name == proj['name']:
+ return proj
+ raise NotFound("Project {} not found".format(name))
+
+
self._apiResource = '/sdns'
self._apiBase = '{}{}{}'.format(self._apiName,
self._apiVersion, self._apiResource)
+
def create(self, name, sdn_controller):
http_code, resp = self._http.post_cmd(endpoint=self._apiBase,
postfields_dict=sdn_controller)
--- /dev/null
+#
+# Copyright 2018 Telefonica Investigacion y Desarrollo S.A.U.
+#
+# 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.
+
+"""
+OSM user mgmt API
+"""
+
+from osmclient.common import utils
+from osmclient.common.exceptions import ClientException
+from osmclient.common.exceptions import NotFound
+import json
+import yaml
+
+
+class User(object):
+ def __init__(self, http=None, client=None):
+ self._http = http
+ self._client = client
+ self._apiName = '/admin'
+ self._apiVersion = '/v1'
+ self._apiResource = '/users'
+ self._apiBase = '{}{}{}'.format(self._apiName,
+ self._apiVersion, self._apiResource)
+
+ def create(self, name, user):
+ """Creates a new OSM user
+ """
+ if 'projects' in user and user['projects'] is not None:
+ user['projects'] = yaml.safe_load(user['projects'])
+ http_code, resp = self._http.post_cmd(endpoint=self._apiBase,
+ postfields_dict=user)
+ #print('HTTP CODE: {}'.format(http_code))
+ #print('RESP: {}'.format(resp))
+ if http_code in (200, 201, 202, 204):
+ if resp:
+ resp = json.loads(resp)
+ if not resp or 'id' not in resp:
+ raise ClientException('unexpected response from server - {}'.format(
+ resp))
+ print(resp['id'])
+ else:
+ msg = ""
+ if resp:
+ try:
+ msg = json.loads(resp)
+ except ValueError:
+ msg = resp
+ raise ClientException("failed to create user {} - {}".format(name, msg))
+
+ def update(self, name, user):
+ """Updates an existing OSM user identified by name
+ """
+ myuser = self.get(name)
+ http_code, resp = self._http.put_cmd(endpoint='{}/{}'.format(self._apiBase,myuser['_id']),
+ postfields_dict=user)
+ #print('HTTP CODE: {}'.format(http_code))
+ #print('RESP: {}'.format(resp))
+ if http_code in (200, 201, 202, 204):
+ if resp:
+ resp = json.loads(resp)
+ if not resp or 'id' not in resp:
+ raise ClientException('unexpected response from server - {}'.format(
+ resp))
+ print(resp['id'])
+ else:
+ msg = ""
+ if resp:
+ try:
+ msg = json.loads(resp)
+ except ValueError:
+ msg = resp
+ raise ClientException("failed to update user {} - {}".format(name, msg))
+
+ def delete(self, name, force=False):
+ """Deletes an existing OSM user identified by name
+ """
+ user = self.get(name)
+ querystring = ''
+ if force:
+ querystring = '?FORCE=True'
+ http_code, resp = self._http.delete_cmd('{}/{}{}'.format(self._apiBase,
+ user['_id'], querystring))
+ #print('HTTP CODE: {}'.format(http_code))
+ #print('RESP: {}'.format(resp))
+ if http_code == 202:
+ print('Deletion in progress')
+ elif http_code == 204:
+ print('Deleted')
+ elif resp and 'result' in resp:
+ print('Deleted')
+ else:
+ msg = ""
+ if resp:
+ try:
+ msg = json.loads(resp)
+ except ValueError:
+ msg = resp
+ raise ClientException("failed to delete user {} - {}".format(name, msg))
+
+ def list(self, filter=None):
+ """Returns the list of OSM users
+ """
+ filter_string = ''
+ if filter:
+ filter_string = '?{}'.format(filter)
+ resp = self._http.get_cmd('{}{}'.format(self._apiBase,filter_string))
+ #print('RESP: {}'.format(resp))
+ if resp:
+ return resp
+ return list()
+
+ def get(self, name):
+ """Returns an OSM user based on name or id
+ """
+ if utils.validate_uuid4(name):
+ for user in self.list():
+ if name == user['_id']:
+ return user
+ else:
+ for user in self.list():
+ if name == user['name']:
+ return user
+ raise NotFound("User {} not found".format(name))
+
+