Coverage for osmclient/sol005/vim.py: 12%

157 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2024-06-22 09:01 +0000

1# Copyright 2018 Telefonica 

2# 

3# All Rights Reserved. 

4# 

5# Licensed under the Apache License, Version 2.0 (the "License"); you may 

6# not use this file except in compliance with the License. You may obtain 

7# a copy of the License at 

8# 

9# http://www.apache.org/licenses/LICENSE-2.0 

10# 

11# Unless required by applicable law or agreed to in writing, software 

12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 

13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

14# License for the specific language governing permissions and limitations 

15# under the License. 

16 

17""" 

18OSM vim API handling 

19""" 

20 

21from osmclient.common import utils 

22from osmclient.common import wait as WaitForStatus 

23from osmclient.common.exceptions import ClientException 

24from osmclient.common.exceptions import NotFound 

25import yaml 

26import json 

27import logging 

28 

29 

30class Vim(object): 

31 def __init__(self, http=None, client=None): 

32 self._http = http 

33 self._client = client 

34 self._logger = logging.getLogger("osmclient") 

35 self._apiName = "/admin" 

36 self._apiVersion = "/v1" 

37 self._apiResource = "/vim_accounts" 

38 self._apiBase = "{}{}{}".format( 

39 self._apiName, self._apiVersion, self._apiResource 

40 ) 

41 

42 # VIM '--wait' option 

43 def _wait(self, id, wait_time, deleteFlag=False): 

44 self._logger.debug("") 

45 self._client.get_token() 

46 # Endpoint to get operation status 

47 apiUrlStatus = "{}{}{}".format(self._apiName, self._apiVersion, "/vim_accounts") 

48 # Wait for status for VIM instance creation/deletion 

49 if isinstance(wait_time, bool): 

50 wait_time = WaitForStatus.TIMEOUT_VIM_OPERATION 

51 WaitForStatus.wait_for_status( 

52 "VIM", 

53 str(id), 

54 wait_time, 

55 apiUrlStatus, 

56 self._http.get2_cmd, 

57 deleteFlag=deleteFlag, 

58 ) 

59 

60 def _get_id_for_wait(self, name): 

61 """Returns id of name, or the id itself if given as argument""" 

62 self._logger.debug("") 

63 self._client.get_token() 

64 for vim in self.list(): 

65 if name == vim["uuid"] or name == vim["name"]: 

66 return vim["uuid"] 

67 return "" 

68 

69 def create( 

70 self, 

71 name, 

72 vim_access, 

73 config={}, 

74 sdn_controller=None, 

75 sdn_port_mapping=None, 

76 wait=False, 

77 ): 

78 vca_id = None 

79 

80 def get_vca_id(vca): 

81 vca = self._client.vca.get(vca) 

82 if vca is None: 

83 raise NotFound("cannot find vca '{}'".format(vca)) 

84 return vca["_id"] 

85 

86 self._logger.debug("") 

87 self._client.get_token() 

88 if "vca" in vim_access: 

89 vca_id = get_vca_id(vim_access["vca"]) 

90 if "vim-type" not in vim_access: 

91 # 'openstack' not in vim_access['vim-type']): 

92 raise Exception("vim type not provided") 

93 vim_account = {} 

94 vim_account["name"] = name 

95 vim_account = self.update_vim_account_dict(vim_account, vim_access) 

96 if vca_id: 

97 vim_account["vca"] = vca_id 

98 vim_config = config 

99 if sdn_controller: 

100 sdnc = self._client.sdnc.get(sdn_controller) 

101 vim_config["sdn-controller"] = sdnc["_id"] 

102 if sdn_port_mapping: 

103 with open(sdn_port_mapping, "r") as f: 

104 vim_config["sdn-port-mapping"] = yaml.safe_load(f.read()) 

105 if vim_config: 

106 vim_account["config"] = vim_config 

107 # vim_account['config'] = json.dumps(vim_config) 

108 

109 http_code, resp = self._http.post_cmd( 

110 endpoint=self._apiBase, postfields_dict=vim_account 

111 ) 

112 # print('HTTP CODE: {}'.format(http_code)) 

113 # print('RESP: {}'.format(resp)) 

114 # if http_code in (200, 201, 202, 204): 

115 if resp: 

116 resp = json.loads(resp) 

117 if not resp or "id" not in resp: 

118 raise ClientException("unexpected response from server - {}".format(resp)) 

119 if wait: 

120 # Wait for status for VIM instance creation 

121 self._wait(resp.get("id"), wait) 

122 print(resp["id"]) 

123 # else: 

124 # msg = "" 

125 # if resp: 

126 # try: 

127 # msg = json.loads(resp) 

128 # except ValueError: 

129 # msg = resp 

130 # raise ClientException("failed to create vim {} - {}".format(name, msg)) 

131 

132 def update( 

133 self, 

134 vim_name, 

135 vim_account, 

136 config, 

137 sdn_controller, 

138 sdn_port_mapping, 

139 wait=False, 

140 ): 

141 self._logger.debug("") 

142 self._client.get_token() 

143 vim = self.get(vim_name) 

144 vim_id_for_wait = self._get_id_for_wait(vim_name) 

145 vim_config = {} 

146 if config is not None: 

147 if not config and (sdn_controller or sdn_port_mapping): 

148 # If config is empty (clearing config) 

