示例#1
0
 def test_incompatible_endpoints(self):
     error = IncompatibleEndpoints(
         RelationEndpoint("mysql", "mysql", "db", "server"),
         RelationEndpoint("riak", "riak", "ring", "peer"))
     self.assertIsStateError(error)
     self.assertTrue("mysql" in str(error))
     self.assertTrue("riak" in str(error))
示例#2
0
 def test_relation_already_exists(self):
     error = RelationAlreadyExists(
         RelationEndpoint("wordpress", "mysql", "mysql", "client"),
         RelationEndpoint("mysql", "mysql", "db", "server"))
     self.assertIsStateError(error)
     self.assertTrue("wordpress" in str(error))
     self.assertTrue("mysql" in str(error))
示例#3
0
 def _default_relations(self):
     wordpress_ep = RelationEndpoint("wordpress", "client-server", "app",
                                     "client")
     mysql_ep = RelationEndpoint("mysql", "client-server", "db", "server")
     self.wordpress_states = yield self.\
         add_relation_service_unit_from_endpoints(wordpress_ep, mysql_ep)
     self.mysql_states = yield self.add_opposite_service_unit(
         self.wordpress_states)
     self.relation = self.mysql_states["unit_relation"]
示例#4
0
 def test_has_relation_between_dyadic_endpoints_missing_assignment(self):
     mysql_ep = RelationEndpoint("mysqldb", "mysql", "db", "server")
     blog_ep = RelationEndpoint("wordpress", "mysql", "mysql", "client")
     self.topology.add_service("s-0", "wordpress")
     self.topology.add_service("s-1", "mysqldb")
     self.topology.add_relation("r-0", "mysql")
     self.topology.assign_service_to_relation("r-0", "s-1", "db", "server")
     self.assertFalse(
         self.topology.has_relation_between_endpoints([mysql_ep, blog_ep]))
     self.assertFalse(
         self.topology.has_relation_between_endpoints([blog_ep, mysql_ep]))
示例#5
0
 def setUp(self):
     yield super(ExecutionContextTest, self).setUp()
     wordpress_ep = RelationEndpoint("wordpress", "client-server", "",
                                     "client")
     mysql_ep = RelationEndpoint("mysql", "client-server", "", "server")
     self.wordpress_states = yield self.\
         add_relation_service_unit_from_endpoints(
             wordpress_ep, mysql_ep)
     self.mysql_states = yield self.add_opposite_service_unit(
         self.wordpress_states)
     self.relation = self.mysql_states["relation"]
示例#6
0
 def setup_default_test_relation(self):
     mysql_ep = RelationEndpoint("mysql", "client-server", "app", "server")
     wordpress_ep = RelationEndpoint("wordpress", "client-server", "db",
                                     "client")
     self.states = yield self.add_relation_service_unit_from_endpoints(
         mysql_ep, wordpress_ep)
     self.unit_directory = os.path.join(
         self.juju_directory, "units",
         self.states["unit"].unit_name.replace("/", "-"))
     os.makedirs(os.path.join(self.unit_directory, "charm", "hooks"))
     os.makedirs(os.path.join(self.juju_directory, "state"))
示例#7
0
 def test_get_relation_between_dyadic_endpoints(self):
     mysql_ep = RelationEndpoint("mysqldb", "mysql", "db", "server")
     blog_ep = RelationEndpoint("wordpress", "mysql", "mysql", "client")
     self.topology.add_service("s-0", "wordpress")
     self.topology.add_service("s-1", "mysqldb")
     self.topology.add_relation("r-0", "mysql")
     self.topology.assign_service_to_relation("r-0", "s-0", "mysql",
                                              "client")
     self.topology.assign_service_to_relation("r-0", "s-1", "db", "server")
     self.assertEqual(
         self.topology.get_relation_between_endpoints([mysql_ep, blog_ep]),
         "r-0")
     self.assertEqual(
         self.topology.get_relation_between_endpoints([blog_ep, mysql_ep]),
         "r-0")
示例#8
0
 def test_has_relation_between_monadic_endpoints(self):
     riak_ep = RelationEndpoint("riak", "riak", "riak", "peer")
     self.topology.add_service("s-0", "riak")
     self.topology.add_relation("r-0", "riak")
     self.topology.assign_service_to_relation("r-0", "s-0", "riak", "peer")
     self.assertTrue(self.topology.has_relation_between_endpoints([riak_ep
                                                                   ]))
