Coverage for manila/share/drivers/dell_emc/common/enas/connector.py: 97%

99 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright (c) 2016 Dell Inc. or its subsidiaries. 

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 

16from http import cookiejar as http_cookiejar 

17import shlex 

18from urllib import error as url_error 

19from urllib import request as url_request 

20 

21from oslo_concurrency import processutils 

22from oslo_log import log 

23from oslo_utils import excutils 

24 

25from manila import exception 

26from manila.i18n import _ 

27from manila.share.drivers.dell_emc.common.enas import constants 

28from manila.share.drivers.dell_emc.common.enas import utils as enas_utils 

29from manila import ssh_utils 

30 

31LOG = log.getLogger(__name__) 

32 

33 

34class XMLAPIConnector(object): 

35 def __init__(self, configuration, debug=True): 

36 super(XMLAPIConnector, self).__init__() 

37 self.storage_ip = enas_utils.convert_ipv6_format_if_needed( 

38 configuration.emc_nas_server) 

39 self.username = configuration.emc_nas_login 

40 self.password = configuration.emc_nas_password 

41 self.debug = debug 

42 self.auth_url = 'https://' + self.storage_ip + '/Login' 

43 self._url = 'https://{}/servlets/CelerraManagementServices'.format( 

44 self.storage_ip) 

45 context = enas_utils.create_ssl_context(configuration) 

46 if context: 46 ↛ 49line 46 didn't jump to line 49 because the condition on line 46 was always true

47 https_handler = url_request.HTTPSHandler(context=context) 

48 else: 

49 https_handler = url_request.HTTPSHandler() 

50 cookie_handler = url_request.HTTPCookieProcessor( 

51 http_cookiejar.CookieJar()) 

52 self.url_opener = url_request.build_opener(https_handler, 

53 cookie_handler) 

54 self._do_setup() 

55 

56 def _do_setup(self): 

57 credential = ('user=' + self.username 

58 + '&password=' + self.password 

59 + '&Login=Login') 

60 req = url_request.Request(self.auth_url, credential.encode(), 

61 constants.CONTENT_TYPE_URLENCODE) 

62 resp = self.url_opener.open(req) 

63 resp_body = resp.read() 

64 self._http_log_resp(resp, resp_body) 

65 

66 def _http_log_req(self, req): 

67 if not self.debug: 

68 return 

69 

70 string_parts = ['curl -i'] 

71 string_parts.append(' -X %s' % req.get_method()) 

72 

73 for k in req.headers: 

74 header = ' -H "%s: %s"' % (k, req.headers[k]) 

75 string_parts.append(header) 

76 

77 if req.data: 77 ↛ 79line 77 didn't jump to line 79 because the condition on line 77 was always true

78 string_parts.append(" -d '%s'" % req.data) 

79 string_parts.append(' ' + req.get_full_url()) 

80 LOG.debug("\nREQ: %s.\n", "".join(string_parts)) 

81 

82 def _http_log_resp(self, resp, body): 

83 if not self.debug: 

84 return 

85 

86 headers = str(resp.headers).replace('\n', '\\n') 

87 

88 LOG.debug( 

89 'RESP: [%(code)s] %(resp_hdrs)s\n' 

90 'RESP BODY: %(resp_b)s.\n', 

91 { 

92 'code': resp.getcode(), 

93 'resp_hdrs': headers, 

94 'resp_b': body, 

95 } 

96 ) 

97 

98 def _request(self, req_body=None, method=None, 

99 header=constants.CONTENT_TYPE_URLENCODE): 

100 req = url_request.Request(self._url, req_body.encode(), header) 

101 if method not in (None, 'GET', 'POST'): 

102 req.get_method = lambda: method 

103 self._http_log_req(req) 

104 try: 

105 resp = self.url_opener.open(req) 

106 resp_body = resp.read() 

107 self._http_log_resp(resp, resp_body) 

108 except url_error.HTTPError as http_err: 

109 if '403' == str(http_err.code): 

110 raise exception.NotAuthorized() 

111 else: 

112 err = {'errorCode': -1, 

113 'httpStatusCode': http_err.code, 

114 'messages': str(http_err), 

115 'request': req_body} 

116 msg = (_("The request is invalid. Reason: %(reason)s") % 

117 {'reason': err}) 

118 raise exception.ManilaException(message=msg) 

119 

120 return resp_body 

121 

122 def request(self, req_body=None, method=None, 

123 header=constants.CONTENT_TYPE_URLENCODE): 

124 try: 

125 resp_body = self._request(req_body, method, header) 

126 except exception.NotAuthorized: 

127 LOG.debug("Login again because client certification " 

128 "may be expired.") 

129 self._do_setup() 

130 resp_body = self._request(req_body, method, header) 

131 

132 return resp_body 

133 

134 

135class SSHConnector(object): 

136 def __init__(self, configuration, debug=True): 

137 super(SSHConnector, self).__init__() 

138 self.storage_ip = configuration.emc_nas_server 

139 self.username = configuration.emc_nas_login 

140 self.password = configuration.emc_nas_password 

141 self.debug = debug 

142 

143 self.sshpool = ssh_utils.SSHPool(ip=self.storage_ip, 

144 port=22, 

145 conn_timeout=None, 

146 login=self.username, 

147 password=self.password) 

148 

149 def run_ssh(self, cmd_list, check_exit_code=False): 

150 command = ' '.join(shlex.quote(cmd_arg) for cmd_arg in cmd_list) 

151 

152 with self.sshpool.item() as ssh: 

153 try: 

154 out, err = processutils.ssh_execute( 

155 ssh, command, check_exit_code=check_exit_code) 

156 self.log_request(command, out, err) 

157 

158 return out, err 

159 except processutils.ProcessExecutionError as e: 

160 with excutils.save_and_reraise_exception(): 

161 LOG.error('Error running SSH command: %(cmd)s. ' 

162 'Error: %(excmsg)s.', 

163 {'cmd': command, 'excmsg': e}) 

164 

165 def log_request(self, cmd, out, err): 

166 if not self.debug: 

167 return 

168 

169 LOG.debug("\nSSH command: %s.\n", cmd) 

170 LOG.debug("SSH command output: out=%(out)s, err=%(err)s.\n", 

171 {'out': out, 'err': err})