From 4578b4bb1af55d6195699b226dde6d2e78ddef86 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier <vincent@nexedi.com> Date: Mon, 24 Sep 2012 18:25:59 +0200 Subject: [PATCH] Provide an SR-transparent way to (de)serialise master data. A better implementation would be at libslap level (so that it works for slapconsole too, for example), but requires too ugly hacks to accomodate current data structure compared to change's otherwise (lack of) complexity. --- setup.py | 3 +++ slapos/recipe/librecipe/__init__.py | 16 +++++++++++++ slapos/recipe/publish.py | 13 ++++++++-- slapos/recipe/request.py | 37 ++++++++++++++++++++++++----- slapos/recipe/slapconfiguration.py | 15 +++++++++++- 5 files changed, 75 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index f7cb501b6..12dce1131 100755 --- a/setup.py +++ b/setup.py @@ -112,11 +112,13 @@ setup(name=name, 'pbs = slapos.recipe.pbs:Recipe', 'proactive = slapos.recipe.proactive:Recipe', 'publish = slapos.recipe.publish:Recipe', + 'publish.serialised = slapos.recipe.publish:Serialised', 'publishurl = slapos.recipe.publishurl:Recipe', 'pwgen = slapos.recipe.pwgen:Recipe', 'pwgen.stable = slapos.recipe.pwgen:StablePasswordGeneratorRecipe', 'requestoptional = slapos.recipe.requestoptional:Recipe', 'request = slapos.recipe.request:Recipe', + 'request.serialised = slapos.recipe.request:Serialised', 'seleniumrunner = slapos.recipe.seleniumrunner:Recipe', 'sheepdogtestbed = slapos.recipe.sheepdogtestbed:SheepDogTestBed', 'shellinabox = slapos.recipe.shellinabox:Recipe', @@ -125,6 +127,7 @@ setup(name=name, 'simplelogger = slapos.recipe.simplelogger:Recipe', 'siptester = slapos.recipe.siptester:SipTesterRecipe', 'slapconfiguration = slapos.recipe.slapconfiguration:Recipe', + 'slapconfiguration.serialised = slapos.recipe.slapconfiguration:Serialised', 'slapcontainer = slapos.recipe.container:Recipe', 'slapmonitor = slapos.recipe.slapmonitor:Recipe', 'slapreport = slapos.recipe.slapreport:Recipe', diff --git a/slapos/recipe/librecipe/__init__.py b/slapos/recipe/librecipe/__init__.py index b4f737a44..c73e7e137 100644 --- a/slapos/recipe/librecipe/__init__.py +++ b/slapos/recipe/librecipe/__init__.py @@ -35,12 +35,28 @@ import netaddr import time import re import urlparse +import json # Use to do from slapos.recipe.librecipe import GenericBaseRecipe from generic import GenericBaseRecipe from genericslap import GenericSlapRecipe from filehash import filehash +# Utility functions to (de)serialise live python objects in order to send them +# to master. +JSON_SERIALISED_MAGIC_KEY = '_' +def wrap(value): + return {JSON_SERIALISED_MAGIC_KEY: json.dumps(value)} + +def unwrap(value): + try: + value = value[JSON_SERIALISED_MAGIC_KEY] + except (KeyError, TypeError): + pass + else: + value = json.loads(value) + return value + class BaseSlapRecipe: """Base class for all slap.recipe.*""" diff --git a/slapos/recipe/publish.py b/slapos/recipe/publish.py index d3813047a..9ed27255e 100644 --- a/slapos/recipe/publish.py +++ b/slapos/recipe/publish.py @@ -25,7 +25,7 @@ # ############################################################################## import zc.buildout - +from slapos.recipe.librecipe import wrap from slapos.recipe.librecipe import GenericSlapRecipe class Recipe(GenericSlapRecipe): @@ -36,5 +36,14 @@ class Recipe(GenericSlapRecipe): for k, v in options.iteritems(): publish_dict[k] = v - self.setConnectionDict(publish_dict) + self._setConnectionDict(publish_dict) return [] + + def _setConnectionDict(self, publish_dict): + return self.setConnectionDict(publish_dict) + +SERIALISED_MAGIC_KEY = '_' + +class Serialised(Recipe): + def _setConnectionDict(self, publish_dict): + return super(Serialised, self)._setConnectionDict(wrap(publish_dict)) diff --git a/slapos/recipe/request.py b/slapos/recipe/request.py index f445de845..1418e6cd9 100644 --- a/slapos/recipe/request.py +++ b/slapos/recipe/request.py @@ -25,7 +25,8 @@ # ############################################################################## import logging - +from slapos.recipe.librecipe import wrap, JSON_SERIALISED_MAGIC_KEY +import json from slapos import slap as slapmodule class Recipe(object): @@ -119,19 +120,33 @@ class Recipe(object): for config_parameter in options['config'].split(): partition_parameter_kw[config_parameter] = \ options['config-%s' % config_parameter] + partition_parameter_kw = self._filterForStorage(partition_parameter_kw) self.instance = instance = request(software_url, software_type, name, partition_parameter_kw=partition_parameter_kw, filter_kw=filter_kw, shared=isSlave) - + return_parameter_dict = self._getReturnParameterDict(instance, + return_parameters) for param in return_parameters: try: - options['connection-%s' % param] = str( - instance.getConnectionParameter(param)) - except slapmodule.NotFoundError: - options['connection-%s' % param] = '' + value = return_parameter_dict[param] + except KeyError: + value = '' if self.failed is None: self.failed = param + options['connection-%s' % param] = value + + def _filterForStorage(self, partition_parameter_kw): + return partition_parameter_kw + + def _getReturnParameterDict(self, instance, return_parameter_list): + result = {} + for param in return_parameters: + try: + result[param] = str(instance.getConnectionParameter(param)) + except slapmodule.NotFoundError: + pass + return result def install(self): if self.failed is not None: @@ -150,3 +165,13 @@ class Recipe(object): return [] update = install + +class Serialised(Recipe): + def _filterForStorage(self, partition_parameter_kw): + return wrap(partition_parameter_kw) + + def _getReturnParameterDict(self, instance, return_parameter_list): + try: + return json.loads(instance.getConnectionParameter(JSON_SERIALISED_MAGIC_KEY)) + except slapmodule.NotFoundError: + return {} diff --git a/slapos/recipe/slapconfiguration.py b/slapos/recipe/slapconfiguration.py index 59f8f9395..da208c088 100644 --- a/slapos/recipe/slapconfiguration.py +++ b/slapos/recipe/slapconfiguration.py @@ -25,6 +25,7 @@ # ############################################################################## import slapos.slap +from slapos.recipe.librecipe import unwrap from ConfigParser import RawConfigParser from netaddr import valid_ipv4, valid_ipv6 @@ -110,11 +111,23 @@ class Recipe(object): options['ipv4'] = ipv4_set options['ipv6'] = ipv6_set options['tap'] = tap_set - options['configuration'] = parameter_dict + parameter_dict = self._expandParameterDict(options, parameter_dict) match = self.OPTCRE_match for key, value in parameter_dict.iteritems(): if match(key) is not None: continue options['configuration.' + key] = value + def _expandParameterDict(self, options, parameter_dict): + options['configuration'] = parameter_dict + return parameter_dict + install = update = lambda self: [] + +class Serialised(Recipe): + def _expandParameterDict(self, options, parameter_dict): + options['configuration'] = parameter_dict = unwrap(parameter_dict) + if isinstance(parameter_dict, dict): + return parameter_dict + else: + return {} -- 2.30.9