summaryrefslogtreecommitdiff
path: root/tools/test-cloud-meta-mock.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/test-cloud-meta-mock.py')
-rwxr-xr-xtools/test-cloud-meta-mock.py122
1 files changed, 104 insertions, 18 deletions
diff --git a/tools/test-cloud-meta-mock.py b/tools/test-cloud-meta-mock.py
index 392955b8ad..ab3630addf 100755
--- a/tools/test-cloud-meta-mock.py
+++ b/tools/test-cloud-meta-mock.py
@@ -1,13 +1,23 @@
#!/usr/bin/env python
+# A service that mocks up various metadata providers. Used for testing,
+# can also be used standalone as a development aid.
+#
+# To run standalone:
+#
# run: $ systemd-socket-activate -l 8000 python tools/test-cloud-meta-mock.py &
# $ NM_CLOUD_SETUP_EC2_HOST=http://localhost:8000 \
# NM_CLOUD_SETUP_LOG=trace \
# NM_CLOUD_SETUP_EC2=yes src/nm-cloud-setup/nm-cloud-setup
# or just: $ python tools/test-cloud-meta-mock.py
+#
+# By default, the utility will server some resources for each known cloud
+# providers, for convenience. The tests start this with "--empty" argument,
+# which starts with no resources.
import os
import socket
+from sys import argv
from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler
@@ -20,36 +30,40 @@ class MockCloudMDRequestHandler(BaseHTTPRequestHandler):
Currently implements a fairly minimal subset of AWS EC2 API.
"""
- _ec2_macs = "/2018-09-24/meta-data/network/interfaces/macs/"
- _meta_resources = {
- "/latest/meta-data/": b"ami-id\n",
- _ec2_macs: b"9e:c0:3e:92:24:2d\n53:e9:7e:52:8d:a8",
- _ec2_macs + "9e:c0:3e:92:24:2d/subnet-ipv4-cidr-block": b"172.31.16.0/20",
- _ec2_macs + "9e:c0:3e:92:24:2d/local-ipv4s": b"172.31.26.249",
- _ec2_macs + "53:e9:7e:52:8d:a8/subnet-ipv4-cidr-block": b"172.31.166.0/20",
- _ec2_macs + "53:e9:7e:52:8d:a8/local-ipv4s": b"172.31.176.249",
- }
-
def log_message(self, format, *args):
pass
def do_GET(self):
- if self.path in self._meta_resources:
+ path = self.path.encode("ascii")
+ if path in self.server._resources:
self.send_response(200)
self.end_headers()
- self.wfile.write(self._meta_resources[self.path])
+ self.wfile.write(self.server._resources[path])
else:
self.send_response(404)
self.end_headers()
def do_PUT(self):
- if self.path == "/latest/api/token":
+ path = self.path.encode("ascii")
+ if path == b"/latest/api/token":
self.send_response(200)
self.end_headers()
self.wfile.write(
b"AQAAALH-k7i18JMkK-ORLZQfAa7nkNjQbKwpQPExNHqzk1oL_7eh-A=="
)
else:
+ length = int(self.headers["content-length"])
+ self.server._resources[path] = self.rfile.read(length)
+ self.send_response(201)
+ self.end_headers()
+
+ def do_DELETE(self):
+ path = self.path.encode("ascii")
+ if path in self.server._resources:
+ del self.server._resources[path]
+ self.send_response(204)
+ self.end_headers()
+ else:
self.send_response(404)
self.end_headers()
@@ -61,16 +75,89 @@ class SocketHTTPServer(HTTPServer):
fron the test runner.
"""
- def __init__(self, server_address, RequestHandlerClass, socket):
+ def __init__(self, server_address, RequestHandlerClass, socket, resources):
BaseServer.__init__(self, server_address, RequestHandlerClass)
self.socket = socket
self.server_address = self.socket.getsockname()
+ self._resources = resources
+
+
+def default_resources():
+ ec2_macs = b"/2018-09-24/meta-data/network/interfaces/macs/"
+
+ aliyun_meta = b"/2016-01-01/meta-data/"
+ aliyun_macs = aliyun_meta + b"network/interfaces/macs/"
+
+ azure_meta = b"/metadata/instance"
+ azure_iface = azure_meta + b"/network/interface/"
+ azure_query = b"?format=text&api-version=2017-04-02"
+
+ gcp_meta = b"/computeMetadata/v1/instance/"
+ gcp_iface = gcp_meta + b"network-interfaces/"
+
+ mac1 = b"9e:c0:3e:92:24:2d"
+ mac2 = b"53:e9:7e:52:8d:a8"
+
+ ip1 = b"172.31.26.249"
+ ip2 = b"172.31.176.249"
+
+ return {
+ b"/latest/meta-data/": b"ami-id\n",
+ ec2_macs: mac2 + b"\n" + mac1,
+ ec2_macs + mac2 + b"/subnet-ipv4-cidr-block": b"172.31.16.0/20",
+ ec2_macs + mac2 + b"/local-ipv4s": ip1,
+ ec2_macs + mac1 + b"/subnet-ipv4-cidr-block": b"172.31.166.0/20",
+ ec2_macs + mac1 + b"/local-ipv4s": ip2,
+ aliyun_meta: b"ami-id\n",
+ aliyun_macs: mac2 + b"\n" + mac1,
+ aliyun_macs + mac2 + b"/vpc-cidr-block": b"172.31.16.0/20",
+ aliyun_macs + mac2 + b"/private-ipv4s": ip1,
+ aliyun_macs + mac2 + b"/primary-ip-address": ip1,
+ aliyun_macs + mac2 + b"/netmask": b"255.255.255.0",
+ aliyun_macs + mac2 + b"/gateway": b"172.31.26.2",
+ aliyun_macs + mac1 + b"/vpc-cidr-block": b"172.31.166.0/20",
+ aliyun_macs + mac1 + b"/private-ipv4s": ip2,
+ aliyun_macs + mac1 + b"/primary-ip-address": ip2,
+ aliyun_macs + mac1 + b"/netmask": b"255.255.255.0",
+ aliyun_macs + mac1 + b"/gateway": b"172.31.176.2",
+ azure_meta + azure_query: b"",
+ azure_iface + azure_query: b"0\n1\n",
+ azure_iface + b"0/macAddress" + azure_query: mac1,
+ azure_iface + b"1/macAddress" + azure_query: mac2,
+ azure_iface + b"0/ipv4/ipAddress/" + azure_query: b"0\n",
+ azure_iface + b"1/ipv4/ipAddress/" + azure_query: b"0\n",
+ azure_iface + b"0/ipv4/ipAddress/0/privateIpAddress" + azure_query: ip1,
+ azure_iface + b"1/ipv4/ipAddress/0/privateIpAddress" + azure_query: ip2,
+ azure_iface + b"0/ipv4/subnet/0/address/" + azure_query: b"172.31.16.0",
+ azure_iface + b"1/ipv4/subnet/0/address/" + azure_query: b"172.31.166.0",
+ azure_iface + b"0/ipv4/subnet/0/prefix/" + azure_query: b"20",
+ azure_iface + b"1/ipv4/subnet/0/prefix/" + azure_query: b"20",
+ gcp_meta + b"id": b"",
+ gcp_iface: b"0\n1\n",
+ gcp_iface + b"0/mac": mac1,
+ gcp_iface + b"1/mac": mac2,
+ gcp_iface + b"0/forwarded-ips/": b"0\n",
+ gcp_iface + b"0/forwarded-ips/0": ip1,
+ gcp_iface + b"1/forwarded-ips/": b"0\n",
+ gcp_iface + b"1/forwarded-ips/0": ip2,
+ }
+resources = None
+try:
+ if argv[1] == "--empty":
+ resources = {}
+except IndexError:
+ pass
+if resources is None:
+ resources = default_resources()
+
# See sd_listen_fds(3)
-fileno = os.getenv("LISTEN_FD")
+fileno = os.getenv("LISTEN_FDS")
if fileno is not None:
- s = socket.socket(fileno=int(fileno))
+ if fileno != "1":
+ raise Exception("Bad LISTEN_FDS")
+ s = socket.socket(fileno=3)
else:
addr = ("localhost", 0)
s = socket.socket()
@@ -78,8 +165,7 @@ else:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s.bind(addr)
-
-httpd = SocketHTTPServer(None, MockCloudMDRequestHandler, socket=s)
+httpd = SocketHTTPServer(None, MockCloudMDRequestHandler, socket=s, resources=resources)
print("Listening on http://%s:%d" % (httpd.server_address[0], httpd.server_address[1]))
httpd.server_activate()