cloudflare/cloudflared

Public

mirrored fromhttps://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
cc1c6d9abc865533e1ebb5a6a387fd3973ff7bc6

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

component-tests/setup.py

165lines · modecode

1#!/usr/bin/env python
2import argparse
3import base64
4import json
5import os
6import subprocess
7import uuid
8
9import CloudFlare
10import yaml
11from retrying import retry
12
13from constants import MAX_RETRIES, BACKOFF_SECS
14from util import LOGGER
15
16
17def get_config_from_env():
18 config_content = base64.b64decode(get_env("COMPONENT_TESTS_CONFIG_CONTENT")).decode('utf-8')
19 return yaml.safe_load(config_content)
20
21
22def get_config_from_file():
23 config_path = get_env("COMPONENT_TESTS_CONFIG")
24 with open(config_path, 'r') as infile:
25 return yaml.safe_load(infile)
26
27
28def persist_config(config):
29 config_path = get_env("COMPONENT_TESTS_CONFIG")
30 with open(config_path, 'w') as outfile:
31 yaml.safe_dump(config, outfile)
32
33
34def persist_origin_cert(config):
35 origincert = get_env("COMPONENT_TESTS_ORIGINCERT")
36 path = config["origincert"]
37 with open(path, 'w') as outfile:
38 outfile.write(origincert)
39 return path
40
41
42@retry(stop_max_attempt_number=MAX_RETRIES, wait_fixed=BACKOFF_SECS * 1000)
43def create_tunnel(config, origincert_path, random_uuid):
44 # Delete any previous existing credentials file. If the agent keeps files around (that's the case in Windows) then
45 # cloudflared tunnel create will refuse to create the tunnel because it does not want to overwrite credentials
46 # files.
47 credentials_path = config["credentials_file"]
48 try:
49 os.remove(credentials_path)
50 except OSError:
51 pass
52
53 tunnel_name = "cfd_component_test-" + random_uuid
54 create_cmd = [config["cloudflared_binary"], "tunnel", "--origincert", origincert_path, "create",
55 "--credentials-file", credentials_path, tunnel_name]
56 LOGGER.info(f"Creating tunnel with {create_cmd}")
57 subprocess.run(create_cmd, check=True)
58
59 list_cmd = [config["cloudflared_binary"], "tunnel", "--origincert", origincert_path, "list", "--name",
60 tunnel_name, "--output", "json"]
61 LOGGER.info(f"Listing tunnel with {list_cmd}")
62 cloudflared = subprocess.run(list_cmd, check=True, capture_output=True)
63 return json.loads(cloudflared.stdout)[0]["id"]
64
65
66@retry(stop_max_attempt_number=MAX_RETRIES, wait_fixed=BACKOFF_SECS * 1000)
67def delete_tunnel(config):
68 credentials_path = config["credentials_file"]
69 delete_cmd = [config["cloudflared_binary"], "tunnel", "--origincert", config["origincert"], "delete",
70 "--credentials-file", credentials_path, "-f", config["tunnel"]]
71 LOGGER.info(f"Deleting tunnel with {delete_cmd}")
72 subprocess.run(delete_cmd, check=True)
73
74
75@retry(stop_max_attempt_number=MAX_RETRIES, wait_fixed=BACKOFF_SECS * 1000)
76def create_dns(config, hostname, type, content):
77 cf = CloudFlare.CloudFlare(debug=True, token=get_env("DNS_API_TOKEN"))
78 cf.zones.dns_records.post(
79 config["zone_tag"],
80 data={'name': hostname, 'type': type, 'content': content, 'proxied': True}
81 )
82
83
84def create_classic_dns(config, random_uuid):
85 classic_hostname = "classic-" + random_uuid + "." + config["zone_domain"]
86 create_dns(config, classic_hostname, "AAAA", "fd10:aec2:5dae::")
87 return classic_hostname
88
89
90def create_named_dns(config, random_uuid):
91 hostname = "named-" + random_uuid + "." + config["zone_domain"]
92 create_dns(config, hostname, "CNAME", config["tunnel"] + ".cfargotunnel.com")
93 return hostname
94
95
96@retry(stop_max_attempt_number=MAX_RETRIES, wait_fixed=BACKOFF_SECS * 1000)
97def delete_dns(config, hostname):
98 cf = CloudFlare.CloudFlare(debug=True, token=get_env("DNS_API_TOKEN"))
99 zone_tag = config["zone_tag"]
100 dns_records = cf.zones.dns_records.get(zone_tag, params={'name': hostname})
101 if len(dns_records) > 0:
102 cf.zones.dns_records.delete(zone_tag, dns_records[0]['id'])
103
104
105def write_file(content, path):
106 with open(path, 'w') as outfile:
107 outfile.write(content)
108
109
110def get_env(env_name):
111 val = os.getenv(env_name)
112 if val is None:
113 raise Exception(f"{env_name} is not set")
114 return val
115
116
117def create():
118 """
119 Creates the necessary resources for the components test to run.
120 - Creates a named tunnel with a random name.
121 - Creates a random CNAME DNS entry for that tunnel.
122 - Creates a random AAAA DNS entry for a classic tunnel.
123
124 Those created resources are added to the config (obtained from an environment variable).
125 The resulting configuration is persisted for the tests to use.
126 """
127 config = get_config_from_env()
128 origincert_path = persist_origin_cert(config)
129
130 random_uuid = str(uuid.uuid4())
131 config["tunnel"] = create_tunnel(config, origincert_path, random_uuid)
132 config["classic_hostname"] = create_classic_dns(config, random_uuid)
133 config["ingress"] = [
134 {
135 "hostname": create_named_dns(config, random_uuid),
136 "service": "hello_world"
137 },
138 {
139 "service": "http_status:404"
140 }
141 ]
142
143 persist_config(config)
144
145
146def cleanup():
147 """
148 Reads the persisted configuration that was created previously.
149 Deletes the resources that were created there.
150 """
151 config = get_config_from_file()
152 delete_tunnel(config)
153 delete_dns(config, config["classic_hostname"])
154 delete_dns(config, config["ingress"][0]["hostname"])
155
156
157if __name__ == '__main__':
158 parser = argparse.ArgumentParser(description='setup component tests')
159 parser.add_argument('--type', choices=['create', 'cleanup'], default='create')
160 args = parser.parse_args()
161
162 if args.type == 'create':
163 create()
164 else:
165 cleanup()
166