2 # Copyright (c) 2019 Erik Schilling
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
23 from pipes
import quote
24 from tempfile
import NamedTemporaryFile
29 from emuvim
.api
.osm
.osm_component_base
import OSMComponentBase
30 from emuvim
.api
.util
.docker_utils
import wrap_debian_like
, DOCKER_HOST_IP
31 from emuvim
.api
.util
.path_utils
import get_absolute_path
32 from emuvim
.api
.util
.process_utils
import wait_until
33 from mininet
.log
import debug
35 # disables warnings about verify=False for TLS
36 # since NBI runs with self-signed certificates this otherwise spams the log
37 urllib3
.disable_warnings()
39 LOG
= logging
.getLogger(__name__
)
42 class NBI(OSMComponentBase
):
44 def __init__(self
, net
, ip
, mongo_ip
, kafka_ip
, version
='latest', name_prefix
=''):
45 OSMComponentBase
.__init
__(self
)
46 self
.instance
= net
.addDocker(
47 '{}nbi'.format(name_prefix
), ip
=ip
, dimage
=wrap_debian_like('opensourcemano/nbi:%s' % version
),
48 volumes
=['osm_packages:/app/storage'],
49 environment
={'OSMNBI_DATABASE_URI': 'mongodb://%s:27017' % mongo_ip
,
50 'OSMNBI_MESSAGE_HOST': kafka_ip
})
51 self
._ip
= self
.instance
.dcinfo
['NetworkSettings']['IPAddress']
54 OSMComponentBase
.start(self
)
55 wait_until('nc -z %s 9999' % self
._ip
)
57 def _osm(self
, command
):
58 prefixed_command
= 'osm %s' % command
59 debug('executing command: %s\n' % prefixed_command
)
60 output
= subprocess
.check_output(prefixed_command
, env
={'OSM_HOSTNAME': self
._ip
}, shell
=True)
61 debug('output: \n%s\n' % output
)
65 def _create_archive(folder
, tmp_file
):
66 folder
= get_absolute_path(folder
)
67 parent_folder
= os
.path
.dirname(folder
)
68 basename
= os
.path
.basename(folder
)
69 subprocess
.call('tar czf %s %s' % (quote(tmp_file
.name
), quote(basename
)), cwd
=parent_folder
, shell
=True)
71 def onboard_vnfd(self
, folder
):
73 with
NamedTemporaryFile() as tmp_archive
:
74 self
._create
_archive
(folder
, tmp_archive
)
75 return self
._osm
('vnfd-create %s' % quote(tmp_archive
.name
)).strip()
76 except subprocess
.CalledProcessError
as e
:
77 raise RuntimeError('creating vnfd failed: %s' % e
.output
)
79 def onboard_nsd(self
, folder
):
81 with
NamedTemporaryFile() as tmp_archive
:
82 self
._create
_archive
(folder
, tmp_archive
)
83 return self
._osm
('nsd-create %s' % quote(tmp_archive
.name
)).strip()
84 except subprocess
.CalledProcessError
as e
:
85 raise RuntimeError('creating nsd failed: %s' % e
.output
)
87 def _get_api_token(self
):
88 token_request
= requests
.post('https://%s:9999/osm/admin/v1/tokens' % self
._ip
,
89 data
={'username': 'admin', 'password': 'admin'}, verify
=False)
90 if not token_request
.ok
:
91 raise RuntimeError('getting token failed with: %s' % token_request
.text
)
92 token
= yaml
.safe_load(token_request
.text
)
95 def _api_request_args(self
):
96 return {'headers': {'Authorization': 'Bearer %s' % self
._get
_api
_token
()}, 'verify': False}
98 def _api_post_request(self
, endpoint
, data
):
99 r
= requests
.post('https://%s:9999/%s' % (self
._ip
, endpoint
),
101 **self
._api
_request
_args
())
103 raise RuntimeError('POST request failed with: %s' % r
.text
)
104 result
= yaml
.safe_load(r
.text
)
107 def _api_get_request(self
, endpoint
):
108 r
= requests
.get('https://%s:9999/%s' % (self
._ip
, endpoint
),
109 **self
._api
_request
_args
())
111 raise RuntimeError('GET request failed with: %s' % r
.text
)
112 result
= yaml
.safe_load(r
.text
)
115 def _api_delete_request(self
, endpoint
):
116 r
= requests
.delete('https://%s:9999/%s' % (self
._ip
, endpoint
),
117 **self
._api
_request
_args
())
119 raise RuntimeError('DELETE request failed with: %s' % r
.text
)
121 def register_emulated_api(self
, name
, api
):
122 output
= self
._osm
('vim-create --name %s '
124 '--password password '
125 '--auth_url http://%s:%d/v2.0 '
126 '--tenant tenantName '
127 '--account_type openstack' % (
129 quote(DOCKER_HOST_IP
),
132 vim_id
= output
.strip()
133 while self
._api
_get
_request
('osm/admin/v1/vim_accounts/%s' % vim_id
)['_admin']['detailed-status'] != 'Done':
137 def ns_create(self
, ns_name
, nsd_id
, vim_id
):
138 result
= self
._api
_post
_request
('osm/nslcm/v1/ns_instances_content', {
141 # dummy text since this cannot be empty
142 'nsDescription': 'created by vim-emu',
143 'vimAccountId': vim_id
,
147 def ns_get(self
, ns_id
):
148 return self
._api
_get
_request
('osm/nslcm/v1/ns_instances_content/%s' % ns_id
)
150 def ns_action(self
, ns_id
, vnf_member_index
, action
, args
=None):
153 result
= self
._api
_post
_request
('osm/nslcm/v1/ns_instances/%s/action' % ns_id
, {
154 'vnf_member_index': str(vnf_member_index
),
156 'primitive_params': args
,
160 def ns_delete(self
, ns_id
):
161 self
._api
_delete
_request
('osm/nslcm/v1/ns_instances_content/%s' % ns_id
)
164 return self
._api
_get
_request
('osm/nslcm/v1/ns_instances_content')
167 def _count_all_in_operational_status(ns_list
, status
):
168 return len(filter(lambda x
: x
['operational-status'] == status
, ns_list
))
170 def ns_wait_until_all_in_status(self
, *statuses
):
171 """Waits for all NSs to be in one of the specified stati.
172 Returns a tuple with the counts of the NSs in the invididual
173 stati in the same order as the specified stati"""
175 LOG
.debug('Waiting for all NS to be in status {}'.format(statuses
))
177 ns_list
= self
.ns_list()
179 for status
in statuses
:
180 state
+= (self
._count
_all
_in
_operational
_status
(ns_list
, status
),)
181 number_correct
= sum(state
)
182 missing
= len(ns_list
) - number_correct
185 logging
.debug('waiting for the status of %s services to change to %s' % (missing
, statuses
))
188 logging
.debug('all %d NSs in status %s' % (len(ns_list
), statuses
))