diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2009-10-19 20:20:09 -0400 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2009-10-19 20:20:09 -0400 |
commit | 2d6dd2c5ade3f5fad3e2257dce52a6e188fe7535 (patch) | |
tree | da9c93d2f87df6d2b688a455a31e69859117ba1e /google_appengine/google/appengine/api/capabilities | |
download | FramedPrototype-2d6dd2c5ade3f5fad3e2257dce52a6e188fe7535.tar.xz FramedPrototype-2d6dd2c5ade3f5fad3e2257dce52a6e188fe7535.zip |
Initial import.
Diffstat (limited to 'google_appengine/google/appengine/api/capabilities')
-rwxr-xr-x | google_appengine/google/appengine/api/capabilities/__init__.py | 172 | ||||
-rw-r--r-- | google_appengine/google/appengine/api/capabilities/__init__.pyc | bin | 0 -> 5952 bytes | |||
-rw-r--r-- | google_appengine/google/appengine/api/capabilities/capability_service_pb.py | 366 | ||||
-rw-r--r-- | google_appengine/google/appengine/api/capabilities/capability_service_pb.pyc | bin | 0 -> 18033 bytes | |||
-rwxr-xr-x | google_appengine/google/appengine/api/capabilities/capability_stub.py | 53 | ||||
-rw-r--r-- | google_appengine/google/appengine/api/capabilities/capability_stub.pyc | bin | 0 -> 1762 bytes |
6 files changed, 591 insertions, 0 deletions
diff --git a/google_appengine/google/appengine/api/capabilities/__init__.py b/google_appengine/google/appengine/api/capabilities/__init__.py new file mode 100755 index 0000000..f672cbb --- /dev/null +++ b/google_appengine/google/appengine/api/capabilities/__init__.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python +# +# Copyright 2007 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""Allows applications to identify API outages and scheduled downtime. + +Some examples: + def StoreUploadedProfileImage(self): + uploaded_image = self.request.get('img') + # If the images API is unavailable, we'll just skip the resize. + if CapabilitySet('images').is_enabled(): + uploaded_image = images.resize(uploaded_image, 64, 64) + store(uploaded_image) + + def RenderHTMLForm(self): + datastore_readonly = CapabilitySet('datastore_v3', capabilities=['write']) + if datastore_readonly.may_be_disabled_in(60): + # self.response.out('<p>Not accepting submissions right now: %s</p>' % + datastore_readonly.admin_message()) + # ...render form with form elements disabled... + else: + # ...render form normally... + + Individual API wrapper modules should expose CapabilitySet objects + for users rather than relying on users to create them. They may + also create convenience methods (e.g. db.IsReadOnly()) that delegate + to the relevant CapabilitySet. + +Classes defined here: + CapabilitySet: encapsulates one or more capabilities, allows introspection. + UnknownCapabilityError: thrown when an unknown capability is requested. +""" + + + + + +from google.appengine.api.capabilities import capability_service_pb +from google.appengine.base import capabilities_pb +from google.appengine.api import apiproxy_stub_map + + +IsEnabledRequest = capability_service_pb.IsEnabledRequest +IsEnabledResponse = capability_service_pb.IsEnabledResponse +CapabilityConfig = capabilities_pb.CapabilityConfig + + +class UnknownCapabilityError(Exception): + """An unknown capability was requested.""" + + +class CapabilitySet(object): + """Encapsulates one or more capabilities. + + Capabilities can either be named explicitly, or inferred from the + list of methods provided. If no capabilities or methods are + provided, this will check whether the entire package is enabled. + """ + def __init__(self, package, capabilities=None, methods=None, + stub_map=apiproxy_stub_map): + """Constructor. + + Args: + capabilities: list of strings + methods: list of strings + """ + if capabilities is None: + capabilities = [] + if methods is None: + methods = [] + self._package = package + self._capabilities = ['*'] + capabilities + self._methods = methods + self._stub_map = stub_map + + def is_enabled(self): + """Tests whether the capabilities is currently enabled. + + Returns: + True if API calls that require these capabillities will succeed. + + Raises: + UnknownCapabilityError, if a specified capability was not recognized. + """ + config = self._get_status() + return config.summary_status() in (IsEnabledResponse.ENABLED, + IsEnabledResponse.SCHEDULED_FUTURE, + IsEnabledResponse.SCHEDULED_NOW) + + def will_remain_enabled_for(self, time=60): + """Returns true if it will remain enabled for the specified amount of time. + + Args: + time: Number of seconds in the future to look when checking for scheduled + downtime. + + Returns: + True if there is no scheduled downtime for the specified capability + within the amount of time specified. + + Raises: + UnknownCapabilityError, if a specified capability was not recognized. + """ + config = self._get_status() + + status = config.summary_status() + if status == IsEnabledResponse.ENABLED: + return True + elif status == IsEnabledResponse.SCHEDULED_NOW: + return False + elif status == IsEnabledResponse.SCHEDULED_FUTURE: + if config.has_time_until_scheduled(): + return config.time_until_scheduled() >= time + else: + return True + elif status == IsEnabledResponse.DISABLED: + return False + else: + return False + + def admin_message(self): + """Get any administrator notice messages for these capabilities. + + Returns: + A string containing one or more admin messages, or an empty string. + + Raises: + UnknownCapabilityError, if a specified capability was not recognized. + """ + message_list = [] + for config in self._get_status().config_list(): + message = config.admin_message() + if message and message not in message_list: + message_list.append(message) + return ' '.join(message_list) + + def _get_status(self): + """Get an IsEnabledResponse for the capabilities listed. + + Returns: + IsEnabledResponse for the specified capabilities. + + Raises: + UnknownCapabilityError: If an unknown capability was requested. + """ + req = IsEnabledRequest() + req.set_package(self._package) + for capability in self._capabilities: + req.add_capability(capability) + for method in self._methods: + req.add_call(method) + + resp = capability_service_pb.IsEnabledResponse() + self._stub_map.MakeSyncCall('capability_service', 'IsEnabled', req, resp) + + if resp.summary_status() == IsEnabledResponse.UNKNOWN: + raise UnknownCapabilityError() + + return resp diff --git a/google_appengine/google/appengine/api/capabilities/__init__.pyc b/google_appengine/google/appengine/api/capabilities/__init__.pyc Binary files differnew file mode 100644 index 0000000..c8ac026 --- /dev/null +++ b/google_appengine/google/appengine/api/capabilities/__init__.pyc diff --git a/google_appengine/google/appengine/api/capabilities/capability_service_pb.py b/google_appengine/google/appengine/api/capabilities/capability_service_pb.py new file mode 100644 index 0000000..9f9ba29 --- /dev/null +++ b/google_appengine/google/appengine/api/capabilities/capability_service_pb.py @@ -0,0 +1,366 @@ +#!/usr/bin/env python +# +# Copyright 2007 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from google.net.proto import ProtocolBuffer +import array +import dummy_thread as thread + +__pychecker__ = """maxreturns=0 maxbranches=0 no-callinit + unusednames=printElemNumber,debug_strs no-special""" + +from google.appengine.base.capabilities_pb import CapabilityConfig +class IsEnabledRequest(ProtocolBuffer.ProtocolMessage): + has_package_ = 0 + package_ = "" + + def __init__(self, contents=None): + self.capability_ = [] + self.call_ = [] + if contents is not None: self.MergeFromString(contents) + + def package(self): return self.package_ + + def set_package(self, x): + self.has_package_ = 1 + self.package_ = x + + def clear_package(self): + if self.has_package_: + self.has_package_ = 0 + self.package_ = "" + + def has_package(self): return self.has_package_ + + def capability_size(self): return len(self.capability_) + def capability_list(self): return self.capability_ + + def capability(self, i): + return self.capability_[i] + + def set_capability(self, i, x): + self.capability_[i] = x + + def add_capability(self, x): + self.capability_.append(x) + + def clear_capability(self): + self.capability_ = [] + + def call_size(self): return len(self.call_) + def call_list(self): return self.call_ + + def call(self, i): + return self.call_[i] + + def set_call(self, i, x): + self.call_[i] = x + + def add_call(self, x): + self.call_.append(x) + + def clear_call(self): + self.call_ = [] + + + def MergeFrom(self, x): + assert x is not self + if (x.has_package()): self.set_package(x.package()) + for i in xrange(x.capability_size()): self.add_capability(x.capability(i)) + for i in xrange(x.call_size()): self.add_call(x.call(i)) + + def Equals(self, x): + if x is self: return 1 + if self.has_package_ != x.has_package_: return 0 + if self.has_package_ and self.package_ != x.package_: return 0 + if len(self.capability_) != len(x.capability_): return 0 + for e1, e2 in zip(self.capability_, x.capability_): + if e1 != e2: return 0 + if len(self.call_) != len(x.call_): return 0 + for e1, e2 in zip(self.call_, x.call_): + if e1 != e2: return 0 + return 1 + + def IsInitialized(self, debug_strs=None): + initialized = 1 + if (not self.has_package_): + initialized = 0 + if debug_strs is not None: + debug_strs.append('Required field: package not set.') + return initialized + + def ByteSize(self): + n = 0 + n += self.lengthString(len(self.package_)) + n += 1 * len(self.capability_) + for i in xrange(len(self.capability_)): n += self.lengthString(len(self.capability_[i])) + n += 1 * len(self.call_) + for i in xrange(len(self.call_)): n += self.lengthString(len(self.call_[i])) + return n + 1 + + def Clear(self): + self.clear_package() + self.clear_capability() + self.clear_call() + + def OutputUnchecked(self, out): + out.putVarInt32(10) + out.putPrefixedString(self.package_) + for i in xrange(len(self.capability_)): + out.putVarInt32(18) + out.putPrefixedString(self.capability_[i]) + for i in xrange(len(self.call_)): + out.putVarInt32(26) + out.putPrefixedString(self.call_[i]) + + def TryMerge(self, d): + while d.avail() > 0: + tt = d.getVarInt32() + if tt == 10: + self.set_package(d.getPrefixedString()) + continue + if tt == 18: + self.add_capability(d.getPrefixedString()) + continue + if tt == 26: + self.add_call(d.getPrefixedString()) + continue + if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError + d.skipData(tt) + + + def __str__(self, prefix="", printElemNumber=0): + res="" + if self.has_package_: res+=prefix+("package: %s\n" % self.DebugFormatString(self.package_)) + cnt=0 + for e in self.capability_: + elm="" + if printElemNumber: elm="(%d)" % cnt + res+=prefix+("capability%s: %s\n" % (elm, self.DebugFormatString(e))) + cnt+=1 + cnt=0 + for e in self.call_: + elm="" + if printElemNumber: elm="(%d)" % cnt + res+=prefix+("call%s: %s\n" % (elm, self.DebugFormatString(e))) + cnt+=1 + return res + + + def _BuildTagLookupTable(sparse, maxtag, default=None): + return tuple([sparse.get(i, default) for i in xrange(0, 1+maxtag)]) + + kpackage = 1 + kcapability = 2 + kcall = 3 + + _TEXT = _BuildTagLookupTable({ + 0: "ErrorCode", + 1: "package", + 2: "capability", + 3: "call", + }, 3) + + _TYPES = _BuildTagLookupTable({ + 0: ProtocolBuffer.Encoder.NUMERIC, + 1: ProtocolBuffer.Encoder.STRING, + 2: ProtocolBuffer.Encoder.STRING, + 3: ProtocolBuffer.Encoder.STRING, + }, 3, ProtocolBuffer.Encoder.MAX_TYPE) + + _STYLE = """""" + _STYLE_CONTENT_TYPE = """""" +class IsEnabledResponse(ProtocolBuffer.ProtocolMessage): + + ENABLED = 1 + SCHEDULED_FUTURE = 2 + SCHEDULED_NOW = 3 + DISABLED = 4 + UNKNOWN = 5 + + _SummaryStatus_NAMES = { + 1: "ENABLED", + 2: "SCHEDULED_FUTURE", + 3: "SCHEDULED_NOW", + 4: "DISABLED", + 5: "UNKNOWN", + } + + def SummaryStatus_Name(cls, x): return cls._SummaryStatus_NAMES.get(x, "") + SummaryStatus_Name = classmethod(SummaryStatus_Name) + + has_summary_status_ = 0 + summary_status_ = 0 + has_time_until_scheduled_ = 0 + time_until_scheduled_ = 0 + + def __init__(self, contents=None): + self.config_ = [] + if contents is not None: self.MergeFromString(contents) + + def summary_status(self): return self.summary_status_ + + def set_summary_status(self, x): + self.has_summary_status_ = 1 + self.summary_status_ = x + + def clear_summary_status(self): + if self.has_summary_status_: + self.has_summary_status_ = 0 + self.summary_status_ = 0 + + def has_summary_status(self): return self.has_summary_status_ + + def time_until_scheduled(self): return self.time_until_scheduled_ + + def set_time_until_scheduled(self, x): + self.has_time_until_scheduled_ = 1 + self.time_until_scheduled_ = x + + def clear_time_until_scheduled(self): + if self.has_time_until_scheduled_: + self.has_time_until_scheduled_ = 0 + self.time_until_scheduled_ = 0 + + def has_time_until_scheduled(self): return self.has_time_until_scheduled_ + + def config_size(self): return len(self.config_) + def config_list(self): return self.config_ + + def config(self, i): + return self.config_[i] + + def mutable_config(self, i): + return self.config_[i] + + def add_config(self): + x = CapabilityConfig() + self.config_.append(x) + return x + + def clear_config(self): + self.config_ = [] + + def MergeFrom(self, x): + assert x is not self + if (x.has_summary_status()): self.set_summary_status(x.summary_status()) + if (x.has_time_until_scheduled()): self.set_time_until_scheduled(x.time_until_scheduled()) + for i in xrange(x.config_size()): self.add_config().CopyFrom(x.config(i)) + + def Equals(self, x): + if x is self: return 1 + if self.has_summary_status_ != x.has_summary_status_: return 0 + if self.has_summary_status_ and self.summary_status_ != x.summary_status_: return 0 + if self.has_time_until_scheduled_ != x.has_time_until_scheduled_: return 0 + if self.has_time_until_scheduled_ and self.time_until_scheduled_ != x.time_until_scheduled_: return 0 + if len(self.config_) != len(x.config_): return 0 + for e1, e2 in zip(self.config_, x.config_): + if e1 != e2: return 0 + return 1 + + def IsInitialized(self, debug_strs=None): + initialized = 1 + if (not self.has_summary_status_): + initialized = 0 + if debug_strs is not None: + debug_strs.append('Required field: summary_status not set.') + for p in self.config_: + if not p.IsInitialized(debug_strs): initialized=0 + return initialized + + def ByteSize(self): + n = 0 + n += self.lengthVarInt64(self.summary_status_) + if (self.has_time_until_scheduled_): n += 1 + self.lengthVarInt64(self.time_until_scheduled_) + n += 1 * len(self.config_) + for i in xrange(len(self.config_)): n += self.lengthString(self.config_[i].ByteSize()) + return n + 1 + + def Clear(self): + self.clear_summary_status() + self.clear_time_until_scheduled() + self.clear_config() + + def OutputUnchecked(self, out): + out.putVarInt32(8) + out.putVarInt32(self.summary_status_) + if (self.has_time_until_scheduled_): + out.putVarInt32(16) + out.putVarInt64(self.time_until_scheduled_) + for i in xrange(len(self.config_)): + out.putVarInt32(26) + out.putVarInt32(self.config_[i].ByteSize()) + self.config_[i].OutputUnchecked(out) + + def TryMerge(self, d): + while d.avail() > 0: + tt = d.getVarInt32() + if tt == 8: + self.set_summary_status(d.getVarInt32()) + continue + if tt == 16: + self.set_time_until_scheduled(d.getVarInt64()) + continue + if tt == 26: + length = d.getVarInt32() + tmp = ProtocolBuffer.Decoder(d.buffer(), d.pos(), d.pos() + length) + d.skip(length) + self.add_config().TryMerge(tmp) + continue + if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError + d.skipData(tt) + + + def __str__(self, prefix="", printElemNumber=0): + res="" + if self.has_summary_status_: res+=prefix+("summary_status: %s\n" % self.DebugFormatInt32(self.summary_status_)) + if self.has_time_until_scheduled_: res+=prefix+("time_until_scheduled: %s\n" % self.DebugFormatInt64(self.time_until_scheduled_)) + cnt=0 + for e in self.config_: + elm="" + if printElemNumber: elm="(%d)" % cnt + res+=prefix+("config%s <\n" % elm) + res+=e.__str__(prefix + " ", printElemNumber) + res+=prefix+">\n" + cnt+=1 + return res + + + def _BuildTagLookupTable(sparse, maxtag, default=None): + return tuple([sparse.get(i, default) for i in xrange(0, 1+maxtag)]) + + ksummary_status = 1 + ktime_until_scheduled = 2 + kconfig = 3 + + _TEXT = _BuildTagLookupTable({ + 0: "ErrorCode", + 1: "summary_status", + 2: "time_until_scheduled", + 3: "config", + }, 3) + + _TYPES = _BuildTagLookupTable({ + 0: ProtocolBuffer.Encoder.NUMERIC, + 1: ProtocolBuffer.Encoder.NUMERIC, + 2: ProtocolBuffer.Encoder.NUMERIC, + 3: ProtocolBuffer.Encoder.STRING, + }, 3, ProtocolBuffer.Encoder.MAX_TYPE) + + _STYLE = """""" + _STYLE_CONTENT_TYPE = """""" + +__all__ = ['IsEnabledRequest','IsEnabledResponse'] diff --git a/google_appengine/google/appengine/api/capabilities/capability_service_pb.pyc b/google_appengine/google/appengine/api/capabilities/capability_service_pb.pyc Binary files differnew file mode 100644 index 0000000..d1a68c2 --- /dev/null +++ b/google_appengine/google/appengine/api/capabilities/capability_service_pb.pyc diff --git a/google_appengine/google/appengine/api/capabilities/capability_stub.py b/google_appengine/google/appengine/api/capabilities/capability_stub.py new file mode 100755 index 0000000..6d33d7e --- /dev/null +++ b/google_appengine/google/appengine/api/capabilities/capability_stub.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# +# Copyright 2007 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""Stub version of the capability service API, everything is always enabled.""" + + + +from google.appengine.api import apiproxy_stub +from google.appengine.api import capabilities + +IsEnabledRequest = capabilities.IsEnabledRequest +IsEnabledResponse = capabilities.IsEnabledResponse +CapabilityConfig = capabilities.CapabilityConfig + +class CapabilityServiceStub(apiproxy_stub.APIProxyStub): + """Python only capability service stub.""" + + def __init__(self, service_name='capability_service'): + """Constructor. + + Args: + service_name: Service name expected for all calls. + """ + super(CapabilityServiceStub, self).__init__(service_name) + + + def _Dynamic_IsEnabled(self, request, response): + """Implementation of CapabilityService::IsEnabled(). + + Args: + request: An IsEnabledRequest. + response: An IsEnabledResponse. + """ + response.set_summary_status(IsEnabledResponse.ENABLED) + + default_config = response.add_config() + default_config.set_package('') + default_config.set_capability('') + default_config.set_status(CapabilityConfig.ENABLED) diff --git a/google_appengine/google/appengine/api/capabilities/capability_stub.pyc b/google_appengine/google/appengine/api/capabilities/capability_stub.pyc Binary files differnew file mode 100644 index 0000000..6336e60 --- /dev/null +++ b/google_appengine/google/appengine/api/capabilities/capability_stub.pyc |