Merge lp:~cjwatson/charms/trusty/turnip/code-in-swift into lp:~canonical-launchpad-branches/charms/trusty/turnip/devel

Proposed by Colin Watson
Status: Rejected
Rejected by: Colin Watson
Proposed branch: lp:~cjwatson/charms/trusty/turnip/code-in-swift
Merge into: lp:~canonical-launchpad-branches/charms/trusty/turnip/devel
Diff against target: 170 lines (+111/-4)
2 files modified
config.yaml (+28/-0)
hooks/actions.py (+83/-4)
To merge this branch: bzr merge lp:~cjwatson/charms/trusty/turnip/code-in-swift
Reviewer Review Type Date Requested Status
Launchpad code reviewers Pending
Review via email: mp+262198@code.launchpad.net

Commit message

Add support for fetching turnip payload from Swift.

Description of the change

Add support for fetching turnip payload from Swift.

I haven't actually tested this yet, but it will be a lot easier to do on qastaging than locally! The code is modelled reasonably closely on that in the certification charm (lp:~gnuoy/canonical-is-charms/certification-python), so it should be more or less right.

To post a comment you must log in.
Revision history for this message
Kit Randel (blr) wrote :

LGTM, although would it be worth factoring out the name of the tarball?

82. By Colin Watson

Factor out tarball name.

Revision history for this message
Colin Watson (cjwatson) wrote :

This has long since been superseded by the in-tree charm.

Unmerged revisions

82. By Colin Watson

Factor out tarball name.

81. By Colin Watson

