示例#1
0
    def add_layer(self,
                  label: str,
                  layer: typing.Union[str, dict, pebble.Layer],
                  *,
                  combine: bool = False):
        # I wish we could combine some of this helpful object corralling with the actual backend,
        # rather than having to re-implement it. Maybe we could subclass
        if not isinstance(label, str):
            raise TypeError('label must be a str, not {}'.format(
                type(label).__name__))

        if isinstance(layer, (str, dict)):
            layer_obj = pebble.Layer(layer)
        elif isinstance(layer, pebble.Layer):
            layer_obj = layer
        else:
            raise TypeError(
                'layer must be str, dict, or pebble.Layer, not {}'.format(
                    type(layer).__name__))
        if label in self._layers:
            # TODO: jam 2021-04-19 These should not be RuntimeErrors but should be proper error
            #  types. https://github.com/canonical/operator/issues/514
            if not combine:
                raise RuntimeError(
                    '400 Bad Request: layer "{}" already exists'.format(label))
            layer = self._layers[label]
            for name, service in layer_obj.services.items():
                # 'override' is actually single quoted in the real error, but
                # it shouldn't be, hopefully that gets cleaned up.
                if not service.override:
                    raise RuntimeError(
                        '500 Internal Server Error: layer "{}" must define'
                        '"override" for service "{}"'.format(label, name))
                if service.override not in ('merge', 'replace'):
                    raise RuntimeError(
                        '500 Internal Server Error: layer "{}" has invalid '
                        '"override" value on service "{}"'.format(label, name))
                if service.override != 'replace':
                    raise RuntimeError(
                        'override: "{}" unsupported for layer "{}" service "{}"'
                        .format(service.override, label, name))
                layer.services[name] = service
        else:
            self._layers[label] = layer_obj
示例#2
0
    def test_add_layer(self):
        okay_response = {
            "result": True,
            "status": "OK",
            "status-code": 200,
            "type": "sync"
        }
        self.client.responses.append(okay_response)
        self.client.responses.append(okay_response)
        self.client.responses.append(okay_response)
        self.client.responses.append(okay_response)

        layer_yaml = """
services:
  foo:
    command: echo bar
    override: replace
"""[1:]
        layer = pebble.Layer(layer_yaml)

        self.client.add_layer('a', layer)
        self.client.add_layer('b', layer.to_yaml())
        self.client.add_layer('c', layer.to_dict())
        self.client.add_layer('d', layer, combine=True)

        def build_expected(label, combine):
            return {
                'action': 'add',
                'combine': combine,
                'label': label,
                'format': 'yaml',
                'layer': layer_yaml,
            }

        self.assertEqual(self.client.requests, [
            ('POST', '/v1/layers', None, build_expected('a', False)),
            ('POST', '/v1/layers', None, build_expected('b', False)),
            ('POST', '/v1/layers', None, build_expected('c', False)),
            ('POST', '/v1/layers', None, build_expected('d', True)),
        ])
示例#3
0
 def test_no_args(self):
     s = pebble.Layer()
     self._assert_empty(s)