blob: 75dcd8c7a5b01f5d1982bbc4558e82261c04f7c7 [file] [log] [blame]
Scott Baker7581c252016-05-27 13:12:47 -07001import os
2import base64
Scott Bakeraab8a292016-06-03 16:32:45 -07003import jinja2
Scott Baker7581c252016-05-27 13:12:47 -07004import string
5import sys
Scott Bakerb0eb23e2016-06-01 16:08:04 -07006import urllib2
7import urlparse
Scott Baker7581c252016-05-27 13:12:47 -07008import xmlrpclib
9
Scott Baker7581c252016-05-27 13:12:47 -070010from xos.config import Config
Scott Bakeraab8a292016-06-03 16:32:45 -070011from core.models import Service, ServiceController, ServiceControllerResource, XOS
Scott Baker7581c252016-05-27 13:12:47 -070012from xos.logger import Logger, logging
13
14logger = Logger(level=logging.INFO)
15
16class XOSBuilder(object):
Scott Baker037f6792016-06-02 16:47:45 -070017 UI_KINDS=["models", "admin", "django_library", "rest", "tosca_custom_types", "tosca_resource","public_key"]
Scott Baker18c89172016-06-02 16:40:25 -070018 SYNC_CONTROLLER_KINDS=["synchronizer", "private_key", "public_key"]
Scott Baker513ea452016-06-02 16:03:26 -070019 SYNC_ALLCONTROLLER_KINDS=["models", "django_library"]
Scott Bakerb0eb23e2016-06-01 16:08:04 -070020
Scott Baker7581c252016-05-27 13:12:47 -070021 def __init__(self):
Scott Bakerb0eb23e2016-06-01 16:08:04 -070022 self.source_ui_image = "xosproject/xos"
23 self.source_sync_image = "xosproject/xos-synchronizer-openstack"
24 self.build_dir = "/opt/xos/BUILD/"
25
26 # stuff that has to do with downloading
27
28 def get_dest_dir(self, scr):
29 xos_base = "opt/xos"
30 service_name = scr.service_controller.name
31 base_dirs = {"models": "%s/services/%s/" % (xos_base, service_name),
32 "admin": "%s/services/%s/" % (xos_base, service_name),
33 "django_library": "%s/services/%s/" % (xos_base, service_name),
34 "synchronizer": "%s/synchronizers/%s/" % (xos_base, service_name),
35 "tosca_custom_types": "%s/tosca/custom_types/" % (xos_base),
Scott Baker18c89172016-06-02 16:40:25 -070036 "tosca_resource": "%s/tosca/resources/" % (xos_base),
37 "private_key": "%s/services/%s/keys" % (xos_base, service_name),
38 "public_key": "%s/services/%s/keys/" % (xos_base, service_name)}
Scott Bakerb0eb23e2016-06-01 16:08:04 -070039 return base_dirs[scr.kind]
40
41 def get_build_fn(self, scr):
42 dest_dir = self.get_dest_dir(scr)
43 dest_fn = os.path.split(urlparse.urlsplit(scr.full_url).path)[-1]
44 return os.path.join(dest_dir, dest_fn)
45
46 def get_download_fn(self, scr):
47 dest_fn = self.get_build_fn(scr)
48 return os.path.join(self.build_dir, dest_fn)
49
50 def read_manifest(self, scr, fn):
51 manifest = []
52 manifest_lines = file(fn).readlines()
53 manifest_lines = [x.strip() for x in manifest_lines]
Scott Bakerc2a2fe92016-06-02 13:19:10 -070054 manifest_lines = [x for x in manifest_lines if x]
Scott Bakerb0eb23e2016-06-01 16:08:04 -070055 for line in manifest_lines:
Scott Bakerc2a2fe92016-06-02 13:19:10 -070056 url_parts = urlparse.urlsplit(scr.full_url)
57 new_path = os.path.join(os.path.join(*os.path.split(url_parts.path)[:-1]),line)
58 url = urlparse.urlunsplit( (url_parts.scheme, url_parts.netloc, new_path, url_parts.query, url_parts.fragment) )
Scott Bakerb0eb23e2016-06-01 16:08:04 -070059
60 build_fn = os.path.join(self.get_dest_dir(scr), line)
Scott Bakerc2a2fe92016-06-02 13:19:10 -070061 download_fn = os.path.join(self.build_dir, build_fn)
Scott Bakerb0eb23e2016-06-01 16:08:04 -070062
63 manifest.append( (url, download_fn, build_fn) )
64 return manifest
65
66 def download_file(self, url, dest_fn):
67 logger.info("Download %s to %s" % (url, dest_fn))
68 if not os.path.exists(os.path.dirname(dest_fn)):
69 os.makedirs(os.path.dirname(dest_fn))
70 obj = urllib2.urlopen(url)
71 file(dest_fn,"w").write(obj.read())
72
Scott Bakerc2a2fe92016-06-02 13:19:10 -070073 # make python files executable
74 if dest_fn.endswith(".py"): # and contents.startswith("#!"):
75 os.chmod(dest_fn, 0755)
76
Scott Bakerb0eb23e2016-06-01 16:08:04 -070077 def download_resource(self, scr):
78 if scr.format == "manifest":
79 manifest_fn = self.get_download_fn(scr)
80 self.download_file(scr.full_url, manifest_fn)
Scott Bakerc2a2fe92016-06-02 13:19:10 -070081 manifest = self.read_manifest(scr, manifest_fn)
Scott Bakerb0eb23e2016-06-01 16:08:04 -070082 for (url, download_fn, build_fn) in manifest:
83 self.download_file(url, download_fn)
84 else:
85 self.download_file(scr.full_url, self.get_download_fn(scr))
86
87 def get_docker_lines(self, scr):
88 if scr.format == "manifest":
89 manifest_fn = self.get_download_fn(scr)
90 manifest = self.read_manifest(scr, manifest_fn)
91 lines = []
92 for (url, download_fn, build_fn) in manifest:
93 lines.append("ADD %s /%s" % (build_fn, build_fn))
94 return lines
95 else:
96 build_fn = self.get_build_fn(scr)
97 return ["ADD %s /%s" % (build_fn, build_fn)]
98
99 def get_controller_docker_lines(self, controller, kinds):
100 dockerfile=[]
101 for scr in controller.service_controller_resources.all():
102 if scr.kind in kinds:
103 lines = self.get_docker_lines(scr)
104 dockerfile = dockerfile + lines
105 return dockerfile
106
107 # stuff that has to do with building
108
Scott Baker513ea452016-06-02 16:03:26 -0700109 def create_xos_app_data(self, name, dockerfile, app_list, migration_list):
Scott Bakerae196c32016-06-01 23:29:22 -0700110 if not os.path.exists(os.path.join(self.build_dir,"opt/xos/xos")):
111 os.makedirs(os.path.join(self.build_dir,"opt/xos/xos"))
112
113 if app_list:
Scott Baker513ea452016-06-02 16:03:26 -0700114 dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_app_list /opt/xos/xos/xosbuilder_app_list" % name)
115 file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_app_list") % name, "w").write("\n".join(app_list)+"\n")
Scott Bakerae196c32016-06-01 23:29:22 -0700116
117 if migration_list:
Scott Baker513ea452016-06-02 16:03:26 -0700118 dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_migration_list /opt/xos/xos/xosbuilder_migration_list" % name)
119 file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_migration_list") % name, "w").write("\n".join(migration_list)+"\n")
Scott Bakerae196c32016-06-01 23:29:22 -0700120
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700121 def create_ui_dockerfile(self):
122 dockerfile_fn = "Dockerfile.UI"
123
Scott Bakerae196c32016-06-01 23:29:22 -0700124 app_list = []
125 migration_list = []
126
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700127 dockerfile = ["FROM %s" % self.source_ui_image]
128 for controller in ServiceController.objects.all():
129 dockerfile = dockerfile + self.get_controller_docker_lines(controller, self.UI_KINDS)
Scott Bakerae196c32016-06-01 23:29:22 -0700130 if controller.service_controller_resources.filter(kind="models").exists():
131 app_list.append("services." + controller.name)
132 migration_list.append(controller.name)
133
Scott Baker513ea452016-06-02 16:03:26 -0700134 self.create_xos_app_data("ui", dockerfile, app_list, migration_list)
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700135
136 file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
137
Scott Baker8d252b62016-06-01 23:08:04 -0700138 return {"dockerfile_fn": dockerfile_fn,
139 "docker_image_name": "xosproject/xos-ui"}
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700140
141 def create_synchronizer_dockerfile(self, controller):
Scott Baker513ea452016-06-02 16:03:26 -0700142 # bake in the synchronizer from this controller
143 sync_lines = self.get_controller_docker_lines(controller, self.SYNC_CONTROLLER_KINDS)
144 if not sync_lines:
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700145 return []
146
147 dockerfile_fn = "Dockerfile.%s" % controller.name
148 dockerfile = ["FROM %s" % self.source_sync_image]
Scott Baker513ea452016-06-02 16:03:26 -0700149
150 # Now bake in models from this controller as well as the others
151 # It's important to bake all services in, because some services'
152 # synchronizers may depend on models from another service.
153 app_list = []
154 for c in ServiceController.objects.all():
155 dockerfile = dockerfile + self.get_controller_docker_lines(c, self.SYNC_ALLCONTROLLER_KINDS)
156 if controller.service_controller_resources.filter(kind="models").exists():
157 app_list.append("services." + controller.name)
158
159 self.create_xos_app_data(controller.name, dockerfile, app_list, None)
160
161 dockerfile = dockerfile + sync_lines
Scott Bakerc2a2fe92016-06-02 13:19:10 -0700162 file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700163
Scott Baker8d252b62016-06-01 23:08:04 -0700164 return {"dockerfile_fn": dockerfile_fn,
165 "docker_image_name": "xosproject/xos-synchronizer-%s" % controller.name}
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700166
Scott Bakeraab8a292016-06-03 16:32:45 -0700167 def create_docker_compose(self):
168 xos = XOS.objects.all()[0]
169
170 volume_list = [] # FINISH ME
171
172 containers = {}
173
174 containers["xos_db"] = \
175 {"image": "xosproject/xos-postgres",
176 "expose": [5432]}
177
178 containers["xos_ui"] = \
179 {"image": "xosproject/xos-ui",
180 "command": "python /opt/xos/manage.py runserver 0.0.0.0:%d --insecure --makemigrations" % xos.ui_port,
181 "ports": {"%d"%xos.ui_port : "%d"%xos.ui_port},
182 "links": ["xos_db"],
183 "volumes": volume_list}
184
Scott Bakerbe41a122016-06-06 10:40:40 -0700185 containers["xos_bootstrap_ui"] = {"image": "xosproject/xos-ui",
186 "command": "python /opt/xos/manage.py runserver 0.0.0.0:%d --insecure --makemigrations" % xos.bootstrap_ui_port,
187 "ports": {"%d"%xos.bootstrap_ui_port : "%d"%xos.bootstrap_ui_port},
188 "links": ["xos_db"],
189 "volumes": volume_list}
190
Scott Bakeraab8a292016-06-03 16:32:45 -0700191 for c in ServiceController.objects.all():
192 containers["xos_synchronizer_%s" % c.name] = \
193 {"image": "xosproject/xos-synchronizer-%s" % controller.name,
194 "command": 'bash -c "sleep 120; bash /opt/xos/synchronizers/%s/run.sh"',
195 "links": ["xos_db"],
196 "volumes": volume_list}
197
198 vars = { "containers": containers }
199
200 template_loader = jinja2.FileSystemLoader( "/opt/xos/synchronizers/onboarding/templates/" )
201 template_env = jinja2.Environment(loader=template_loader)
202 template = template_env.get_template("docker-compose.yml.j2")
203 buffer = template.render(vars)
204
205 if not os.path.exists("/opt/xos/synchronizers/onboarding/docker-compose"):
206 os.makedirs("/opt/xos/synchronizers/onboarding/docker-compose")
207 file("/opt/xos/synchronizers/onboarding/docker-compose/docker-compose.yml", "w").write(buffer)
208
Scott Baker8d252b62016-06-01 23:08:04 -0700209# def build_xos(self):
210# dockerfiles=[]
211# dockerfiles.append(self.create_ui_dockerfile())
212#
213# for controller in ServiceController.objects.all():
214# dockerfiles.append(self.create_synchronizer_dockerfile(controller))
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700215
216
217