Add support for fetching turnip payload from Swift.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'config.yaml'
2--- config.yaml 2015-05-22 15:42:11 +0000
3+++ config.yaml 2015-06-18 13:52:10 +0000
4@@ -37,6 +37,10 @@
5 type: string
6 default: '19417'
7 description: API port.
8+ code_src:
9+ type: string
10+ default: 'local'
11+ description: Code source: 'local' or 'swift'.
12 revision:
13 type: string
14 default: '1'
15@@ -120,6 +124,30 @@
16 description: |
17 Hosts that should be allowed to rsync logs. Note that this relies on
18 basenode.
19+ swift_username:
20+ type: string
21+ default: ""
22+ description: Username to use when accessing Swift.
23+ swift_password:
24+ type: string
25+ default: ""
26+ description: Password to use when accessing Swift.
27+ swift_auth_url:
28+ type: string
29+ default: ""
30+ description: URL for authenticating against Keystone.
31+ swift_region_name:
32+ type: string
33+ default: ""
34+ description: Swift region.
35+ swift_tenant_name:
36+ type: string
37+ default: ""
38+ description: Entity that owns resources.
39+ swift_container_name:
40+ type: string
41+ default: ""
42+ description: Container to put objects in.
43
44 # apt configuration used by charmhelpers.
45 install_sources:
46
47=== modified file 'hooks/actions.py'
48--- hooks/actions.py 2015-05-22 15:42:11 +0000
49+++ hooks/actions.py 2015-06-18 13:52:10 +0000
50@@ -1,5 +1,6 @@
51 import base64
52 import grp
53+import hashlib
54 import os
55 import pwd
56 import shutil
57@@ -39,6 +40,7 @@
58 LOGS_DIR = os.path.join(BASE_DIR, 'logs')
59 DATA_DIR = os.path.join(BASE_DIR, 'data')
60 KEY_DIR = os.path.join(BASE_DIR, 'keys')
61+CODE_TARBALL = 'turnip.tar.gz'
62
63 CODE_USER = config['code_user']
64 CODE_GROUP = config['code_group']
65@@ -87,16 +89,90 @@
66 host.add_user_to_group(USER, CGIT_GROUP)
67
68
69+def get_swift_creds(config):
70+ return {
71+ 'user': config['swift_username'],
72+ 'project': config['swift_tenant_name'],
73+ 'password': config['swift_password'],
74+ 'authurl': config['swift_auth_url'],
75+ 'region': config['swift_region_name'],
76+ }
77+
78+
79+def swift_base_cmd(**swift_creds):
80+ return [
81+ 'swift',
82+ '--os-username=' + swift_creds['user'],
83+ '--os-tenant-name=' + swift_creds['project'],
84+ '--os-password=' + swift_creds['password'],
85+ '--os-auth-url=' + swift_creds['authurl'],
86+ '--os-region-name=' + swift_creds['region'],
87+ ]
88+
89+
90+def swift_get_etag(name, container=None, **swift_creds):
91+ cmd = swift_base_cmd(**swift_creds) + ['stat', container, name]
92+ file_stat = subprocess.check_output(cmd).splitlines()
93+ for line in file_stat:
94+ words = line.split()
95+ if words[0] == 'ETag:':
96+ return words[1]
97+
98+
99+def swift_fetch(source, target, container=None, **swift_creds):
100+ cmd = swift_base_cmd(**swift_creds) + [
101+ 'download', '--output=' + target, container, source]
102+ subprocess.check_call(cmd)
103+
104+
105+def md5sum(filename):
106+ md5 = hashlib.md5()
107+ with open(filename, 'rb') as f:
108+ for chunk in iter(lambda: f.read(128 * md5.block_size), b''):
109+ md5.update(chunk)
110+ return md5.hexdigest()
111+
112+
113 def unpack_source(service_name):
114 hookenv.log('Deploying source...')
115
116 make_srv_location()
117
118 # Copy source archive
119- archive_path = os.path.join(BASE_DIR, 'turnip.tar.gz')
120+ archive_path = os.path.join(BASE_DIR, CODE_TARBALL)
121+ if os.path.exists(archive_path):
122+ archive_md5sum = md5sum(archive_path)
123+ else:
124+ archive_md5sum = None
125
126- with open(os.path.join(CHARM_FILES_DIR, 'turnip.tar.gz')) as file:
127- host.write_file(archive_path, file.read(), perms=0o644)
128+ if config['code_src'] == 'swift':
129+ swift_creds = get_swift_creds(config)
130+ swift_container = config['swift_container_name']
131+ swift_etag = swift_get_etag(
132+ CODE_TARBALL, container=swift_container, **swift_creds)
133+ if swift_etag is None:
134+ raise Exception(
135+ 'code_src == swift, but %s not found in Swift' % CODE_TARBALL)
136+ if archive_md5sum is not None and swift_etag == archive_md5sum:
137+ hookenv.log(
138+ 'Skipping code deployment: checksum of %s matches checksum '
139+ 'of file in Swift' % archive_path)
140+ return
141+ swift_fetch(
142+ CODE_TARBALL, archive_path, container=swift_container,
143+ **swift_creds)
144+ elif config['code_src'] == 'local':
145+ charm_path = os.path.join(CHARM_FILES_DIR, CODE_TARBALL)
146+ if archive_md5sum is not None and md5sum(charm_path) == archive_md5sum:
147+ hookenv.log(
148+ 'Skipping code deployment: checksum of %s matches checksum '
149+ 'of %s' % (archive_path, charm_path))
150+ return
151+ with open(charm_path) as file:
152+ host.write_file(archive_path, file.read(), perms=0o644)
153+ else:
154+ raise Exception(
155+ "Unsupported code_src value: '%s'" % config['code_src'])
156
157 # Unpack source
158 archive.extract_tarfile(archive_path, CODE_DIR)
159@@ -109,7 +185,10 @@
160 def install_packages(service_name):
161 hookenv.log('Installing system packages...')
162 fetch.configure_sources(update=True)
163- fetch.apt_install(REQUIRED_PACKAGES, fatal=True)
164+ packages = list(REQUIRED_PACKAGES)
165+ if config['code_src'] == 'swift':
166+ packages.append('python-swiftclient')
167+ fetch.apt_install(packages, fatal=True)
168
169
170 def install_python_packages(service_name):

Subscribers

People subscribed via source and target branches

to all changes: