Skip to content

Commit 3efe8dc

Browse files
committed
Unify MetadataProxyHandlerBaseSocketServer class
The class ``MetadataProxyHandlerBaseSocketServer`` is implemented only once in ``neutron.common.metadata``. Conflicts: neutron/agent/metadata/agent.py Partial-Bug: #2100585 Change-Id: I17f80ec62398eeb0135a7ab2ff59aa692d2fa086 (cherry picked from commit af3cab0) Signed-off-by: Rodolfo Alonso Hernandez <[email protected]>
1 parent 0c38e52 commit 3efe8dc

File tree

3 files changed

+104
-187
lines changed

3 files changed

+104
-187
lines changed

neutron/agent/metadata/agent.py

Lines changed: 3 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,21 @@
1414

1515
import io
1616
import socketserver
17-
import urllib
1817

1918
from neutron_lib.agent import topics
2019
from neutron_lib import constants
2120
from neutron_lib import context
2221
from oslo_config import cfg
2322
from oslo_log import log as logging
24-
import requests
2523
import webob
2624

2725
from neutron._i18n import _
2826
from neutron.agent.common import base_agent_rpc
2927
from neutron.agent.linux import utils as agent_utils
3028
from neutron.agent.metadata import proxy_base
3129
from neutron.agent import rpc as agent_rpc
32-
from neutron.common import ipv6_utils
3330
from neutron.common import loopingcall
3431
from neutron.common import metadata as common_metadata
35-
from neutron.common import utils as common_utils
3632

3733

3834
LOG = logging.getLogger(__name__)
@@ -58,95 +54,9 @@ def __init__(self, topic):
5854
version='1.0')
5955

6056

61-
class MetadataProxyHandlerBaseSocketServer(
62-
proxy_base.MetadataProxyHandlerBase):
63-
@staticmethod
64-
def _http_response(http_response, request):
65-
_res = webob.Response(
66-
body=http_response.content,
67-
status=http_response.status_code,
68-
content_type=http_response.headers['content-type'],
69-
charset=http_response.encoding)
70-
# NOTE(ralonsoh): there should be a better way to format the HTTP
71-
# response, adding the HTTP version to the ``webob.Response``
72-
# output string.
73-
out = request.http_version + ' ' + str(_res)
74-
if (int(_res.headers['content-length']) == 0 and
75-
_res.status_code == 200):
76-
# Add 2 extra \r\n to the result. HAProxy is also expecting
77-
# it even when the body is empty.
78-
out += '\r\n\r\n'
79-
return out.encode(http_response.encoding)
80-
81-
def _proxy_request(self, instance_id, project_id, req):
82-
headers = {
83-
'X-Forwarded-For': req.headers.get('X-Forwarded-For'),
84-
'X-Instance-ID': instance_id,
85-
'X-Tenant-ID': project_id,
86-
'X-Instance-ID-Signature': common_utils.sign_instance_id(
87-
self.conf, instance_id)
88-
}
89-
90-
nova_host_port = ipv6_utils.valid_ipv6_url(
91-
self.conf.nova_metadata_host,
92-
self.conf.nova_metadata_port)
93-
94-
url = urllib.parse.urlunsplit((
95-
self.conf.nova_metadata_protocol,
96-
nova_host_port,
97-
req.path_info,
98-
req.query_string,
99-
''))
100-
101-
disable_ssl_certificate_validation = self.conf.nova_metadata_insecure
102-
if self.conf.auth_ca_cert and not disable_ssl_certificate_validation:
103-
verify_cert = self.conf.auth_ca_cert
104-
else:
105-
verify_cert = not disable_ssl_certificate_validation
106-
107-
client_cert = None
108-
if self.conf.nova_client_cert and self.conf.nova_client_priv_key:
109-
client_cert = (self.conf.nova_client_cert,
110-
self.conf.nova_client_priv_key)
111-
112-
try:
113-
resp = requests.request(method=req.method, url=url,
114-
headers=headers,
115-
data=req.body,
116-
cert=client_cert,
117-
verify=verify_cert,
118-
timeout=60)
119-
except requests.ConnectionError:
120-
msg = _('The remote metadata server is temporarily unavailable. '
121-
'Please try again later.')
122-
LOG.warning(msg)
123-
title = '503 Service Unavailable'
124-
return common_metadata.encode_http_reponse(title, title, msg)
125-
126-
if resp.status_code == 200:
127-
return self._http_response(resp, req)
128-
if resp.status_code == 403:
129-
LOG.warning(
130-
'The remote metadata server responded with Forbidden. This '
131-
'response usually occurs when shared secrets do not match.'
132-
)
133-
# TODO(ralonsoh): add info in the returned HTTP message to the VM.
134-
return self._http_response(resp, req)
135-
if resp.status_code == 500:
136-
msg = _(
137-
'Remote metadata server experienced an internal server error.'
138-
)
139-
LOG.warning(msg)
140-
# TODO(ralonsoh): add info in the returned HTTP message to the VM.
141-
return self._http_response(resp, req)
142-
if resp.status_code in (400, 404, 409, 502, 503, 504):
143-
# TODO(ralonsoh): add info in the returned HTTP message to the VM.
144-
return self._http_response(resp, req)
145-
raise Exception(_('Unexpected response code: %s') % resp.status_code)
146-
147-
148-
class MetadataProxyHandler(MetadataProxyHandlerBaseSocketServer,
149-
socketserver.StreamRequestHandler):
57+
class MetadataProxyHandler(
58+
common_metadata.MetadataProxyHandlerBaseSocketServer,
59+
socketserver.StreamRequestHandler):
15060
NETWORK_ID_HEADER = 'X-Neutron-Network-ID'
15161
ROUTER_ID_HEADER = 'X-Neutron-Router-ID'
15262
_conf = None