示例#9
0
    def test_service_relation_watching(self):
        """When the unit lifecycle is started, the assigned relations
        of the service are watched, with unit relation lifecycles
        created for each.

        Relation hook invocation do not maintain global order or determinism
        across relations. They only maintain ordering and determinism within
        a relation. A shared scheduler across relations would be needed to
        maintain such behavior.
        """
        file_path = self.write_start_and_relation_hooks()
        wordpress1_states = yield self.add_opposite_service_unit(self.states)
        yield self.lifecycle.start()
        yield self.wait_on_hook("app-relation-changed")

        self.assertTrue(os.path.exists(file_path))
        self.assertEqual([x.strip() for x in open(file_path).readlines()],
                         ["joined", "changed"])

        # Queue up our wait condition, of 4 hooks firing
        hooks_complete = self.wait_on_hook(sequence=[
            "app-relation-joined",  # joined event fires join hook,
            "app-relation-changed",  # followed by changed hook
            "app-relation-changed",
            "app-relation-departed"
        ])

        # add another.
        wordpress2_states = yield self.add_opposite_service_unit(
            (yield self.add_relation_service_unit_to_another_endpoint(
                self.states,
                RelationEndpoint("wordpress-2", "client-server", "db",
                                 "client"))))

        # modify one.
        wordpress1_states["unit_relation"].set_data({"hello": "world"})

        # delete one.
        self.client.delete("/relations/%s/client/%s" %
                           (wordpress2_states["relation"].internal_id,
                            wordpress2_states["unit"].internal_id))

        # verify results, waiting for hooks to complete
        yield hooks_complete
        self.assertEqual(
            set([x.strip() for x in open(file_path).readlines()]),
            set(["joined", "changed", "joined", "changed", "departed"]))
示例#10
0
 def endpoints(*pairs):
     return [(RelationEndpoint(*pair[0].split()),
              RelationEndpoint(*pair[1].split())) for pair in pairs]
示例#11
0
 def test_duplicate_endpoints(self):
     riak_ep = RelationEndpoint("riak", "riak", "ring", "peer")
     error = DuplicateEndpoints(riak_ep, riak_ep)
     self.assertIsStateError(error)
     self.assertTrue("riak" in str(error))
示例#12
0
    def test_may_relate_to(self):
        # TODO: Needs a doc string
        mysql_ep = RelationEndpoint("mysqldb", "mysql", "db", "server")
        blog_ep = RelationEndpoint("blog", "mysql", "mysql", "client")
        pg_ep = RelationEndpoint("postgres", "postgres", "db", "server")

        self.assertRaises(TypeError, mysql_ep.may_relate_to, 42)

        # should relate, along with symmetric case
        self.assert_(mysql_ep.may_relate_to(blog_ep))
        self.assert_(blog_ep.may_relate_to(mysql_ep))

        # no common relation_type
        self.assertFalse(blog_ep.may_relate_to(pg_ep))
        self.assertFalse(pg_ep.may_relate_to(blog_ep))

        # antireflexive om relation_role -
        # must be consumer AND provider or vice versa
        self.assertFalse(blog_ep.may_relate_to(
            RelationEndpoint("foo", "mysql", "db", "client")))
        self.assertFalse(mysql_ep.may_relate_to(
            RelationEndpoint("foo", "mysql", "db", "server")))

        # irreflexive for server/client
        self.assertFalse(mysql_ep.may_relate_to(mysql_ep))
        self.assertFalse(blog_ep.may_relate_to(blog_ep))
        self.assertFalse(pg_ep.may_relate_to(pg_ep))

        # but reflexive for peer
        riak_ep = RelationEndpoint("riak", "riak", "riak", "peer")
        self.assert_(riak_ep.may_relate_to(riak_ep))
示例#13
0
    def test_may_relate_to(self):
        # TODO: Needs a doc string
        mysql_ep = RelationEndpoint("mysqldb", "mysql", "db", "server")
        blog_ep = RelationEndpoint("blog", "mysql", "mysql", "client")
        pg_ep = RelationEndpoint("postgres", "postgres", "db", "server")

        self.assertRaises(TypeError, mysql_ep.may_relate_to, 42)

        # should relate, along with symmetric case
        self.assert_(mysql_ep.may_relate_to(blog_ep))
        self.assert_(blog_ep.may_relate_to(mysql_ep))

        # no common relation_type
        self.assertFalse(blog_ep.may_relate_to(pg_ep))
        self.assertFalse(pg_ep.may_relate_to(blog_ep))

        # antireflexive om relation_role -
        # must be consumer AND provider or vice versa
        self.assertFalse(
            blog_ep.may_relate_to(
                RelationEndpoint("foo", "mysql", "db", "client")))
        self.assertFalse(
            mysql_ep.may_relate_to(
                RelationEndpoint("foo", "mysql", "db", "server")))

        # irreflexive for server/client
        self.assertFalse(mysql_ep.may_relate_to(mysql_ep))
        self.assertFalse(blog_ep.may_relate_to(blog_ep))
        self.assertFalse(pg_ep.may_relate_to(pg_ep))

        # but reflexive for peer
        riak_ep = RelationEndpoint("riak", "riak", "riak", "peer")
        self.assert_(riak_ep.may_relate_to(riak_ep))
示例#14
0
    def test_peer_relation(self):
        """Verify status works with peer relations.
        """
        m1 = yield self.machine_state_manager.add_machine_state()
        m2 = yield self.machine_state_manager.add_machine_state()
        yield self.provider.start_machine({
            "machine-id": 0,
            "dns-name": "steamcloud-1.com"
        })
        yield self.provider.start_machine({
            "machine-id": 1,
            "dns-name": "steamcloud-2.com"
        })
        yield m1.set_instance_id(0)
        yield m2.set_instance_id(1)

        riak = yield self.add_service_from_charm("riak")
        riak_u1 = yield self.add_unit(riak, m1)
        riak_u2 = yield self.add_unit(riak, m2, with_agent=lambda _: False)
        yield self.set_unit_state(riak_u1, "started")
        yield self.set_unit_state(riak_u2, "started")

        _, (peer_rel, ) = yield self.relation_state_manager.add_relation_state(
            RelationEndpoint("riak", "peer", "ring", "peer"))

        yield ZookeeperWorkflowState(
            self.client,
            (yield peer_rel.add_unit_state(riak_u1))).set_state("up")
        yield peer_rel.add_unit_state(riak_u2)

        state = yield status.collect(["riak"], self.provider, self.client,
                                     None)
        self.assertEqual(
            state["services"]["riak"], {
                "charm": "local:series/riak-7",
                "relations": {
                    "ring": "riak"
                },
                "units": {
                    "riak/0": {
                        "machine": 0,
                        "public-address": "riak-0.example.com",
                        "relations": {
                            "ring": {
                                "state": "up"
                            }
                        },
                        "state": "started"
                    },
                    "riak/1": {
                        "machine": 1,
                        "public-address": "riak-1.example.com",
                        "relations": {
                            "ring": {
                                "state": None
                            }
                        },
                        "state": "down"
                    }
                }
            })
示例#15
0
    def build_topology(self, base=None, skip_unit_agents=()):
        """Build a simulated topology with a default machine configuration.

        This method returns a dict that can be used to get handles to
        the constructed objects.
        """
        state = {}

        # build out the topology using the state managers
        m1 = yield self.machine_state_manager.add_machine_state()
        m2 = yield self.machine_state_manager.add_machine_state()
        m3 = yield self.machine_state_manager.add_machine_state()
        m4 = yield self.machine_state_manager.add_machine_state()
        m5 = yield self.machine_state_manager.add_machine_state()
        m6 = yield self.machine_state_manager.add_machine_state()
        m7 = yield self.machine_state_manager.add_machine_state()

        # inform the provider about the machine
        yield self.provider.start_machine({
            "machine-id": 0,
            "dns-name": "steamcloud-1.com"
        })
        yield self.provider.start_machine({
            "machine-id": 1,
            "dns-name": "steamcloud-2.com"
        })
        yield self.provider.start_machine({
            "machine-id": 2,
            "dns-name": "steamcloud-3.com"
        })
        yield self.provider.start_machine({
            "machine-id": 3,
            "dns-name": "steamcloud-4.com"
        })
        yield self.provider.start_machine({
            "machine-id": 4,
            "dns-name": "steamcloud-5.com"
        })
        yield self.provider.start_machine({
            "machine-id": 5,
            "dns-name": "steamcloud-6.com"
        })
        yield self.provider.start_machine({
            "machine-id": 6,
            "dns-name": "steamcloud-7.com"
        })

        yield m1.set_instance_id(0)
        yield m2.set_instance_id(1)
        yield m3.set_instance_id(2)
        yield m4.set_instance_id(3)
        yield m5.set_instance_id(4)
        yield m6.set_instance_id(5)
        yield m7.set_instance_id(6)

        state["machines"] = [m1, m2, m3, m4, m5, m6, m7]

        # "Deploy" services
        wordpress = yield self.add_service_from_charm("wordpress")
        mysql = yield self.add_service_from_charm("mysql")
        yield mysql.set_exposed_flag()  # but w/ no open ports

        varnish = yield self.add_service_from_charm("varnish")
        yield varnish.set_exposed_flag()
        # w/o additional metadata
        memcache = yield self.add_service("memcache")

        state["services"] = dict(wordpress=wordpress,
                                 mysql=mysql,
                                 varnish=varnish,
                                 memcache=memcache)

        def with_unit(name):
            for pattern in skip_unit_agents:
                if fnmatch(name, pattern):
                    return False
            return True

        wpu = yield self.add_unit(wordpress, m1, with_unit)
        myu1 = yield self.add_unit(mysql, m2, with_unit)
        myu2 = yield self.add_unit(mysql, m3, with_unit)
        vu1 = yield self.add_unit(varnish, m4, with_unit)
        vu2 = yield self.add_unit(varnish, m5, with_unit)
        mc1 = yield self.add_unit(memcache, m6, with_unit)
        mc2 = yield self.add_unit(memcache, m7, with_unit)

        # add unit states to services and assign to machines
        # Set the lifecycle state and open ports, if any, for each unit state.
        yield self.set_unit_state(wpu, "started", [(80, "tcp"), (443, "tcp")])
        yield self.set_unit_state(myu1, "started")
        yield self.set_unit_state(myu2, "stopped")
        yield self.set_unit_state(vu1, "started", [(80, "tcp")])
        yield self.set_unit_state(vu2, "started", [(80, "tcp")])
        yield self.set_unit_state(mc1, None)
        yield self.set_unit_state(mc2, "installed")

        # Wordpress integrates with each of the following
        # services. Each relation endpoint is used to define the
        # specific relation to be established.
        mysql_ep = RelationEndpoint("mysql", "client-server", "db", "server")
        memcache_ep = RelationEndpoint("memcache", "client-server", "cache",
                                       "server")
        varnish_ep = RelationEndpoint("varnish", "client-server", "proxy",
                                      "client")

        wordpress_db_ep = RelationEndpoint("wordpress", "client-server", "db",
                                           "client")
        wordpress_cache_ep = RelationEndpoint("wordpress", "client-server",
                                              "cache", "client")
        wordpress_proxy_ep = RelationEndpoint("wordpress", "client-server",
                                              "proxy", "server")

        # Create relation service units for each of these relations
        yield self.add_relation_with_relation_units(mysql_ep, [myu1, myu2],
                                                    ["up", "departed"],
                                                    wordpress_db_ep, [wpu],
                                                    ["up"])
        yield self.add_relation_with_relation_units(memcache_ep, [mc1, mc2],
                                                    ["up", "down"],
                                                    wordpress_cache_ep, [wpu],
                                                    ["up"])
        yield self.add_relation_with_relation_units(varnish_ep, [vu1, vu2],
                                                    ["up", "up"],
                                                    wordpress_proxy_ep, [wpu],
                                                    ["up"])

        state["relations"] = dict(wordpress=[wpu],
                                  mysql=[myu1, myu2],
                                  varnish=[vu1, vu2],
                                  memcache=[mc1, mc2])
        returnValue(state)
示例#16
0
    def test_lifecycle_start_stop_starts_relations(self):
        """Starting a stopped lifecycle, restarts relation events.
        """
        wordpress1_states = yield self.add_opposite_service_unit(self.states)
        wordpress2_states = yield self.add_opposite_service_unit(
            (yield self.add_relation_service_unit_to_another_endpoint(
                self.states,
                RelationEndpoint("wordpress-2", "client-server", "db",
                                 "client"))))

        # Start and stop lifecycle
        file_path = self.write_start_and_relation_hooks()
        yield self.lifecycle.start()
        yield self.wait_on_hook("app-relation-changed")
        self.assertTrue(os.path.exists(file_path))
        yield self.lifecycle.stop()

        ########################################################
        # Add, remove relations, and modify related unit settings.

        # The following isn't enough to trigger a hook notification.
        # yield wordpress1_states["relation"].unassign_service(
        #    wordpress1_states["service"])
        #
        # The removal of the external relation, means we stop getting notifies
        # of it, but the underlying unit agents of the service are responsible
        # for removing their presence nodes within the relationship, which
        # triggers a hook invocation.
        yield self.client.delete("/relations/%s/client/%s" %
                                 (wordpress1_states["relation"].internal_id,
                                  wordpress1_states["unit"].internal_id))

        yield wordpress2_states["unit_relation"].set_data({"hello": "world"})

        yield self.add_opposite_service_unit(
            (yield self.add_relation_service_unit_to_another_endpoint(
                self.states,
                RelationEndpoint("wordpress-3", "client-server", "db",
                                 "client"))))

        # Verify no hooks are executed.
        yield self.sleep(0.1)

        res = [x.strip() for x in open(file_path)]
        if ((res != ["joined", "changed", "joined", "changed"])
                and (res != ["joined", "joined", "changed", "changed"])):
            self.fail("Invalid join sequence %s" % res)

        # XXX - With scheduler local state recovery, we should get the modify.

        # Start and verify events.
        hooks_executed = self.wait_on_hook(sequence=[
            "config-changed",
            "start",
            "app-relation-departed",
            "app-relation-joined",  # joined event fires joined hook,
            "app-relation-changed"  # followed by changed hook
        ])
        yield self.lifecycle.start()
        yield hooks_executed
        res.extend(["departed", "joined", "changed"])
        self.assertEqual([x.strip() for x in open(file_path)], res)