Esempio n. 1
0
    def __init__(self, inner):
        """ Takes a reference to a Yay AST node """
        self.inner = PythonicWrapper(inner)
        self.inner.parent = inner.parent
        self.observers = collections.defaultdict(list)

        for k in dir(self):
            prop = getattr(self, k)
            if isinstance(prop, Property):
                i = getattr(self.inner, k)
                i.inner.parent = inner.parent
                i.parent = inner.parent
                p = prop.klass(self, i, **prop.kwargs)
                setattr(self, k, p)
Esempio n. 2
0
    def __init__(self, inner):
        """ Takes a reference to a Yay AST node """
        self.inner = PythonicWrapper(inner)
        self.inner.parent = inner.parent
        self.observers = collections.defaultdict(list)

        for k in dir(self):
            prop = getattr(self, k)
            if isinstance(prop, Property):
                i = getattr(self.inner, k)
                i.inner.parent = inner.parent
                i.parent = inner.parent
                p = prop.klass(self, i, **prop.kwargs)
                setattr(self, k, p)
Esempio n. 3
0
class Resource(object):

    """ A resource represents a resource that can be configured on the system.
    This might be as simple as a symlink or as complex as a database schema
    migration. Resources have policies that represent how the resource is to
    be treated. Providers are the implementation of the resource policy.

    Resource definitions specify the complete set of attributes that can be
    configured for a resource. Policies define which attributes must be
    configured for the policy to be used.

    """

    __metaclass__ = ResourceType

    policies = AvailableResourcePolicies()
    """ A dictionary of policy names mapped to policy classes (not objects).

    These are the policies for this resource class.

    Here be metaprogramming magic.

    Dynamically allocated as Yaybu starts up this is effectively static once
    we're up and running. The combination of this attribute and the policy
    argument below is sufficient to determine which provider might be
    appropriate for this resource.

    """

    policy = Property(PolicyArgument)
    """ The list of policies provided by configuration. This is an argument
    like any other, but has a complex representation that holds the conditions
    and options for the policies as specified in the input file. """

    name = Property(String)

    watch = Property(List, default=[])
    """ A list of files to monitor while this resource is applied

    The file will be hashed before and after a resource is applied.
    If the hash changes, then it will be like a policy has been applied
    on that file.

    For example::

        resources.append:
          - Execute:
              name: buildout-foobar
              command: buildout2.6
              watch:
                - /var/local/sites/foobar/apache/apache.cfg

          - Service:
              name: apache2
              policy:
                restart:
                  when: watched
                  on: File[/var/local/sites/foobar/apache/apache.cfg]
    """

    def __init__(self, inner):
        """ Takes a reference to a Yay AST node """
        self.inner = PythonicWrapper(inner)
        self.inner.parent = inner.parent
        self.observers = collections.defaultdict(list)

        for k in dir(self):
            prop = getattr(self, k)
            if isinstance(prop, Property):
                i = getattr(self.inner, k)
                i.inner.parent = inner.parent
                i.parent = inner.parent
                p = prop.klass(self, i, **prop.kwargs)
                setattr(self, k, p)

    @classmethod
    def get_argument_names(klass):
        for k in dir(klass):
            attr = getattr(klass, k)
            if isinstance(attr, Property):
                yield k

    def get_argument_values(self):
        """ Return all argument names and values in a dictionary. If an
        argument has no default and has not been set, it's value in the
        dictionary will be None. """

        retval = {}
        for key in self.get_argument_names():
            retval[key] = getattr(self, key, None)

    def register_observer(self, when, resource, policy):
        self.observers[when].append((resource, policy))

    def validate(self, context):
        """ Validate that this resource is correctly specified. Will raise
        an exception if it is invalid. Returns True if it is valid.

        We only validate if:

           - only known arguments are specified
           - the chosen policies all exist, or
           - there is at least one default policy, and
           - the arguments provided conform with all selected policies, and
           - the selected policies all share a single provider

        If the above is all true then we can identify a provider that should
        be able to implement the required policies.

        """

        # This will throw any error if any of our validation fails
        self.get_argument_values()

        # Only allow keys that are in the schema
        for key in self.inner.keys():
            if not key in self.get_argument_names():
                raise error.ParseError(
                    "'%s' is not a valid option for resource %s" % (key, self),
                    self.inner.anchor)

        # Error if doesn't conform to policy
        for p in self.get_potential_policies():
            p.validate(self)

            # throws an exception if there is not oneandonlyone provider
            p.get_provider(context)

        return True

    def test(self, context):
        """ Apply the provider for the selected policy, and then fire any
        events that are being observed. """
        for policy in self.get_potential_policies():
            Provider = policy.get_provider(context)
            p = Provider(self)
            p.test(context)

    def apply(self, context, output=None, policy=None):
        """ Apply the provider for the selected policy, and then fire any
        events that are being observed. """
        if policy is None:
            pol = self.get_default_policy(context)
        else:
            pol_class = self.policies[policy]
            pol = pol_class(self)
        prov_class = pol.get_provider(context)
        prov = prov_class(self)
        changed = prov.apply(context, output)
        context.state.clear_override(self)
        if changed:
            self.fire_event(context, pol.name)
        return changed

    def fire_event(self, context, name):
        """ Apply the appropriate policies on the resources that are observing
        this resource for the firing of a policy. """
        for resource, policy in self.observers[name]:
            context.state.override(resource, policy)

    def bind(self, resources):
        """ Bind this resource to all the resources on which it triggers.
        Returns a list of the resources to which we are bound. """
        bound = []
        policy = self.policy.resolve()
        if policy:
            for trigger in policy.triggers:
                bound.append(trigger.bind(resources, self))
        return bound

    def get_potential_policies(self):
        policy = self.policy.resolve()
        if policy:
            return [P(self) for P in policy.all_potential_policies(self)]
        else:
            return [self.policies.default()(self)]

    def get_default_policy(self, context):
        """ Return an instantiated policy for this resource. """
        selected = context.state.overridden_policy(self)
        if not selected:
            policy = self.policy.resolve()
            if policy:
                selected = policy.literal_policy(self)
            else:
                selected = self.policies.default()
        return selected(self)

    @property
    def id(self):
        classname = getattr(self, '__resource_name__', self.__class__.__name__)
        return "%s[%s]" % (classname, self.inner.name.as_string())

    def __repr__(self):
        return self.id
Esempio n. 4
0
class Resource(object):
    """ A resource represents a resource that can be configured on the system.
    This might be as simple as a symlink or as complex as a database schema
    migration. Resources have policies that represent how the resource is to
    be treated. Providers are the implementation of the resource policy.

    Resource definitions specify the complete set of attributes that can be
    configured for a resource. Policies define which attributes must be
    configured for the policy to be used.

    """

    __metaclass__ = ResourceType

    policies = AvailableResourcePolicies()
    """ A dictionary of policy names mapped to policy classes (not objects).

    These are the policies for this resource class.

    Here be metaprogramming magic.

    Dynamically allocated as Yaybu starts up this is effectively static once
    we're up and running. The combination of this attribute and the policy
    argument below is sufficient to determine which provider might be
    appropriate for this resource.

    """

    policy = Property(PolicyArgument)
    """ The list of policies provided by configuration. This is an argument
    like any other, but has a complex representation that holds the conditions
    and options for the policies as specified in the input file. """

    name = Property(String)

    watch = Property(List, default=[])
    """ A list of files to monitor while this resource is applied

    The file will be hashed before and after a resource is applied.
    If the hash changes, then it will be like a policy has been applied
    on that file.

    For example::

        resources.append:
          - Execute:
              name: buildout-foobar
              command: buildout2.6
              watch:
                - /var/local/sites/foobar/apache/apache.cfg

          - Service:
              name: apache2
              policy:
                restart:
                  when: watched
                  on: File[/var/local/sites/foobar/apache/apache.cfg]
    """
    def __init__(self, inner):
        """ Takes a reference to a Yay AST node """
        self.inner = PythonicWrapper(inner)
        self.inner.parent = inner.parent
        self.observers = collections.defaultdict(list)

        for k in dir(self):
            prop = getattr(self, k)
            if isinstance(prop, Property):
                i = getattr(self.inner, k)
                i.inner.parent = inner.parent
                i.parent = inner.parent
                p = prop.klass(self, i, **prop.kwargs)
                setattr(self, k, p)

    @classmethod
    def get_argument_names(klass):
        for k in dir(klass):
            attr = getattr(klass, k)
            if isinstance(attr, Property):
                yield k

    def get_argument_values(self):
        """ Return all argument names and values in a dictionary. If an
        argument has no default and has not been set, it's value in the
        dictionary will be None. """

        retval = {}
        for key in self.get_argument_names():
            retval[key] = getattr(self, key, None)

    def register_observer(self, when, resource, policy):
        self.observers[when].append((resource, policy))

    def validate(self, context):
        """ Validate that this resource is correctly specified. Will raise
        an exception if it is invalid. Returns True if it is valid.

        We only validate if:

           - only known arguments are specified
           - the chosen policies all exist, or
           - there is at least one default policy, and
           - the arguments provided conform with all selected policies, and
           - the selected policies all share a single provider

        If the above is all true then we can identify a provider that should
        be able to implement the required policies.

        """

        # This will throw any error if any of our validation fails
        self.get_argument_values()

        # Only allow keys that are in the schema
        for key in self.inner.keys():
            if not key in self.get_argument_names():
                raise error.ParseError(
                    "'%s' is not a valid option for resource %s" % (key, self),
                    self.inner.anchor)

        # Error if doesn't conform to policy
        for p in self.get_potential_policies():
            p.validate(self)

            # throws an exception if there is not oneandonlyone provider
            p.get_provider(context)

        return True

    def test(self, context):
        """ Apply the provider for the selected policy, and then fire any
        events that are being observed. """
        for policy in self.get_potential_policies():
            Provider = policy.get_provider(context)
            p = Provider(self)
            p.test(context)

    def apply(self, context, output=None, policy=None):
        """ Apply the provider for the selected policy, and then fire any
        events that are being observed. """
        if policy is None:
            pol = self.get_default_policy(context)
        else:
            pol_class = self.policies[policy]
            pol = pol_class(self)
        prov_class = pol.get_provider(context)
        prov = prov_class(self)
        changed = prov.apply(context, output)
        context.state.clear_override(self)
        if changed:
            self.fire_event(context, pol.name)
        return changed

    def fire_event(self, context, name):
        """ Apply the appropriate policies on the resources that are observing
        this resource for the firing of a policy. """
        for resource, policy in self.observers[name]:
            context.state.override(resource, policy)

    def bind(self, resources):
        """ Bind this resource to all the resources on which it triggers.
        Returns a list of the resources to which we are bound. """
        bound = []
        policy = self.policy.resolve()
        if policy:
            for trigger in policy.triggers:
                bound.append(trigger.bind(resources, self))
        return bound

    def get_potential_policies(self):
        policy = self.policy.resolve()
        if policy:
            return [P(self) for P in policy.all_potential_policies(self)]
        else:
            return [self.policies.default()(self)]

    def get_default_policy(self, context):
        """ Return an instantiated policy for this resource. """
        selected = context.state.overridden_policy(self)
        if not selected:
            policy = self.policy.resolve()
            if policy:
                selected = policy.literal_policy(self)
            else:
                selected = self.policies.default()
        return selected(self)

    @property
    def id(self):
        classname = getattr(self, '__resource_name__', self.__class__.__name__)
        return "%s[%s]" % (classname, self.inner.name.as_string())

    def __repr__(self):
        return self.id