summaryrefslogtreecommitdiff
path: root/hooks
diff options
Diffstat (limited to 'hooks')
-rwxr-xr-xhooks/hooks.py146
l---------hooks/update-status1
2 files changed, 122 insertions, 25 deletions
diff --git a/hooks/hooks.py b/hooks/hooks.py
index d3774a7..9de334d 100755
--- a/hooks/hooks.py
+++ b/hooks/hooks.py
@@ -6,7 +6,9 @@ Created on Aug 1, 2012
'''
import commands
+import json
import os
+import pprint
import re
import signal
import socket
@@ -30,14 +32,15 @@ from string import Template
from textwrap import dedent
from yaml.constructor import ConstructorError
+from charmhelpers.core.decorators import retry_on_exception
+from charmhelpers.payload.execd import execd_preinstall
+
from charmhelpers.fetch import (
add_source,
apt_update,
apt_install
)
-import json
-
from charmhelpers.core.host import (
service,
lsb_release,
@@ -47,6 +50,7 @@ from charmhelpers.core.hookenv import (
close_port,
config,
is_relation_made,
+ log as juju_log,
open_port,
unit_get,
relation_get,
@@ -58,15 +62,12 @@ from charmhelpers.core.hookenv import (
Hooks,
DEBUG,
WARNING,
- is_leader
+ is_leader,
+ status_set,
+ application_version_set,
)
-from charmhelpers.core.hookenv import log as juju_log
-
-from charmhelpers.payload.execd import execd_preinstall
-
from charmhelpers.contrib.hahelpers.cluster import (
- oldest_peer,
peer_units
)
@@ -586,8 +587,8 @@ def remove_replset_from_upstart():
"""
try:
mongodb_init_config = open(default_mongodb_init_config).read()
-
- if re.search(' --replSet', mongodb_init_config,
+
+ if re.search(' --replSet', mongodb_init_config,
re.MULTILINE) is not None:
mongodb_init_config = re.sub(' --replSet .\w+', '',
mongodb_init_config)
@@ -921,6 +922,7 @@ def arm64_trusty_quirk():
def install_hook():
juju_log('Begin install hook.')
execd_preinstall()
+ status_set('maintenance', 'Installing packages')
juju_log("Installing mongodb")
add_source(config('source'), config('key'))
@@ -935,9 +937,9 @@ def install_hook():
@hooks.hook('config-changed')
def config_changed():
juju_log("Entering config_changed")
- print "Entering config_changed"
+ status_set('maintenance', 'Configuring unit')
config_data = config()
- print "config_data: ", config_data
+ juju_log("config_data: {}".format(config_data), level=DEBUG)
mongodb_config = open(default_mongodb_config).read()
# Trigger volume initialization logic for permanent storage
@@ -976,11 +978,12 @@ def config_changed():
current_web_admin_ui_port = int(current_mongodb_port) + 1000
new_web_admin_ui_port = int(config_data['port']) + 1000
- print "current_mongodb_port: ", current_mongodb_port
+ juju_log("Configured mongodb port: {}".format(current_mongodb_port),
+ level=DEBUG)
public_address = unit_get('public-address')
- print "public_address: ", public_address
+ juju_log("unit's public_address: {}".format(public_address), level=DEBUG)
private_address = unit_get('private-address')
- print "private_address: ", private_address
+ juju_log("unit's private_address: {}".format(private_address), level=DEBUG)
# Update mongodb configuration file
mongodb_config = mongodb_conf(config_data)
@@ -1009,6 +1012,7 @@ def config_changed():
write_logrotate_config(config_data)
# restart mongodb
+ status_set('maintenance', 'Restarting mongod')
restart_mongod()
# attach to replSet ( if needed )
@@ -1069,8 +1073,10 @@ def config_changed():
open_port(config_data['mongos_port'])
update_nrpe_config()
+ application_version_set(get_mongod_version())
+ update_status()
- print "About to leave config_changed"
+ juju_log("About to leave config_changed", level=DEBUG)
return(True)
@@ -1148,6 +1154,7 @@ def replica_set_relation_joined():
if enable_replset(my_replset):
juju_log('Restarting mongodb after config change (enable replset)',
level=DEBUG)
+ status_set('maintenance', 'Restarting mongod to enable replicaset')
restart_mongod()
relation_set(relation_id(), {
@@ -1157,6 +1164,8 @@ def replica_set_relation_joined():
'install-order': my_install_order,
'type': 'replset',
})
+
+ update_status()
juju_log("replica_set_relation_joined-finish")
@@ -1165,7 +1174,8 @@ def am_i_primary():
for i in xrange(10):
try:
r = run_admin_command(c, 'replSetGetStatus')
- juju_log('am_i_primary: replSetGetStatus returned: %s' % str(r),
+ pretty_r = pprint.pformat(r)
+ juju_log('am_i_primary: replSetGetStatus returned: %s' % pretty_r,
level=DEBUG)
return r['myState'] == MONGO_PRIMARY
except OperationFailure as e:
@@ -1180,7 +1190,7 @@ def am_i_primary():
# replication not initialized yet (Mongo3.4+)
return False
elif 'not running with --replSet' in str(e):
- # replicaset not configured
+ # replicaset not configured
return False
else:
raise
@@ -1191,6 +1201,56 @@ def am_i_primary():
raise TimeoutException('Unable to determine if local unit is primary')
+def get_replicaset_status():
+ """Connect to mongod and get the status of replicaset
+ This function is used mainly within update_status() to display
+ replicaset status in 'juju status' output
+
+ :returns string: can be any of replicaset states
+ (https://docs.mongodb.com/manual/reference/replica-states/)
+ or can be the string of an exception while getting the status
+ """
+
+ c = MongoClient('localhost')
+ try:
+ r = run_admin_command(c, 'replSetGetStatus')
+ for member in r['members']:
+ if 'self' in member:
+ return member['stateStr']
+
+ # if 'self' was not found in the output, then log a warning and print
+ # the output given by replSetGetStatus
+ r_pretty = pprint.pformat(r)
+ juju_log('get_replicaset_status() failed to get replicaset state:' +
+ r_pretty, level=WARNING)
+ return 'Unknown replica set state'
+
+ except OperationFailure as e:
+ juju_log('get_replicaset_status() exception: %s' % str(e), DEBUG)
+ if 'not running with --replSet' in str(e):
+ return 'not in replicaset'
+ else:
+ return str(e)
+
+def get_mongod_version():
+ """ Connects to mongod and get the db.version() output
+ Mainly used for application_set_version in config-changed hook
+ """
+
+ c = MongoClient('localhost')
+ return c.server_info()['version']
+
+
+# Retry until the replica set is in active state, retry 45 times before failing,
+# wait 1, 2, 3, 4, ... seconds between each retry, this will add 33 minutes of
+# accumulated sleep()
+@retry_on_exception(num_retries=45, base_delay=1)
+def wait_until_replset_is_active():
+ status = update_status()
+ if status != 'active':
+ raise Exception('ReplicaSet not active: {}'.format(status))
+
+
@hooks.hook('replica-set-relation-changed')
def replica_set_relation_changed():
private_address = unit_get('private-address')
@@ -1208,6 +1268,7 @@ def replica_set_relation_changed():
# Initialize the replicaset - we do this only on the leader!
if is_leader():
juju_log('Initializing replicaset')
+ status_set('maintenance', 'Initializing replicaset')
init_replset()
unit = "%s:%s" % (private_address, config('port'))
@@ -1218,9 +1279,11 @@ def replica_set_relation_changed():
juju_log('Adding new secondary... %s' % unit_remote, level=DEBUG)
join_replset(unit, unit_remote)
+ wait_until_replset_is_active()
juju_log('replica_set_relation_changed-finish')
+
@hooks.hook('replica-set-relation-departed')
def replica_set_relation_departed():
juju_log('replica_set_relation_departed-start')
@@ -1263,12 +1326,12 @@ def replica_set_relation_broken():
c = MongoClient('localhost')
r = c.admin.command('isMaster')
-
+
try:
master_node = r['primary']
except KeyError:
pass
-
+
if 'master_node' in locals(): # unit is part of replicaset, remove it!
unit = "%s:%s" % (unit_get('private-address'), config('port'))
juju_log('Removing myself via %s' % (master_node), 'DEBUG')
@@ -1350,11 +1413,12 @@ def mongos_relation_changed():
port = relation_get('port')
rel_type = relation_get('type')
if hostname is None or port is None or rel_type is None:
- print("mongos_relation_changed: relation data not ready.")
+ juju_log("mongos_relation_changed: relation data not ready.",
+ level=DEBUG)
return
if rel_type == 'configsvr':
config_servers = load_config_servers(default_mongos_list)
- print "Adding config server: %s:%s" % (hostname, port)
+ juju_log("Adding config server: %s:%s" % (hostname, port), level=DEBUG)
if hostname is not None and \
port is not None and \
hostname != '' and \
@@ -1379,11 +1443,11 @@ def mongos_relation_changed():
mongo_client(mongos_host, shard_command2)
else:
- print("mongos_relation_change: undefined rel_type: %s" %
- rel_type)
+ juju_log("mongos_relation_change: undefined rel_type: %s" % rel_type,
+ level=DEBUG)
return
- print("mongos_relation_changed returns: %s" % retVal)
+ juju_log("mongos_relation_changed returns: %s" % retVal, level=DEBUG)
@hooks.hook('mongos-relation-broken')
@@ -1439,6 +1503,38 @@ def uprade_charm():
remove_rest_from_upstart()
+@hooks.hook('update-status')
+def update_status():
+ """
+ Returns: workload_state (so that some hooks know they need to re-run
+ update_status if needed)
+ """
+
+ workload = 'active'
+ status = 'Unit is ready'
+
+ if is_relation_made('replica-set'):
+ # only check for replica-set state if the relation was made which means
+ # more than 1 units were deployed and peer related.
+ mongo_status = get_replicaset_status()
+ if mongo_status in ('PRIMARY', 'SECONDARY'):
+ workload = 'active'
+ status = 'Unit is ready as ' + mongo_status
+ elif mongo_status in ('not in replicaset',):
+ workload = 'active'
+ status = 'Unit is ready, ' + mongo_status
+ else:
+ workload = 'maintenance'
+ status = mongo_status
+ juju_log('mongo_status is unknown: {}'.format(status), level=DEBUG)
+
+ juju_log('Setting workload: {} - {}'.format(workload, status), level=DEBUG)
+ status_set(workload, status)
+
+ return workload
+
+
+
def run(command, exit_on_error=True):
'''Run a command and return the output.'''
try:
diff --git a/hooks/update-status b/hooks/update-status
new file mode 120000
index 0000000..9416ca6
--- /dev/null
+++ b/hooks/update-status
@@ -0,0 +1 @@
+hooks.py \ No newline at end of file