This repository has been archived by the owner on Jul 25, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 37
/
agent-bootstrap-script.template
214 lines (155 loc) · 6.1 KB
/
agent-bootstrap-script.template
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# NOTE: don't use .format for string substitution since templating uses same to do
# variable substitution
import subprocess
import sys
import httplib
import urllib2
import shlex
import os
import platform
import socket
import ssl
import tempfile
import json
import traceback
import signal
import logging
# Set the time, so certs work below ALWAYS.
# Future NTP job will set it again,
# so preserving host's date is unecessary
ret = subprocess.call("date -s @{server_epoch_seconds} > /dev/null 2>&1", shell=True)
# create Logger with a single file handler
bootstrap_log = logging.getLogger("bootstrap")
bootstrap_log.setLevel(logging.DEBUG)
handler = logging.FileHandler("/var/log/chroma-agent.log")
handler.setLevel(logging.DEBUG)
handler.setFormatter(logging.Formatter("[%(asctime)s] bootstrap %(name)s %(levelname)s %(message)s"))
bootstrap_log.addHandler(handler)
IML_CONF_DIR = "/etc/iml/"
# The agent's private key, never shared
PRIVATE_KEY = os.path.join(IML_CONF_DIR, "private.pem")
# The agent's certificate, generated by the manager in response to a CSR
AGENT_CERT = os.path.join(IML_CONF_DIR, "self.crt")
# The root certificate used to authenticate the manager
AUTHORITY_CERT = os.path.join(IML_CONF_DIR, "authority.crt")
REPO_PATH = "/etc/yum.repos.d/Intel-Lustre-Agent.repo"
base_url = "{base_url}"
reg_url = "{reg_url}"
cert_str = """{cert_str}"""
repo_url = "{repo_url}"
repo_packages = "{repo_packages}"
profile_json = '{profile_json}'
REPO_CONTENT = """{repos}"""
class VerifiedHTTPSConnection(httplib.HTTPSConnection):
def connect(self):
sock = socket.create_connection((self.host, self.port), self.timeout)
if self._tunnel_host:
self.sock = sock
self._tunnel()
self.sock = ssl.wrap_socket(sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=AUTHORITY_CERT)
class VerifiedHTTPSHandler(urllib2.HTTPSHandler):
def __init__(self, connection_class=VerifiedHTTPSConnection):
self.specialized_conn_class = connection_class
urllib2.HTTPSHandler.__init__(self)
def https_open(self, req):
return self.do_open(self.specialized_conn_class, req)
def launch_command(cmd):
args = shlex.split(cmd)
debug = 'Command returned %d: stdout: "%s" stderr: "%s"'
bootstrap_log.info("Executing shell command with arguments: %s" % args)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
bootstrap_log.debug(debug % (p.returncode, out, err))
if p.returncode != 0:
raise Exception(debug % (p.returncode, out, err))
return out.strip()
def setup_keys():
if not os.path.exists(IML_CONF_DIR):
os.makedirs(IML_CONF_DIR)
with open(AUTHORITY_CERT, "w") as f:
f.write(cert_str)
return launch_command("openssl genrsa -out %s 2048" % PRIVATE_KEY)
def reg_manager():
fqdn = socket.getfqdn()
nodename = os.uname()[1]
csr = launch_command("openssl req -new -subj /C=/ST=/L=/O=/CN=%s -key %s" % (fqdn, PRIVATE_KEY))
data = json.dumps({{
"address": socket.gethostbyname(socket.gethostname()),
"fqdn": fqdn,
"nodename": nodename,
"version": 0,
"csr": csr,
"capabilities": [],
}})
try:
https_handler = VerifiedHTTPSHandler()
url_opener = urllib2.build_opener(https_handler)
url_opener.addheaders.append(("Content-Type", "application/json"))
handle = url_opener.open(reg_url, data)
response = handle.readlines()
handle.close()
json_resp = json.loads(response[0])
open(AGENT_CERT, "w").write(json_resp["certificate"])
return json_resp
except urllib2.URLError, e:
bootstrap_log.exception("Cannot reach host/url %s: %s" % (reg_url, e))
raise
def create_repo(contents):
tmp = tempfile.NamedTemporaryFile()
# this format needs to match chroma_agent.action_plugins.agent_setup.configure_repo
tmp.write(contents)
tmp.flush()
launch_command("cp %s %s" % (tmp.name, REPO_PATH))
os.chmod(REPO_PATH, 0644)
def install_agent():
return launch_command("yum install -y %s" % repo_packages)
def configure_server():
launch_command("chroma-agent set_server_url --url %s" % base_url)
launch_command("chroma-agent set_profile --profile_json '%s'" % profile_json)
def start_services():
launch_command("systemctl enable --now iml-storage-server.target")
def kill_zombies():
try:
# attempt to stop a pre-installed instance
launch_command("systemctl stop iml-storage-server.target")
except Exception:
# Will fail if not pre-installed
pass
# ensure that there are no old agents hanging around
for pid in [d for d in os.listdir("/proc") if d.isdigit()]:
try:
with open("/proc/%s/cmdline" % pid) as f:
if "chroma-agent-daemon" in f.read():
os.kill(int(pid), signal.SIGKILL)
except (OSError, IOError):
# Don't bail if this fails -- it's not critical
pass
def main():
try:
bootstrap_log.info("Agent bootstrap started...")
# Get a clean deployment environment
kill_zombies()
# Set up SSL keys and register with the manager using our
# embedded registration token
setup_keys()
registration_response = reg_manager()
contents = REPO_CONTENT.format(AUTHORITY_CERT, PRIVATE_KEY, AGENT_CERT).strip()
if len(contents) > 0:
# Now that we're registered, we can download packages
create_repo(contents)
install_agent()
# Persist the agent configuration file so that it can connect
# to the manager
configure_server()
bootstrap_log.info("Agent bootstrap completed, starting agent...")
# Finally start the services.
start_services()
print json.dumps(
{{"host_id": registration_response["host_id"], "command_id": registration_response["command_id"]}}
)
return 0
except Exception, err:
bootstrap_log.exception("Error from agent-bootstrap-script main():")
return 1
if __name__ == "__main__":
sys.exit(main())