neutron/agent/ovn/metadata/server_socket.py

Lines changed: 3 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -12,117 +12,26 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
1615
import io
1716
import socketserver
18-
import urllib
1917

2018
from oslo_config import cfg
2119
from oslo_log import log as logging
22-
import requests
2320
import webob
2421

2522
from neutron._i18n import _
2623
from neutron.agent.linux import utils as agent_utils
2724
from neutron.agent.metadata import proxy_base
28-
from neutron.common import ipv6_utils
2925
from neutron.common import metadata as common_metadata
3026
from neutron.common.ovn import constants as ovn_const
31-
from neutron.common import utils as common_utils
3227

3328

3429
LOG = logging.getLogger(__name__)
3530

3631

37-
class MetadataProxyHandlerBaseSocketServer(
38-
proxy_base.MetadataProxyHandlerBase):
39-
@staticmethod
40-
def _http_response(http_response, request):
41-
_res = webob.Response(
42-
body=http_response.content,
43-
status=http_response.status_code,
44-
content_type=http_response.headers['content-type'],
45-
charset=http_response.encoding)
46-
# NOTE(ralonsoh): there should be a better way to format the HTTP
47-
# response, adding the HTTP version to the ``webob.Response``
48-
# output string.
49-
out = request.http_version + ' ' + str(_res)
50-
if (int(_res.headers['content-length']) == 0 and
51-
_res.status_code == 200):
52-
# Add 2 extra \r\n to the result. HAProxy is also expecting
53-
# it even when the body is empty.
54-
out += '\r\n\r\n'
55-
return out.encode(http_response.encoding)
56-
57-
def _proxy_request(self, instance_id, project_id, req):
58-
headers = {
59-
'X-Forwarded-For': req.headers.get('X-Forwarded-For'),
60-
'X-Instance-ID': instance_id,
61-
'X-Tenant-ID': project_id,
62-
'X-Instance-ID-Signature': common_utils.sign_instance_id(
63-
self.conf, instance_id)
64-
}
65-
66-
nova_host_port = ipv6_utils.valid_ipv6_url(
67-
self.conf.nova_metadata_host,
68-
self.conf.nova_metadata_port)
69-
70-
url = urllib.parse.urlunsplit((
71-
self.conf.nova_metadata_protocol,
72-
nova_host_port,
73-
req.path_info,
74-
req.query_string,
75-
''))
76-
77-
disable_ssl_certificate_validation = self.conf.nova_metadata_insecure
78-
if self.conf.auth_ca_cert and not disable_ssl_certificate_validation:
79-
verify_cert = self.conf.auth_ca_cert
80-
else:
81-
verify_cert = not disable_ssl_certificate_validation
82-
83-
client_cert = None
84-
if self.conf.nova_client_cert and self.conf.nova_client_priv_key:
85-
client_cert = (self.conf.nova_client_cert,
86-
self.conf.nova_client_priv_key)
87-
88-
try:
89-
resp = requests.request(method=req.method, url=url,
90-
headers=headers,
91-
data=req.body,
92-
cert=client_cert,
93-
verify=verify_cert,
94-
timeout=60)
95-
except requests.ConnectionError:
96-
msg = _('The remote metadata server is temporarily unavailable. '
97-
'Please try again later.')
98-
LOG.warning(msg)
99-
title = '503 Service Unavailable'
100-
return common_metadata.encode_http_reponse(title, title, msg)
101-
102-
if resp.status_code == 200:
103-
return self._http_response(resp, req)
104-
if resp.status_code == 403:
105-
LOG.warning(
106-
'The remote metadata server responded with Forbidden. This '
107-
'response usually occurs when shared secrets do not match.'
108-
)
109-
# TODO(ralonsoh): add info in the returned HTTP message to the VM.
110-
return self._http_response(resp, req)
111-
if resp.status_code == 500:
112-
msg = _(
113-
'Remote metadata server experienced an internal server error.'
114-
)
115-
LOG.warning(msg)
116-
# TODO(ralonsoh): add info in the returned HTTP message to the VM.
117-
return self._http_response(resp, req)
118-
if resp.status_code in (400, 404, 409, 502, 503, 504):
119-
# TODO(ralonsoh): add info in the returned HTTP message to the VM.
120-
return self._http_response(resp, req)
121-
raise Exception(_('Unexpected response code: %s') % resp.status_code)
122-
123-
124-
class MetadataProxyHandler(MetadataProxyHandlerBaseSocketServer,
125-
socketserver.StreamRequestHandler):
32+
class MetadataProxyHandler(
33+
common_metadata.MetadataProxyHandlerBaseSocketServer,
34+
socketserver.StreamRequestHandler):
12635
NETWORK_ID_HEADER = 'X-OVN-Network-ID'
12736
ROUTER_ID_HEADER = ''
12837
_conf = None

