Merge lp:~fginther/charms/trusty/jenkaas/configure-slaves into lp:~canonical-ci-engineering/charms/trusty/jenkaas/trunk

Proposed by Francis Ginther
Status: Needs review
Proposed branch: lp:~fginther/charms/trusty/jenkaas/configure-slaves
Merge into: lp:~canonical-ci-engineering/charms/trusty/jenkaas/trunk
Diff against target: 142 lines (+71/-2) (has conflicts)
2 files modified
hooks/actions.py (+26/-1)
hooks/services.py (+45/-1)
Text conflict in hooks/actions.py
Text conflict in hooks/services.py
To merge this branch: bzr merge lp:~fginther/charms/trusty/jenkaas/configure-slaves
Reviewer Review Type Date Requested Status
Para Siva (community) Approve
Joe Talbott (community) Approve
Review via email: mp+262618@code.launchpad.net

Commit message

Adds a slave_manager to connect other nodes via the jenkaas-slave relation.

Description of the change

Adds a slave_manager to connect other nodes via the jenkaas-slave relation.

Configuring a slave requires the jenkins service to be running (and not just starting up). I didn't think this fit well with the existing service manager as all of those actions should take place while the service is stopped. So, I created a separate service manager, slave_manager, specifically for handling actions as a result of relation changes. This charm only supports a single relation (jenkaas-slave) so it's assumed that this is the relation being managed.

The InRelation and NotInRelation classes were created to fit within the service managers "required_data" usage.

To post a comment you must log in.
11. By Francis Ginther

Remove debug logging.

Revision history for this message
Joe Talbott (joetalbott) wrote :

I'm not a fan of the InRelation and NotInRelation classes (since they are essentially a method call) but if that's the only way then so be it.

review: Approve
Revision history for this message
Para Siva (psivaa) wrote :

Looks good except an inline comment about an unused import.

A little bit curious about if we could not use 'start' callbacks in the first ServiceManager instance for creating the slave. By then the service will have started, i guess.

review: Approve
12. By Francis Ginther

flake8 cleanup.

Revision history for this message
Francis Ginther (fginther) wrote :

> I'm not a fan of the InRelation and NotInRelation classes (since they are
> essentially a method call) but if that's the only way then so be it.

I dug some more on this and think I can see a way to do this inside the 'data_ready' list directly without creating the separate class. Let me see if I can get this to work while resolving the merge conflicts.

Revision history for this message
Francis Ginther (fginther) wrote :

> Looks good except an inline comment about an unused import.

Thanks. Ran flake8 and resolved 2 issues including the unused import.

> A little bit curious about if we could not use 'start' callbacks in the first
> ServiceManager instance for creating the slave. By then the service will have
> started, i guess.

Adding 'start' callbacks would be a way to make sure configure_slaves only runs after the jenkins service is started, but there would have to be a delay between the two as it takes jenkins a few seconds to be responsive. If this becomes a problem for the slave_manager, it could be addressed by adding a 'required_data' callback to ensure that jenkins is started and responding. After working with this for a while, I think it's easier to keep the relation and non-relation hooks handled separately, you don't need to re-install plugins when adding a slave for example.

Revision history for this message
Para Siva (psivaa) wrote :

> Adding 'start' callbacks would be a way to make sure configure_slaves only
> runs after the jenkins service is started, but there would have to be a delay
> between the two as it takes jenkins a few seconds to be responsive. If this
> becomes a problem for the slave_manager, it could be addressed by adding a
> 'required_data' callback to ensure that jenkins is started and responding.
> After working with this for a while, I think it's easier to keep the relation
> and non-relation hooks handled separately, you don't need to re-install
> plugins when adding a slave for example.
This makes a lot of sense. Thanks for the explanation. +1 from me.

Unmerged revisions

12. By Francis Ginther

flake8 cleanup.

11. By Francis Ginther

Remove debug logging.

10. By Francis Ginther

Remove broken and changed hooks as they are just repeating the departed and joined events and clean up the code around creating and deleting a node.

9. By Francis Ginther

Add missing jenkaas-slave-relation-broken and jenkaas-slave-relation-departed symlinks.

8. By Francis Ginther

Create a slave_manager to handle the relations.

7. By Francis Ginther

First pass at connecting and disconnecting slaves.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'hooks/actions.py'
--- hooks/actions.py 2015-06-22 16:56:46 +0000
+++ hooks/actions.py 2015-06-23 13:32:12 +0000
@@ -12,10 +12,15 @@
1212
13SERVICE_NAME = 'jenkaas'13SERVICE_NAME = 'jenkaas'
14SERVICE_CONFIGNAME = 'jenkaas.conf'14SERVICE_CONFIGNAME = 'jenkaas.conf'
15<<<<<<< TREE
15DEPS_PKGES = [16DEPS_PKGES = [
16 "daemon", "adduser", "psmisc", "default-jre",17 "daemon", "adduser", "psmisc", "default-jre",
17 "pwgen",18 "pwgen",
18 ]19 ]
20=======
21DEPS_PKGES = ["daemon", "adduser", "psmisc", "default-jre",
22 "pwgen", "python-jenkins"]
23>>>>>>> MERGE-SOURCE
1924
20config = hookenv.config()25config = hookenv.config()
2126
@@ -63,7 +68,8 @@
63 hookenv.log('Installing jenkins config')68 hookenv.log('Installing jenkins config')
64 in_config = os.path.join(hookenv.charm_dir(),69 in_config = os.path.join(hookenv.charm_dir(),
65 'files/templates/config.xml')70 'files/templates/config.xml')
66 shutil.copy(in_config, _service_dir())71 if not os.path.exists(os.path.join(_service_dir(), 'config.xml')):
72 shutil.copy(in_config, _service_dir())
6773
6874
69def configure_default_user(service_name):75def configure_default_user(service_name):
@@ -95,6 +101,7 @@
95101
96def install_slaves(service_name):102def install_slaves(service_name):
97 hookenv.log('Installing slaves')103 hookenv.log('Installing slaves')
104<<<<<<< TREE
98 hookenv.log(hookenv.relations())105 hookenv.log(hookenv.relations())
99106
100107
@@ -129,3 +136,21 @@
129136
130def start_jenkins(service_name):137def start_jenkins(service_name):
131 host.service_start('jenkins')138 host.service_start('jenkins')
139=======
140 node = hookenv.remote_unit().replace('/', '-')
141 hookenv.log('Configuring slave: {}'.format(node))
142
143 import jenkins
144 j = jenkins.Jenkins('http://localhost:8080',
145 username=config['username'],
146 password=config['password'])
147
148 if (hookenv.hook_name().endswith('joined') or
149 hookenv.hook_name().endswith('changed')):
150 hookenv.log('Creating slave: {}'.format(node))
151 j.create_node(node,
152 launcher='hudson.slaves.JNLPLauncher')
153 else:
154 hookenv.log('Deleting slave: {}'.format(node))
155 j.delete_node(node)
156>>>>>>> MERGE-SOURCE
132157
=== removed symlink 'hooks/jenkaas-slave-relation-changed'
=== target was u'hooks.py'
=== added symlink 'hooks/jenkaas-slave-relation-departed'
=== target is u'hooks.py'
=== modified file 'hooks/services.py'
--- hooks/services.py 2015-06-22 16:56:46 +0000
+++ hooks/services.py 2015-06-23 13:32:12 +0000
@@ -14,10 +14,34 @@
14 def provide_data(self):14 def provide_data(self):
15 return {15 return {
16 'master-address': hookenv.unit_get('private-address'),16 'master-address': hookenv.unit_get('private-address'),
17 'port': 8080,17 'username': hookenv.config('username'),
18 'password': hookenv.config('password'),
18 }19 }
1920
2021
22class InRelation(dict):
23 '''This is used to seprate the hooks into relation and non-relation.'''
24 def __init__(self):
25 hookenv.log('InRelation: {}'.format(hookenv.in_relation_hook()))
26
27 def __bool__(self):
28 return hookenv.in_relation_hook()
29
30 __nonzero__ = __bool__
31
32
33class NotInRelation(dict):
34 '''This is used to seprate the hooks into relation and non-relation.'''
35 def __init__(self):
36 hookenv.log('InRelation: {}'.format(hookenv.in_relation_hook()))
37
38 def __bool__(self):
39 hookenv.log('NotInRelation: {}'.format(not hookenv.in_relation_hook()))
40 return not hookenv.in_relation_hook()
41
42 __nonzero__ = __bool__
43
44
21def manage():45def manage():
22 config = hookenv.config()46 config = hookenv.config()
23 manager = ServiceManager([47 manager = ServiceManager([
@@ -25,6 +49,7 @@
25 'service': 'jenkaas',49 'service': 'jenkaas',
26 'required_data': [50 'required_data': [
27 config,51 config,
52 NotInRelation(),
28 ],53 ],
29 'provided_data': [MasterToSlaveProvider()],54 'provided_data': [MasterToSlaveProvider()],
30 'data_ready': [55 'data_ready': [
@@ -37,11 +62,30 @@
37 actions.create_example_job,62 actions.create_example_job,
38 actions.install_jenkins_config,63 actions.install_jenkins_config,
39 actions.configure_default_user,64 actions.configure_default_user,
65<<<<<<< TREE
40 actions.install_slaves,66 actions.install_slaves,
67=======
68 render_template(
69 source='upstart.conf',
70 target='/etc/init/jenkaas.conf'),
71>>>>>>> MERGE-SOURCE
41 actions.log_start,72 actions.log_start,
42 ],73 ],
43 'start': actions.start_jenkins,74 'start': actions.start_jenkins,
44 'ports': [8080],75 'ports': [8080],
45 },76 },
46 ])77 ])
78 slave_manager = ServiceManager([
79 {
80 'service': 'jenkaas',
81 'required_data': [
82 config,
83 InRelation(),
84 ],
85 'data_ready': [
86 actions.install_slaves,
87 ],
88 },
89 ])
47 manager.manage()90 manager.manage()
91 slave_manager.manage()

Subscribers

People subscribed via source and target branches