Merge bootstack-ops:jjo-juju_bundle_export-juju_12 into bootstack-ops:master

Proposed by JuanJo Ciarlante
Status: Merged
Merged at revision: b7e3fc8841b07b25c21e1403e29d2e0d4d303646
Proposed branch: bootstack-ops:jjo-juju_bundle_export-juju_12
Merge into: bootstack-ops:master
Diff against target: 138 lines (+54/-18)
1 file modified
ops-bundle/scripts/juju_bundle_export.py (+54/-18)
Reviewer Review Type Date Requested Status
Peter Sabaini (community) Approve
Review via email: mp+320244@code.launchpad.net

Commit message

[jjo] add juju2 support, verified working ok (juju-deployer --diff w/minimals) on both juju1,2

Description of the change

[jjo] add juju2 support, verified working ok (juju-deployer --diff w/minimals) on both juju1,2

To post a comment you must log in.
Revision history for this message
JuanJo Ciarlante (jjo) wrote :

FYI tested on both juju versions as:
v1:
  ./scripts/juju_bundle_export.py -o env.yaml -o env.codetree
  JUJU_DEPLOYER=~/bootstack-*lab/charms
  juju-deployer --diff -c env.yaml

v2:
  ./scripts/juju_bundle_export.py -o env.yaml -o env.codetree
  JUJU_DEPLOYER=~/charms
  juju-deployer --diff -c env.yaml

Revision history for this message
Peter Sabaini (peter-sabaini) wrote :

Lgtm in general, some minor comments inline

review: Approve
Revision history for this message
JuanJo Ciarlante (jjo) wrote :

Thanks Peter for the review, will address your comments.

Revision history for this message
JuanJo Ciarlante (jjo) wrote :

@chrome0: addressed comments, PTAL

Revision history for this message
Peter Sabaini (peter-sabaini) wrote :

