/usr/share/pyshared/juju/state/environment.py is in juju-0.7 0.7-0ubuntu2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | import zookeeper
from twisted.internet.defer import inlineCallbacks, returnValue
from txzookeeper.utils import retry_change
from juju.environment.config import EnvironmentsConfig
from juju.lib import serializer
from juju.state.errors import EnvironmentStateNotFound
from juju.state.base import StateBase
SETTINGS_PATH = "/settings"
class EnvironmentStateManager(StateBase):
def _force(self, path, content):
return retry_change(self._client, path, lambda *_: content)
def set_config_state(self, config, environment_name):
serialized_env = config.serialize(environment_name)
return self._force("/environment", serialized_env)
@inlineCallbacks
def get_config(self):
try:
content, stat = yield self._client.get("/environment")
except zookeeper.NoNodeException:
raise EnvironmentStateNotFound()
config = EnvironmentsConfig()
config.parse(content)
returnValue(config)
@inlineCallbacks
def get_in_legacy_environment(self):
"""Return True if bootstrapped with pre-constraints code."""
stat = yield self._client.exists("/constraints")
returnValue(not stat)
def set_constraints(self, constraints):
"""Set the machine constraints for the whole environment.
These may be overridden piecemeal, or entirely, by service constraints.
"""
data = constraints.data
data.pop("ubuntu-series", None)
return self._force("/constraints", serializer.dump(data))
@inlineCallbacks
def get_constraint_set(self):
"""Get the ConstraintSet generated by this environment's provider.
This is needed to generate any Constraints object that will apply in
this environment; but it shouldn't be needed by any processes other
than the CLI and the provisioning agent.
"""
config = yield self.get_config()
provider = config.get_default().get_machine_provider()
constraint_set = yield provider.get_constraint_set()
returnValue(constraint_set)
@inlineCallbacks
def get_constraints(self):
"""Get the environment's machine constraints."""
constraint_set = yield self.get_constraint_set()
try:
content, stat = yield self._client.get("/constraints")
data = serializer.load(content)
except zookeeper.NoNodeException:
data = {}
returnValue(constraint_set.load(data))
# TODO The environment waiting/watching logic in the
# provisioning agent should be moved here (#640726).
class GlobalSettingsStateManager(StateBase):
"""State for the the environment's runtime characterstics.
This can't be stored directly in the environment, as that has access
restrictions. The runtime state can be accessed from all connected
juju clients.
"""
def set_provider_type(self, provider_type):
return self._set_value("provider-type", provider_type, once=True)
def get_provider_type(self):
return self._get_value("provider-type")
def is_debug_log_enabled(self):
"""Find out if the debug log is enabled. Returns a boolean.
"""
return self._get_value("debug-log", False)
def set_debug_log(self, enabled):
"""Enable/Disable the debug log.
:param enabled: Boolean denoting whether the log should be enabled.
"""
return self._set_value("debug-log", bool(enabled))
def set_environment_id(self, uid):
return self._set_value("env-id", uid, once=True)
def get_environment_id(self):
return self._get_value("env-id")
@inlineCallbacks
def _get_value(self, key, default=None):
try:
content, stat = yield self._client.get(SETTINGS_PATH)
except zookeeper.NoNodeException:
returnValue(default)
data = serializer.load(content)
returnValue(data.get(key, default))
def _set_value(self, key, value, once=False):
def set_value(old_content, stat):
if not old_content:
data = {}
else:
data = serializer.load(old_content)
if once and key in data:
raise ValueError("%s can only be set once" % key)
data[key] = value
return serializer.dump(data)
return retry_change(self._client, SETTINGS_PATH, set_value)
def watch_settings_changes(self, callback, error_callback=None):
"""Register a callback to invoked when the runtime changes.
This watch primarily serves to get a persistent watch of the
existance and modifications to the global settings.
The callback will be invoked the first time as soon as the
settings are present. If the settings are already present, it
will be invoked immediately. For initial presence the callback
value will be the boolean value True.
An error callback will be invoked if the callback raised an
exception. The watcher will be stopped, and the error
consumed by the error callback.
"""
assert callable(callback), "Invalid callback"
watcher = _RuntimeWatcher(self._client, callback, error_callback)
return watcher.start()
class _RuntimeWatcher(object):
def __init__(self, client, callback, error_callback=None):
self._client = client
self._callback = callback
self._watching = False
self._error_callback = error_callback
@property
def is_running(self):
return self._watching
@inlineCallbacks
def start(self):
"""Start watching the settings.
The callback will receive notification of changes in addition
to an initial presence message. No state is conveyed via
the watch api only notifications.
"""
assert not self._watching, "Already Watching"
self._watching = True
# This logic will break if the node is removed, and so will
# the function below, but the internal logic never removes
# it, so we do not handle this case.
exists_d, watch_d = self._client.exists_and_watch(SETTINGS_PATH)
exists = yield exists_d
if exists:
yield self._on_settings_changed()
else:
watch_d.addCallback(self._on_settings_changed)
returnValue(self)
def stop(self):
"""Stop the environment watcher, no more callbacks will be invoked."""
self._watching = False
@inlineCallbacks
def _on_settings_changed(self, change_event=True):
"""Setup a perpetual watch till the watcher is stopped.
"""
# Ensure the watch is active, and the client is connected.
if not self._watching or not self._client.connected:
returnValue(False)
exists_d, watch_d = self._client.exists_and_watch(SETTINGS_PATH)
try:
yield self._callback(change_event)
except Exception, e:
self._watching = False
if self._error_callback:
self._error_callback(e)
return
watch_d.addCallback(self._on_settings_changed)
|