149 raise ClientException( 

150 "clearing config is incompatible with updating SDN info" 

151 ) 

152 vim_config = config 

153 if sdn_controller == "": 

154 vim_config["sdn-controller"] = None 

155 vim_config["sdn-port-mapping"] = None 

156 else: 

157 if sdn_controller: 

158 sdnc = self._client.sdnc.get(sdn_controller) 

159 vim_config["sdn-controller"] = sdnc["_id"] 

160 if sdn_port_mapping: 

161 with open(sdn_port_mapping, "r") as f: 

162 vim_config["sdn-port-mapping"] = yaml.safe_load(f.read()) 

163 vim_account["config"] = vim_config 

164 # vim_account['config'] = json.dumps(vim_config) 

165 http_code, resp = self._http.patch_cmd( 

166 endpoint="{}/{}".format(self._apiBase, vim["_id"]), 

167 postfields_dict=vim_account, 

168 ) 

169 # print('HTTP CODE: {}'.format(http_code)) 

170 # print('RESP: {}'.format(resp)) 

171 # if http_code in (200, 201, 202, 204): 

172 if wait: 

173 # In this case, 'resp' always returns None, so 'resp['id']' cannot be used. 

174 # Use the previously obtained id instead. 

175 wait_id = vim_id_for_wait 

176 # Wait for status for VI instance update 

177 self._wait(wait_id, wait) 

178 # else: 

179 # pass 

180 # else: 

181 # msg = "" 

182 # if resp: 

183 # try: 

184 # msg = json.loads(resp) 

185 # except ValueError: 

186 # msg = resp 

187 # raise ClientException("failed to update vim {} - {}".format(vim_name, msg)) 

188 

189 def update_vim_account_dict(self, vim_account, vim_access): 

190 self._logger.debug("") 

191 vim_account["vim_type"] = vim_access["vim-type"] 

192 vim_account["description"] = vim_access["description"] 

193 vim_account["vim_url"] = vim_access["vim-url"] or "null" 

194 vim_account["vim_user"] = vim_access["vim-username"] or "null" 

195 vim_account["vim_password"] = vim_access["vim-password"] or "null" 

196 vim_account["vim_tenant_name"] = vim_access["vim-tenant-name"] or "null" 

197 if "prometheus-config" in vim_access: 

198 vim_account["prometheus-config"] = vim_access["prometheus-config"] 

199 return vim_account 

200 

201 def get_id(self, name): 

202 """Returns a VIM id from a VIM name""" 

203 self._logger.debug("") 

204 for vim in self.list(): 

205 if name == vim["name"]: 

206 return vim["uuid"] 

207 raise NotFound("vim {} not found".format(name)) 

208 

209 def delete(self, vim_name, force=False, wait=False): 

210 self._logger.debug("") 

211 self._client.get_token() 

212 vim_id = vim_name 

213 if not utils.validate_uuid4(vim_name): 

214 vim_id = self.get_id(vim_name) 

215 querystring = "" 

216 if force: 

217 querystring = "?FORCE=True" 

218 http_code, resp = self._http.delete_cmd( 

219 "{}/{}{}".format(self._apiBase, vim_id, querystring) 

220 ) 

221 # print('HTTP CODE: {}'.format(http_code)) 

222 # print('RESP: {}'.format(resp)) 

223 if http_code == 202: 

224 if wait: 

225 # When deleting an account, 'resp' may be None. 

226 # In such a case, the 'id' from 'resp' cannot be used, so use 'vim_id' instead 

227 wait_id = vim_id 

228 if resp: 

229 resp = json.loads(resp) 

230 wait_id = resp.get("id") 

231 # Wait for status for VIM account deletion 

232 self._wait(wait_id, wait, deleteFlag=True) 

233 else: 

234 print("Deletion in progress") 

235 elif http_code == 204: 

236 print("Deleted") 

237 else: 

238 msg = resp or "" 

239 # if resp: 

240 # try: 

241 # msg = json.loads(resp) 

242 # except ValueError: 

243 # msg = resp 

244 raise ClientException("failed to delete vim {} - {}".format(vim_name, msg)) 

245 

246 def list(self, filter=None): 

247 """Returns a list of VIM accounts""" 

248 self._logger.debug("") 

249 self._client.get_token() 

250 filter_string = "" 

251 if filter: 

252 filter_string = "?{}".format(filter) 

253 _, resp = self._http.get2_cmd("{}{}".format(self._apiBase, filter_string)) 

254 if not resp: 

255 return list() 

256 vim_accounts = json.loads(resp) 

257 for datacenter in vim_accounts: 

258 datacenter["uuid"] = datacenter.get("_id") # backward compatibility? 

259 return vim_accounts 

260 

261 def get(self, name): 

262 """Returns a VIM account based on name or id""" 

263 self._logger.debug("") 

264 self._client.get_token() 

265 vim_id = name 

266 if not utils.validate_uuid4(name): 

267 vim_id = self.get_id(name) 

268 try: 

269 _, resp = self._http.get2_cmd("{}/{}".format(self._apiBase, vim_id)) 

270 if resp: 

271 resp = json.loads(resp) 

272 if not resp or "_id" not in resp: 

273 raise ClientException("failed to get vim info: {}".format(resp)) 

274 return resp 

275 except NotFound: 

276 raise NotFound("vim '{}' not found".format(name))