Coolbeans, +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/ops-bundle/scripts/juju_bundle_export.py b/ops-bundle/scripts/juju_bundle_export.py
2index 1fd6487..8256cdf 100755
3--- a/ops-bundle/scripts/juju_bundle_export.py
4+++ b/ops-bundle/scripts/juju_bundle_export.py
5@@ -24,8 +24,7 @@ import yaml
6 import argparse
7 import re
8 import requests
9-from jujuclient import Environment
10-from deployer import utils
11+from deployer import (utils, env)
12
13 logging.basicConfig()
14 logger = logging.getLogger()
15@@ -38,7 +37,7 @@ CHARM_DIR_MAP = {
16
17
18 def charmstore_get(series, charm):
19- cs_reply = requests.get('https://api.jujucharms.com/v4/search', params = {
20+ cs_reply = requests.get('https://api.jujucharms.com/v4/search', params={
21 'name': charm,
22 'series': series,
23 })
24@@ -52,37 +51,75 @@ def charmstore_get(series, charm):
25 class Bundle(object):
26 def __init__(self, args):
27 self.args = args
28+
29 self.env_name = utils.get_env_name(args.env_name)
30- self.env = Environment.connect(self.env_name)
31+ self.env = env.select_runtime(self.env_name, None)
32+ logger.debug('Using runtime %s on %s', env.__class__.__name__, self.env_name)
33+ self.env.connect()
34 self.env._debug = args.debug
35 self.deploy = {}
36 self.codetree = {}
37
38+ # Below two methods mostly stolen from deployer/action/diff.py,
39+ # as juju2 doesn't have a relations dict, need to build it from
40+ # each service iteration
41+ def _get_rel_name(self, src, tgt):
42+ if not self.env_status:
43+ logger.warning("_get_rel_name called without initialized env_status")
44+ return None
45+ svc_rels = self.env_status['services'][tgt]['relations']
46+ for r, eps in svc_rels.items():
47+ if src in eps:
48+ return r
49+ return None
50+
51+ def _load_rels(self, svc_name):
52+ rels = set()
53+ svc_rels = self.env_status['services'][svc_name].get(
54+ 'relations', {})
55+ # There is ambiguity here for multiple rels between two
56+ # services without the relation id, which we need support
57+ # from core for.
58+ for r_name, r_svcs in svc_rels.items():
59+ for r_svc in r_svcs:
60+ # Skip peer relations
61+ if r_svc == svc_name:
62+ continue
63+ rr_name = self._get_rel_name(svc_name, r_svc)
64+ rels.add(
65+ tuple(sorted([
66+ "%s:%s" % (svc_name, r_name),
67+ "%s:%s" % (r_svc, rr_name)] if rr_name else r_svc)))
68+ return rels
69+
70 def export(self):
71- stat = self.env.get_stat()
72+ self.env_status = self.env.status()
73 services = {}
74- relations = []
75- for service_name, service_val in stat.get('Services', {}).items():
76- units = service_val.get('Units', None)
77- subord_to = service_val.get('SubordinateTo')
78+ relations = set()
79+ subordto_key = [None, 'SubordinateTo', 'subordinate-to'][self.env.juju_version]
80+ charm_key = [None, 'Charm', 'charm'][self.env.juju_version]
81+ # print( yaml.dump(self.env_status.get('services'), default_flow_style=False))
82+ for service_name, service_val in self.env_status.get('services', {}).items():
83+ units = service_val.get('units', None)
84+ subord_to = service_val.get(subordto_key)
85 # Subordinate units show no Units
86 if units or subord_to:
87- charm = '-'.join(service_val['Charm'].split('-')[0:-1])
88+ charm = '-'.join(service_val[charm_key].split('-')[0:-1])
89 service = {
90 'charm': charm
91 }
92 if units:
93 service['num_units'] = len(units)
94 if not self.args.minimal:
95- config = self.env.get_service(service_name).get('Config', {})
96+ config = self.env.get_config(service_name)
97 options = {k: v['value'] for k, v in config.items()
98 if not v.get('default', False)}
99 if options:
100 service['options'] = options
101 services[service_name] = service
102- for relation in stat.get('Relations', []):
103- if len(relation.get('Endpoints')) == 2:
104- relations.append(relation.get('Key').split(' '))
105+ relations.update(self._load_rels(service_name))
106+ relations = [list(rel) for rel in sorted(relations)]
107+
108 self.deploy = {
109 'services': services,
110 'relations': relations,
111@@ -94,8 +131,7 @@ class Bundle(object):
112 self.local_charm_url_map = {}
113 bootstack_dir = self.args.bootstackdir.format(env_name=self.env_name)
114 bs_codetree_file = os.path.join(bootstack_dir,
115- "customer/configs/bootstack-charms.bzr")
116- logger.info("foo")
117+ "customer/configs/bootstack-charms.bzr")
118 if (os.path.exists(bs_codetree_file)):
119 with open(bs_codetree_file) as bs_ct_f:
120 for line in bs_ct_f:
121@@ -112,7 +148,7 @@ class Bundle(object):
122
123 def local_charm_dir(self, charm_dir):
124 if self.local_charms_dir and os.path.exists(
125- os.path.join(self.local_charms_dir, charm_dir)):
126+ os.path.join(self.local_charms_dir, charm_dir)):
127 return os.path.join(self.local_charms_dir, charm_dir)
128 return None
129
130@@ -121,7 +157,7 @@ class Bundle(object):
131 for service, service_val in self.deploy['services'].items():
132 charm_url = service_val['charm']
133 if charm_url.startswith('local:'):
134- service_val['charm'] = self.get_charm_local_url(service, charm_url)
135+ service_val['charm'] = self.get_charm_local_url(service, charm_url)
136
137 def get_charm_local_url(self, service, charm_url):
138 """Return a line for codetree, in the form of

Subscribers

People subscribed via source and target branches

to all changes: