Merge lp:~bjornt/landscape-charm/bundles-render-local into lp:~landscape/landscape-charm/trunk

Proposed by Björn Tillenius
Status: Superseded
Proposed branch: lp:~bjornt/landscape-charm/bundles-render-local
Merge into: lp:~landscape/landscape-charm/trunk
Diff against target: 500 lines (+458/-0) (has conflicts)
8 files modified
.bzrignore (+1/-0)
Makefile (+29/-0)
README.md (+28/-0)
charm-store (+70/-0)
landscape-template.jinja2 (+99/-0)
render-bundles (+80/-0)
ubuntu-deps (+53/-0)
update-charm-revisions (+98/-0)
Conflict adding file .bzrignore.  Moved existing file to .bzrignore.moved.
Conflict adding file Makefile.  Moved existing file to Makefile.moved.
Conflict adding file README.md.  Moved existing file to README.md.moved.
To merge this branch: bzr merge lp:~bjornt/landscape-charm/bundles-render-local
Reviewer Review Type Date Requested Status
Landscape Pending
Landscape Pending
Review via email: mp+296667@code.launchpad.net

Description of the change

Allow the branch or charm of landscape-server to be given to
render-bundles.

This allows you to generate bundles that use a local branch or charm.

It's meant to be used by lp:~bjornt/landscape-charm/deploy-local-branch.
You can see the diff for that branch here:

    https://pastebin.canonical.com/158174/

This will allow you to use 'make stage-landscape-charm' to deploy the
landscape-server branch you're working on.

Testing instructions:

In a landscape-server branch:

    CHARM_BRANCH=lp:~bjornt/landscape-charm/deploy-local-branch make stage-landscape-charm
    bzr checkout lp:~bjornt/landscape-charm/bundles-render-local build/landscape-charm/bundles

To deploy with Juju 1.25 and juju-deployer:

    make -C build/landscape-charm deploy-local

To deploy with Juju 2:

    make -C build/landscape-charm bundles-local-charm
    juju-2.0 build/landscape-charm/bundles/build/landscape-scalable/bundle.yaml

To post a comment you must log in.
28. By Björn Tillenius

Review comments.

Unmerged revisions

28. By Björn Tillenius

Review comments.

27. By Björn Tillenius

Allow the landscape-server branch to specified to render-bundles.

26. By Björn Tillenius

Allow the landscape-server charm to specified to render-bundles.

25. By David Britton

Merge bundles-trunk-xenial [f=1585389] [r=chad.smith,landscape-builder,fginther] [a=David Britton]
- Use Xenial charm for postgres and landscape.
- rework push/diff/publish workflow for new 'charm' tool
- make CHARM_STORE_USER required in Makefile for safety.

24. By David Britton

Just do a make render [trivial]

23. By Andreas Hasenack

Updated charm revisions

22. By Adam Collard

Bump us (again) to 16.03 from 15.11 in the bundle [trivial] [r=ack]

21. By David Britton

don't use machines in 'scalable' case.

20. By David Britton

check in rendered changes to bundles.

19. By David Britton

to: needs to be an array in v4 bundles.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.bzrignore'
2--- .bzrignore 1970-01-01 00:00:00 +0000
3+++ .bzrignore 2016-06-07 14:03:21 +0000
4@@ -0,0 +1,1 @@
5+build
6
7=== renamed file '.bzrignore' => '.bzrignore.moved'
8=== added file 'Makefile'
9--- Makefile 1970-01-01 00:00:00 +0000
10+++ Makefile 2016-06-07 14:03:21 +0000
11@@ -0,0 +1,29 @@
12+diff-charm-store: check-env render
13+ ./charm-store diff $${CHARM_STORE_USER}
14+
15+push-charm-store: check-env render
16+ ./charm-store push $${CHARM_STORE_USER}
17+
18+publish-charm-store: check-env render
19+ ./charm-store publish-latest $${CHARM_STORE_USER}
20+
21+check-env:
22+ifndef CHARM_STORE_USER
23+ $(error CHARM_STORE_USER is undefined, hint: launchpad id.)
24+endif
25+
26+clean:
27+ @rm -rf build
28+
29+render: deps clean
30+ @./render-bundles
31+
32+update-charm-revisions:
33+ @./update-charm-revisions \
34+ $(EXTRA_UPDATE_ARGUMENTS) \
35+ apache2 postgresql juju-gui haproxy rabbitmq-server nfs
36+
37+deps:
38+ @./ubuntu-deps
39+
40+.PHONY: clean render commit-charm-store update-charm-revisions compare-charm-store deps
41
42=== renamed file 'Makefile' => 'Makefile.moved'
43=== added file 'README.md'
44--- README.md 1970-01-01 00:00:00 +0000
45+++ README.md 2016-06-07 14:03:21 +0000
46@@ -0,0 +1,28 @@
47+Overview
48+========
49+
50+This branch contains the necessary config and instructions for using
51+juju-deployer/juju-quickstart to deploy the landscape charm.
52+
53+Deployment should be straightforward.
54+
55+Dense Deployment - MAAS
56+=======================
57+For MAAS where LXCs can be addressed externally, you can deploy to a single
58+machine while at the same time making the service scalable in the future:
59+
60+ juju quickstart u/landscape/landscape-dense-maas/
61+
62+Dense Deployment - Other
63+========================
64+For other substrates, use the plain dense deployment which allows your
65+landscape server to be fully reachable, but will not allow easy scaling
66+should load increase.
67+
68+ juju quickstart u/landscape/landscape-dense/
69+
70+Scalable Deployment
71+===================
72+For a truly scalable deployment, the following stanza should be used.
73+
74+ juju quickstart u/landscape/landscape-scalable
75
76=== renamed file 'README.md' => 'README.md.moved'
77=== added file 'charm-store'
78--- charm-store 1970-01-01 00:00:00 +0000
79+++ charm-store 2016-06-07 14:03:21 +0000
80@@ -0,0 +1,70 @@
81+#!/bin/bash -e
82+#
83+# Mostly intended to be called with make targets
84+# Needs make clean, make render called first.
85+#
86+
87+ACTION=$1
88+STORE_USER=${2:-landscape}
89+
90+if [ -z "$ACTION" ]; then
91+ cat <<EOF
92+Usage: $0 ACTION [user]
93+ actions:
94+ push - push to 'unpublished' channel
95+ publish-latest - publish the latest copy
96+ diff - diff your branch to the latest stable channel copy
97+ user:
98+ charm store user name
99+EOF
100+ exit 1
101+fi
102+
103+if [ "$ACTION" == "push" ]; then
104+ echo "# Will be pushing new [unpublished] versions to the charm store"
105+ echo "# as user: $STORE_USER"
106+fi
107+
108+for target in landscape-dense-maas landscape-dense landscape-scalable; do
109+
110+ if [ "$ACTION" == "diff" ]; then
111+ echo "# [$target] Pulling fresh copy from stable channel"
112+ charm pull --channel stable "cs:~${STORE_USER}/bundle/${target}" build/${target}-stable
113+
114+ echo "# [$target] Diff from latest stable"
115+ diff -Naur build/${target}-stable build/${target} || /bin/true
116+ fi
117+
118+ if [ "$ACTION" == "push" ]; then
119+ echo "# [$target] Pushing to namespace ~${STORE_USER}, unpublished channel"
120+ url=$(charm push build/${target} cs:~${STORE_USER}/bundle/${target} | grep ^url | awk '{ print $2 }')
121+
122+ echo "# [$target] Publishing to development channel"
123+ charm publish --channel development $url
124+ fi
125+
126+ if [ "$ACTION" == "publish-latest" ]; then
127+ latest=$(charm show --channel unpublished --format=json cs:~${STORE_USER}/bundle/${target} | jq -r '.["revision-info"].Revisions[0]')
128+ echo "# [$target] Publishing latest unpublished revision, stable channel"
129+ charm publish $latest
130+ fi
131+
132+done
133+
134+cat <<EOF
135+#
136+# You can manually examine things if you wish:"
137+# ll build/*"
138+# ll build/*-stable"
139+#
140+# Show details in the store:
141+# charm show [--channel unpublished] cs:~${STORE_USER}/bundle/landscape-dense-maas
142+#
143+# Make sure everyone can use your charm if you want:
144+# charm grant cs:~${STORE_USER}/bundle/BUNDLE_NAME-VERSION everyone
145+#
146+# Publish like this (controls what clients see by default, you can
147+# even set it to a previous known good version):
148+# charm publish cs:~${STORE_USER}/bundle/BUNDLE_NAME-VERSION
149+#
150+EOF
151
152=== added file 'landscape-template.jinja2'
153--- landscape-template.jinja2 1970-01-01 00:00:00 +0000
154+++ landscape-template.jinja2 2016-06-07 14:03:21 +0000
155@@ -0,0 +1,99 @@
156+series: xenial
157+services:
158+ rabbitmq-server:
159+ charm: cs:xenial/rabbitmq-server-0
160+ {% if rabbitmq["to"] %}
161+ to:
162+ - {{ rabbitmq["to"] }}
163+ {% endif %}
164+ num_units: 1
165+ annotations:
166+ "gui-x": "600"
167+ "gui-y": "370"
168+ postgresql:
169+ charm: cs:xenial/postgresql-99
170+ {% if postgresql["memory"] %}
171+ constraints: mem={{ postgresql["memory"] }}
172+ {% endif %}
173+ {% if postgresql["to"] %}
174+ to:
175+ - {{ postgresql["to"] }}
176+ {% endif %}
177+ num_units: 1
178+ options:
179+ extra_packages: python-apt postgresql-contrib postgresql-.*-debversion postgresql-plpython-.*
180+ max_connections: {{ postgresql.max_connections }}
181+ max_prepared_transactions: {{ postgresql.max_connections }}
182+ {% if postgresql.manual_tuning %}
183+ performance_tuning: manual
184+ {% endif %}
185+ {% if postgresql.shared_buffers %}
186+ shared_buffers: {{ postgresql.shared_buffers }}
187+ {% endif %}
188+ {% if postgresql.checkpoint_segments %}
189+ checkpoint_segments: {{ postgresql.checkpoint_segments }}
190+ {% endif %}
191+ {% if postgresql.maintenance_work_mem %}
192+ maintenance_work_mem: {{ postgresql.maintenance_work_mem }}
193+ {% endif %}
194+ {% if postgresql.work_mem %}
195+ work_mem: {{ postgresql.work_mem }}
196+ {% endif %}
197+ {% if postgresql.effective_cache_size %}
198+ effective_cache_size: {{ postgresql.effective_cache_size }}
199+ {% endif %}
200+ annotations:
201+ "gui-x": "600"
202+ "gui-y": "120"
203+ haproxy:
204+ charm: cs:trusty/haproxy-19
205+ {% if haproxy["to"] %}
206+ to:
207+ - {{ haproxy["to"] }}
208+ {% endif %}
209+ expose: True
210+ num_units: 1
211+ options:
212+ enable_monitoring: True
213+ monitoring_allowed_cidr: "0.0.0.0/0"
214+ monitoring_password: "haproxy"
215+ default_timeouts: "queue 60000, connect 5000, client 120000, server 120000"
216+ # Don't deploy default haproxy service on port 80
217+ services: ""
218+ source: backports
219+ ssl_cert: SELFSIGNED
220+ annotations:
221+ "gui-x": "1200"
222+ "gui-y": "120"
223+ landscape-server:
224+ {% if landscape["branch"] %}
225+ branch: {{ landscape["branch"] }}
226+ {% else %}
227+ charm: {{ landscape["charm"] }}
228+ {% endif %}
229+ {% if landscape["memory"] %}
230+ constraints: mem={{ landscape["memory"] }}
231+ {% endif %}
232+ {% if landscape["to"] %}
233+ to:
234+ - {{ landscape["to"] }}
235+ {% endif %}
236+ num_units: 1
237+ options:
238+ source: {{ landscape["source"] }}
239+ key: {{ landscape["key"] }}
240+ {% if landscape["ssl-cert"] %}
241+ ssl-cert: {{ landscape["ssl-cert"] }}
242+ ssl-key: {{ landscape["ssl-key"] }}
243+ {% endif %}
244+ annotations:
245+ "gui-x": "950"
246+ "gui-y": "120"
247+{% if landscape["to"] %}
248+machines:
249+ "0": {}
250+{% endif %}
251+relations:
252+ - [landscape-server, rabbitmq-server]
253+ - [landscape-server, haproxy]
254+ - ["landscape-server:db", "postgresql:db-admin"]
255
256=== added file 'render-bundles'
257--- render-bundles 1970-01-01 00:00:00 +0000
258+++ render-bundles 2016-06-07 14:03:21 +0000
259@@ -0,0 +1,80 @@
260+#!/usr/bin/python3
261+"""Render the landscape-server bundles."""
262+
263+import argparse
264+import os
265+import shutil
266+
267+from jinja2 import FileSystemLoader, Environment
268+
269+DEFAULTS = {
270+ "rabbitmq": {},
271+ "postgresql": {
272+ "max_connections": 500,
273+ "max_prepared_transactions": 500,
274+ "memory": 2048},
275+ "haproxy": {},
276+ "landscape": {
277+ "charm": "cs:~davidpbritton/xenial/landscape-server",
278+ "memory": 2048,
279+ "source":
280+ "deb http://ppa.launchpad.net/landscape/16.03/ubuntu trusty main",
281+ "key": "4652B4E6"}
282+}
283+
284+FLAVORS = [
285+ # scalable
286+ {"name": "scalable"},
287+
288+ # dense
289+ {"name": "dense",
290+ "rabbitmq": {
291+ "to": "lxc:0"},
292+ "postgresql": {
293+ "to": "lxc:0"},
294+ "haproxy": {
295+ "to": "0"},
296+ "landscape": {
297+ "to": "lxc:0"}},
298+
299+ # dense-maas
300+ {"name": "dense-maas",
301+ "rabbitmq": {
302+ "to": "lxc:0"},
303+ "postgresql": {
304+ "to": "lxc:0"},
305+ "haproxy": {
306+ "to": "lxc:0"},
307+ "landscape": {
308+ "to": "lxc:0"}},
309+]
310+
311+if __name__ == "__main__":
312+ current_dir = os.path.dirname(__file__)
313+ parser = argparse.ArgumentParser(description=__doc__)
314+ parser.add_argument("--landscape-branch", type=str, required=False)
315+ parser.add_argument("--landscape-charm", type=str, required=False)
316+ args = parser.parse_args()
317+ environment = Environment(
318+ loader=FileSystemLoader(current_dir),
319+ trim_blocks=True, lstrip_blocks=True,
320+ keep_trailing_newline=True)
321+ template = environment.get_template("landscape-template.jinja2")
322+ for flavor in FLAVORS:
323+ build_dir = os.path.join(current_dir, "build")
324+ path_parts = [build_dir, "landscape-%s" % flavor["name"]]
325+ os.makedirs(os.path.join(*path_parts))
326+ shutil.copy("README.md", os.path.join(*path_parts))
327+
328+ path_parts.append("bundle.yaml")
329+ with open(os.path.join(*path_parts), "w") as fd:
330+ context = DEFAULTS.copy()
331+ for key in context.keys():
332+ context[key].update(flavor.get(key, {}))
333+ context["name"] = flavor["name"]
334+ if args.landscape_charm:
335+ context["landscape"]["charm"] = args.landscape_charm
336+ if args.landscape_branch:
337+ context["landscape"]["branch"] = args.landscape_branch
338+ fd.write(template.render(context))
339+ print("Generated bundles in {}/...".format(build_dir))
340
341=== added file 'ubuntu-deps'
342--- ubuntu-deps 1970-01-01 00:00:00 +0000
343+++ ubuntu-deps 2016-06-07 14:03:21 +0000
344@@ -0,0 +1,53 @@
345+#!/bin/bash -u
346+
347+set -u
348+
349+INTERACTIVE=0
350+tty -s && INTERACTIVE=1
351+
352+function apt_get() {
353+ local skip=0
354+
355+ # first check if this is necessary - we don't want to ask for sudo
356+ # unless we need it, since this is run from make build-devel
357+ output=$(apt-get -s $*)
358+ if [ $? -ne 0 ]; then
359+ echo "Error: Dependency simulation failed: $*"
360+ exit 1
361+ fi
362+
363+ # Check for any lines that start with Inst, which signifies
364+ # a package will be installed or upgraded
365+ echo "$output" | grep '^Inst ' > /dev/null || skip=1
366+
367+ if [ $skip -eq 1 ]; then
368+ echo " * Skipping: $*"
369+ return
370+ fi
371+
372+ if [ $INTERACTIVE -eq 0 ]; then
373+ DEBIAN_FRONTEND=noninteractive sudo apt-get \
374+ -y --force-yes -o Dpkg::Options::='--force-confold' $*
375+ else
376+ sudo apt-get $*
377+ fi
378+
379+ if [ $? -ne 0 ]; then
380+ echo "Error: Package installation failed: $*"
381+ exit 1
382+ fi
383+}
384+
385+
386+function install_deps {
387+ apt_get install \
388+ python3-jinja2 \
389+ jq
390+}
391+
392+
393+# If running non-interactively, go ahead and apt-get update
394+# before we start, keeps jenkins slaves and the like updated
395+[ $INTERACTIVE -eq 0 ] && sudo apt-get update
396+
397+install_deps
398
399=== added file 'update-charm-revisions'
400--- update-charm-revisions 1970-01-01 00:00:00 +0000
401+++ update-charm-revisions 2016-06-07 14:03:21 +0000
402@@ -0,0 +1,98 @@
403+#!/usr/bin/python3
404+
405+import argparse
406+import fileinput
407+import re
408+import sys
409+from urllib.request import urlopen
410+from yaml import load
411+from glob import glob
412+
413+
414+class Charm(object):
415+
416+ def __init__(self, charm_name, series):
417+ """Create a charm object.
418+ @param charm_name: name of charm
419+ """
420+ reference = "cs:{}/{}".format(series, charm_name)
421+ base_url = "https://store.juju.ubuntu.com/charm-info?charms="
422+ url = "{}{}".format(base_url, reference)
423+ response = urlopen(url)
424+ self.charm_data = load(response)[reference]
425+ self.name = charm_name
426+ if "errors" in self.charm_data:
427+ raise IOError("{}: {}".format(
428+ charm_name, self.charm_data["errors"]))
429+ self.revision = self.charm_data["revision"]
430+ self.store_url = "cs:{}/{}-{}".format(series, self.name, self.revision)
431+
432+
433+def _get_charm(charm_name, series):
434+ """
435+ Small wrapper to try to get the series charm you specify. Falls back
436+ to precise if you specified something else
437+ """
438+ try:
439+ return Charm(charm_name, series)
440+ except IOError as e:
441+ if series != "precise":
442+ try:
443+ return Charm(charm_name, series="precise")
444+ except IOError as precise_e:
445+ raise IOError(
446+ "%s: not found? (even tried precise): {}, {}".format(
447+ charm_name, e, precise_e))
448+ raise
449+
450+
451+def replace_in_config(filename, charms, series):
452+ """
453+ Iterate over each charm, replacing all occurences of old charm store
454+ urls with new versions. Intent is to leave file in a state that can
455+ be tested and checked in if successful.
456+
457+ Look for lines like:
458+ charm: cs:trusty/juju-gui-83
459+
460+ Or:
461+ series: trusty
462+ """
463+ for line in fileinput.input(filename, inplace=1):
464+ pattern = "^(\s*)series:\s.*$"
465+ line = re.sub(pattern, r"\1series: %s" % series, line)
466+ for charm in charms:
467+ pattern = "cs:[^/]+/{}-[0-9]+".format(charm.name)
468+ line = re.sub(pattern, charm.store_url, line)
469+ sys.stdout.write(line)
470+
471+ print("# Config written, use `bzr diff %s` to see any changes" % filename)
472+
473+
474+def get_options():
475+ """Parse and return command line options."""
476+ description = "Put new charmstore descriptors into a deployer file."
477+ parser = argparse.ArgumentParser(description=description)
478+ parser.add_argument("charms", help="List charms to update", nargs='*')
479+ parser.add_argument("--series", help="Charm series", default="xenial")
480+ return parser.parse_args()
481+
482+
483+def main():
484+ options = get_options()
485+ charms = []
486+ if len(options.charms):
487+ print("# Latest upstream versions of charms ({}):".format(
488+ options.series))
489+ for charm_name in options.charms:
490+ charm = _get_charm(charm_name, series=options.series)
491+ print("# {}: {}".format(charm_name, charm.revision))
492+ charms.append(charm)
493+
494+ for filename in glob("*.jinja2"):
495+ replace_in_config(filename, charms, series=options.series)
496+
497+ sys.exit(0)
498+
499+if __name__ == "__main__":
500+ main()

Subscribers

People subscribed via source and target branches