neutron/common/metadata.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,20 @@
1111
# License for the specific language governing permissions and limitations
1212
# under the License.
1313

14+
import abc
15+
from urllib import parse
16+
1417
import jinja2
1518
from neutron_lib import constants
1619
from oslo_log import log as logging
1720
from oslo_utils import encodeutils
21+
import requests
22+
import webob
23+
24+
from neutron._i18n import _
25+
from neutron.agent.metadata import proxy_base
26+
from neutron.common import ipv6_utils
27+
from neutron.common import utils as common_utils
1828

1929

2030
LOG = logging.getLogger(__name__)
@@ -140,3 +150,91 @@ def encode_http_reponse(http_code, title, message):
140150
reponse = RESPONSE.render(http_code=http_code, title=title,
141151
body_title=title, body=message, len=length)
142152
return encodeutils.to_utf8(reponse)
153+
154+
155+
class MetadataProxyHandlerBaseSocketServer(
156+
proxy_base.MetadataProxyHandlerBase,
157+
metaclass=abc.ABCMeta):
158+
@staticmethod
159+
def _http_response(http_response, request):
160+
_res = webob.Response(
161+
body=http_response.content,
162+
status=http_response.status_code,
163+
content_type=http_response.headers['content-type'],
164+
charset=http_response.encoding)
165+
# NOTE(ralonsoh): there should be a better way to format the HTTP
166+
# response, adding the HTTP version to the ``webob.Response``
167+
# output string.
168+
out = request.http_version + ' ' + str(_res)
169+
if (int(_res.headers['content-length']) == 0 and
170+
_res.status_code == 200):
171+
# Add 2 extra \r\n to the result. HAProxy is also expecting
172+
# it even when the body is empty.
173+
out += '\r\n\r\n'
174+
return out.encode(http_response.encoding)
175+
176+
def _proxy_request(self, instance_id, project_id, req):
177+
headers = {
178+
'X-Forwarded-For': req.headers.get('X-Forwarded-For'),
179+
'X-Instance-ID': instance_id,
180+
'X-Tenant-ID': project_id,
181+
'X-Instance-ID-Signature': common_utils.sign_instance_id(
182+
self.conf, instance_id)
183+
}
184+
185+
nova_host_port = ipv6_utils.valid_ipv6_url(
186+
self.conf.nova_metadata_host,
187+
self.conf.nova_metadata_port)
188+
189+
url = parse.urlunsplit((
190+
self.conf.nova_metadata_protocol,
191+
nova_host_port,
192+
req.path_info,
193+
req.query_string,
194+
''))
195+
196+
disable_ssl_certificate_validation = self.conf.nova_metadata_insecure
197+
if self.conf.auth_ca_cert and not disable_ssl_certificate_validation:
198+
verify_cert = self.conf.auth_ca_cert
199+
else:
200+
verify_cert = not disable_ssl_certificate_validation
201+
202+
client_cert = None
203+
if self.conf.nova_client_cert and self.conf.nova_client_priv_key:
204+
client_cert = (self.conf.nova_client_cert,
205+
self.conf.nova_client_priv_key)
206+
207+
try:
208+
resp = requests.request(method=req.method, url=url,
209+
headers=headers,
210+
data=req.body,
211+
cert=client_cert,
212+
verify=verify_cert,
213+
timeout=60)
214+
except requests.ConnectionError:
215+
msg = _('The remote metadata server is temporarily unavailable. '
216+
'Please try again later.')
217+
LOG.warning(msg)
218+
title = '503 Service Unavailable'
219+
return encode_http_reponse(title, title, msg)
220+
221+
if resp.status_code == 200:
222+
return self._http_response(resp, req)
223+
if resp.status_code == 403:
224+
LOG.warning(
225+
'The remote metadata server responded with Forbidden. This '
226+
'response usually occurs when shared secrets do not match.'
227+
)
228+
# TODO(ralonsoh): add info in the returned HTTP message to the VM.
229+
return self._http_response(resp, req)
230+
if resp.status_code == 500:
231+
msg = _(
232+
'Remote metadata server experienced an internal server error.'
233+
)
234+
LOG.warning(msg)
235+
# TODO(ralonsoh): add info in the returned HTTP message to the VM.
236+
return self._http_response(resp, req)
237+
if resp.status_code in (400, 404, 409, 502, 503, 504):
238+
# TODO(ralonsoh): add info in the returned HTTP message to the VM.
239+
return self._http_response(resp, req)
240+
raise Exception(_('Unexpected response code: %s') % resp.status_code)

0 commit comments

Comments
 (0)