Example #1
0
    def test_add_multiple_units(self):
        """
        'juju add-unit <service_name>' will add a new service
        unit of the given service.
        """
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 1)

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main(["add-unit", "--num-units", "5", "mysql"])
        yield finished

        # verify the unit and its machine assignment.
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 6)

        topology = yield self.get_topology()
        unit = yield self.service_state1.get_unit_state("mysql/1")
        machine_id = topology.get_service_unit_machine(
            self.service_state1.internal_id, unit.internal_id)
        self.assertNotEqual(machine_id, None)
        for i in xrange(1, 6):
            self.assertIn(
                "Unit 'mysql/%d' added to service 'mysql'" % i,
                self.output.getvalue())
        yield self.assert_machine_assignments("mysql", [1, 2, 3, 4, 5, 6])
Example #2
0
    def test_shell_with_unit(self):
        """
        'juju ssh mysql/0' will execute ssh against the machine
        hosting the unit.
        """
        mock_environment = self.mocker.patch(Environment)
        mock_environment.get_machine_provider()
        self.mocker.result(self.provider)

        mock_exec = self.mocker.replace(os.execvp)
        mock_exec("ssh", [
            "ssh", "-o",
            "ControlPath " + self.tmp_home + "/.juju/ssh/master-%r@%h:%p",
            "-o", "ControlMaster no", "*****@*****.**"
        ])

        # Track unwanted calls:
        calls = []
        mock_exec(ARGS, KWARGS)
        self.mocker.count(0, None)
        self.mocker.call(lambda *args, **kwargs: calls.append((args, kwargs)))

        finished = self.setup_cli_reactor()
        self.mocker.replay()
        yield self.unit.connect_agent()

        main(["ssh", self.unit.unit_name])
        yield finished

        self.assertEquals(calls, [])
        self.assertIn("Connecting to unit mysql/0 at mysql-0.example.com",
                      self.output.getvalue())
Example #3
0
    def test_policy_from_environment(self):
        config = {
            "environments": {"firstenv": {
                    "placement": "local",
                    "type": "dummy"}}}

        self.write_config(dump(config))
        self.config.load()

        ms0 = yield self.machine_state_manager.get_machine_state(0)
        yield self.service_unit1.unassign_from_machine()
        yield self.service_unit1.assign_to_machine(ms0)

        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 1)

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main(["add-unit", "mysql"])
        yield finished

        # Verify the local policy was used
        topology = yield self.get_topology()
        unit = yield self.service_state1.get_unit_state("mysql/1")
        machine_id = topology.get_service_unit_machine(
            self.service_state1.internal_id, unit.internal_id)
        self.assertNotEqual(machine_id, None)
        self.assertIn(
            "Unit 'mysql/1' added to service 'mysql'",
            self.output.getvalue())
        # adding a second unit still assigns to machine 0 with local policy
        yield self.assert_machine_assignments("mysql", [0, 0])
Example #4
0
    def test_scp_machine_id(self):
        """Verify scp command is invoked against the host for a machine ID."""
        mock_environment = self.mocker.patch(Environment)
        mock_environment.get_machine_provider()
        self.mocker.result(self.provider)

        # Verify expected call against scp
        mock_exec = self.mocker.replace(os.execvp)
        mock_exec(
            "scp",
            ["scp", "[email protected]:foo/*", "10.1.2.3:."])

        # But no other calls
        calls = []
        mock_exec(ARGS, KWARGS)
        self.mocker.count(0, None)
        self.mocker.call(lambda *args, **kwargs: calls.append((args, kwargs)))

        finished = self.setup_cli_reactor()
        self.mocker.replay()

        yield self.unit.connect_agent()
        main(["scp", "0:foo/*", "10.1.2.3:."])
        yield finished
        self.assertEquals(calls, [])
Example #5
0
    def test_shell_with_machine_and_unconnected_machine_agent(self):
        """If a machine doesn't have a connected machine agent,
        the ssh command will wait till one exists before connecting.
        """
        mock_environment = self.mocker.patch(Environment)
        mock_environment.get_machine_provider()
        self.mocker.result(self.provider)

        mock_machine = self.mocker.patch(MachineState)
        mock_machine.watch_agent()
        self.mocker.result((succeed(False), succeed(True)))
        mock_exec = self.mocker.replace(os.execvp)
        mock_exec("ssh", [
            "ssh", "-o",
            "ControlPath " + self.tmp_home + "/.juju/ssh/master-%r@%h:%p",
            "-o", "ControlMaster no", "*****@*****.**"
        ])

        # Track unwanted calls:
        calls = []
        mock_exec(ARGS, KWARGS)
        self.mocker.count(0, None)
        self.mocker.call(lambda *args, **kwargs: calls.append((args, kwargs)))

        finished = self.setup_cli_reactor()
        self.mocker.replay()
        yield self.machine.connect_agent()
        main(["ssh", "0"])
        yield finished

        self.assertEquals(calls, [])

        self.assertIn("Waiting for machine to come up", self.output.getvalue())
Example #6
0
    def test_scp_machine_id(self):
        """Verify scp command is invoked against the host for a machine ID."""
        # We need to do this because separate instances of DummyProvider don't
        # share instance state.
        mock_environment = self.mocker.patch(Environment)
        mock_environment.get_machine_provider()
        self.mocker.result(self.provider)

        # Verify expected call against scp
        mock_exec = self.mocker.replace(os.execvp)
        mock_exec(
            "scp",
            ["scp", "[email protected]:foo/*", "10.1.2.3:."])

        # But no other calls
        calls = []
        mock_exec(ARGS, KWARGS)
        self.mocker.count(0, None)
        self.mocker.call(lambda *args, **kwargs: calls.append((args, kwargs)))

        finished = self.setup_cli_reactor()
        self.mocker.replay()

        yield self.unit.connect_agent()
        main(["scp", "0:foo/*", "10.1.2.3:."])
        yield finished
        self.assertEquals(calls, [])
Example #7
0
    def test_open_tunnel(self):
        """
        'juju-control bootstrap' will invoke the bootstrap method of all
        configured machine providers in all environments.
        """
        config = {
            "environments": {
                "firstenv": {
                    "type": "dummy", "admin-secret": "homer"}}}
        self.write_config(dump(config))
        self.setup_cli_reactor()
        self.setup_exit(0)

        provider = self.mocker.patch(MachineProvider)
        provider.connect(share=True)

        hanging_deferred = self.mocker.replace(open_tunnel.hanging_deferred)

        def callback(deferred):
            deferred.callback(None)
            return deferred

        hanging_deferred()
        self.mocker.passthrough(callback)
        self.mocker.replay()

        self.capture_stream("stderr")
        main(["open-tunnel"])

        lines = filter(None, self.log.getvalue().split("\n"))
        self.assertEqual(
            lines,
            ["Tunnel to the environment is open. Press CTRL-C to close it.",
             "'open_tunnel' command finished successfully"])
Example #8
0
 def test_custom_parser_does_not_extend_to_subcommand(self):
     stderr = self.capture_stream("stderr")
     self.mocker.replay()
     try:
         main(["deploy"])
     except SystemExit, e:
         self.assertEqual(e.args[0], 2)
Example #9
0
    def test_deploy_policy_from_environment(self):
        config = {"environments": {"firstenv": {"placement": "local", "type": "dummy", "default-series": "series"}}}

        self.write_config(yaml.dump(config))
        self.config.load()

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main(
            [
                "deploy",
                "--environment",
                "firstenv",
                "--repository",
                self.unbundled_repo_path,
                "local:sample",
                "beekeeper",
            ]
        )
        yield finished

        # and verify its placed on node 0 (as per local policy)
        service = yield self.service_state_manager.get_service_state("beekeeper")
        units = yield service.get_all_unit_states()
        unit = units[0]
        machine_id = yield unit.get_assigned_machine_id()
        self.assertEqual(machine_id, 0)
Example #10
0
    def test_deploy_multiple_environments_none_specified(self):
        """
        If multiple environments are configured, with no default,
        one must be specified for the deploy command.
        """
        self.capture_logging()
        self.setup_cli_reactor()
        self.setup_exit(1)
        self.mocker.replay()

        config = {
            "environments": {
                "firstenv": {
                    "type": "dummy",
                    "admin-secret": "homer"
                },
                "secondenv": {
                    "type": "dummy",
                    "admin-secret": "marge"
                }
            }
        }

        self.write_config(yaml.dump(config))
        stderr = self.capture_stream("stderr")
        main(["deploy", "--repository", self.unbundled_repo_path, "mysql"])
        self.assertIn("There are multiple environments", stderr.getvalue())
Example #11
0
    def test_deploy_policy_from_environment(self):
        config = {
            "environments": {
                "firstenv": {
                    "placement": "local",
                    "type": "dummy",
                    "default-series": "series"
                }
            }
        }

        self.write_config(yaml.dump(config))
        self.config.load()

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main([
            "deploy", "--environment", "firstenv", "--repository",
            self.unbundled_repo_path, "local:sample", "beekeeper"
        ])
        yield finished

        # and verify its placed on node 0 (as per local policy)
        service = yield self.service_state_manager.get_service_state(
            "beekeeper")
        units = yield service.get_all_unit_states()
        unit = units[0]
        machine_id = yield unit.get_assigned_machine_id()
        self.assertEqual(machine_id, 0)
Example #12
0
    def xtest_deploy_with_nonexistent_environment_specified(self):
        self.capture_logging()
        self.setup_cli_reactor()
        self.setup_exit(1)
        self.mocker.replay()

        config = {
            "environments": {
                "firstenv": {
                    "type": "dummy",
                    "admin-secret": "homer"
                },
                "secondenv": {
                    "type": "dummy",
                    "admin-secret": "marge"
                }
            }
        }

        self.write_config(yaml.dump(config))

        stderr = self.capture_stream("stderr")
        main([
            "deploy", "--environment", "roman-candle", "--repository",
            self.unbundled_repo_path, "sample"
        ])
        self.assertIn("Invalid environment 'roman-candle'", stderr.getvalue())
Example #13
0
    def test_include_log(self):
        """Messages can be filtered to include only certain log channels."""
        log = yield self.get_configured_log("hook.output", "unit:cassandra/1")
        log2 = yield self.get_configured_log("unit.workflow", "unit:mysql/1")
        log3 = yield self.get_configured_log("provisioning", "agent:provision")

        for i in range(5):
            log.info(str(i))

        for i in range(5):
            log2.info(str(i))

        for i in range(5):
            log3.info(str(i))

        cli_done = self.setup_cli_reactor()
        self.setup_exit()
        self.mocker.replay()

        stream = self.capture_stream("stdout")
        main(["debug-log", "--include", "unit.workflow",
              "-i", "agent:provision", "--limit", "8"])
        yield cli_done

        output = stream.getvalue()
        self.assertNotIn("cassandra/1", output)
        self.assertIn("mysql/1", output)
        self.assertIn("provisioning", output)
Example #14
0
    def test_include_agent(self):
        """Messages can be filtered to include only certain agents."""
        log = yield self.get_configured_log("hook.output", "unit:cassandra/10")
        log2 = yield self.get_configured_log("hook.output", "unit:cassandra/1")
        # example of an agent context name sans ":"
        log3 = yield self.get_configured_log("unit.workflow", "mysql/1")

        for i in range(5):
            log.info(str(i))

        for i in range(5):
            log2.info(str(i))

        for i in range(5):
            log3.info(str(i))

        cli_done = self.setup_cli_reactor()
        self.setup_exit()
        self.mocker.replay()

        stream = self.capture_stream("stdout")
        main(["debug-log", "--include", "cassandra/1", "--limit", "4"])
        yield cli_done

        output = stream.getvalue()
        self.assertNotIn("mysql/1", output)
        self.assertNotIn("cassandra/10", output)
        self.assertIn("cassandra/1", output)
Example #15
0
    def test_remove_unassigned_unit(self):
        """Remove unit also works if the unit is unassigned to a machine.
        """
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 3)

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main(["remove-unit", "mysql/1"])
        yield finished

        # verify the unit and its machine assignment.
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 2)

        topology = yield self.get_topology()
        topology = yield self.get_topology()
        self.assertFalse(
            topology.has_service_unit(self.service_state1.internal_id,
                                      self.service_unit2.internal_id))

        topology = yield self.get_topology()
        self.assertTrue(
            topology.has_service_unit(self.service_state1.internal_id,
                                      self.service_unit1.internal_id))
Example #16
0
 def test_terminate_unused_machine(self):
     """Verify a typical allocation, unassignment, and then termination."""
     wait_on_reactor_stopped = self.setup_cli_reactor()
     self.setup_exit(0)
     self.mocker.replay()
     wordpress_service_state = \
         yield self.add_service_from_charm("wordpress")
     wordpress_unit_state = yield wordpress_service_state.add_unit_state()
     wordpress_machine_state = \
         yield self.machine_state_manager.add_machine_state()
     yield wordpress_unit_state.assign_to_machine(wordpress_machine_state)
     riak_service_state = yield self.add_service_from_charm("riak")
     riak_unit_state = yield riak_service_state.add_unit_state()
     riak_machine_state = \
         yield self.machine_state_manager.add_machine_state()
     yield riak_unit_state.assign_to_machine(riak_machine_state)
     mysql_service_state = yield self.add_service_from_charm("mysql")
     mysql_unit_state = yield mysql_service_state.add_unit_state()
     mysql_machine_state = \
         yield self.machine_state_manager.add_machine_state()
     yield mysql_unit_state.assign_to_machine(mysql_machine_state)
     yield wordpress_unit_state.unassign_from_machine()
     yield mysql_unit_state.unassign_from_machine()
     yield self.assert_machine_states([0, 1, 2, 3], [])
     main(["terminate-machine", "1", "3"])
     yield wait_on_reactor_stopped
     self.assertIn(
         "Machines terminated: 1, 3", self.output.getvalue())
     yield self.assert_machine_states([0, 2], [1, 3])
Example #17
0
    def test_remove_multiple_units(self):
        """
        'juju remove-unit <unit_name1> <unit_name2>...' removes desired units.
        """
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 3)

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main(["remove-unit", "mysql/0", "mysql/2"])
        yield finished

        topology = yield self.get_topology()
        self.assertFalse(
            topology.has_service_unit(self.service_state1.internal_id,
                                      self.service_unit1.internal_id))

        topology = yield self.get_topology()
        self.assertTrue(
            topology.has_service_unit(self.service_state1.internal_id,
                                      self.service_unit2.internal_id))

        self.assertFalse(
            topology.get_service_units_in_machine(self.machine.internal_id))

        self.assertIn("Unit 'mysql/0' removed from service 'mysql'",
                      self.output.getvalue())
        self.assertIn("Unit 'mysql/2' removed from service 'mysql'",
                      self.output.getvalue())
Example #18
0
    def test_passthrough_args(self):
        """Verify that args are passed through to the underlying scp command.

        For example, something like the following command should be valid::

          $ juju scp -o "ConnectTimeout 60" foo mysql/0:/foo/bar
        """
        mock_environment = self.mocker.patch(Environment)
        mock_environment.get_machine_provider()
        self.mocker.result(self.provider)

        # Verify expected call against scp
        mock_exec = self.mocker.replace(os.execvp)
        mock_exec("scp", [
            "scp", "-r", "-o", "ConnectTimeout 60", "foo",
            "[email protected]:/foo/bar"
        ])

        # But no other calls
        calls = []
        mock_exec(ARGS, KWARGS)
        self.mocker.count(0, None)
        self.mocker.call(lambda *args, **kwargs: calls.append((args, kwargs)))

        finished = self.setup_cli_reactor()
        self.mocker.replay()

        main([
            "scp", "-r", "-o", "ConnectTimeout 60", "foo", "mysql/0:/foo/bar"
        ])
        yield finished
        self.assertEquals(calls, [])
Example #19
0
    def test_passthrough_args(self):
        """Verify that args are passed through to the underlying scp command.

        For example, something like the following command should be valid::

          $ juju scp -o "ConnectTimeout 60" foo mysql/0:/foo/bar
        """
        # Verify expected call against scp
        mock_exec = self.mocker.replace(os.execvp)
        mock_exec("scp", [
            "scp", "-r", "-o", "ConnectTimeout 60",
            "foo", "[email protected]:/foo/bar"])

        # But no other calls
        calls = []
        mock_exec(ARGS, KWARGS)
        self.mocker.count(0, None)
        self.mocker.call(lambda *args, **kwargs: calls.append((args, kwargs)))

        finished = self.setup_cli_reactor()
        self.mocker.replay()

        main(["scp", "-r", "-o", "ConnectTimeout 60",
              "foo", "mysql/0:/foo/bar"])
        yield finished
        self.assertEquals(calls, [])
Example #20
0
    def test_shell_with_unit(self):
        """
        'juju ssh mysql/0' will execute ssh against the machine
        hosting the unit.
        """
        mock_environment = self.mocker.patch(Environment)
        mock_environment.get_machine_provider()
        self.mocker.result(self.provider)

        mock_exec = self.mocker.replace(os.execvp)
        mock_exec("ssh", [
            "ssh",
            "-o",
            "ControlPath " + self.tmp_home + "/.juju/ssh/master-%r@%h:%p",
            "-o", "ControlMaster no",
            "*****@*****.**"])

        # Track unwanted calls:
        calls = []
        mock_exec(ARGS, KWARGS)
        self.mocker.count(0, None)
        self.mocker.call(lambda *args, **kwargs: calls.append((args, kwargs)))

        finished = self.setup_cli_reactor()
        self.mocker.replay()
        yield self.unit.connect_agent()

        main(["ssh", self.unit.unit_name])
        yield finished

        self.assertEquals(calls, [])
        self.assertIn(
            "Connecting to unit mysql/0 at mysql-0.example.com",
            self.output.getvalue())
Example #21
0
 def test_custom_parser_does_not_extend_to_subcommand(self):
     stderr = self.capture_stream("stderr")
     self.mocker.replay()
     try:
         main(["deploy"])
     except SystemExit, e:
         self.assertEqual(e.args[0], 2)
Example #22
0
    def test_destroy_environment(self):
        """Command will terminate instances in only one environment."""
        config = {
            "environments": {"firstenv": {"type": "dummy"},
                             "secondenv": {"type": "dummy"}}}
        self.write_config(dump(config))
        finished = self.setup_cli_reactor()

        envs = set(("firstenv", "secondenv"))

        def track_destroy_environment_call(self):
            envs.remove(self.environment_name)
            return succeed(True)

        provider = self.mocker.patch(MachineProvider)
        provider.destroy_environment()
        self.mocker.call(track_destroy_environment_call, with_object=True)

        self.setup_exit(0)
        mock_raw = self.mocker.replace(raw_input)
        mock_raw(MATCH(lambda x: x.startswith(
                    "WARNING: this command will destroy the 'secondenv' "
                    "environment (type: dummy)")))
        self.mocker.result("y")
        self.mocker.replay()

        main(["destroy-environment", "-e", "secondenv"])
        yield finished
        self.assertIn("Destroying environment 'secondenv' (type: dummy)...",
                      self.log.getvalue())
        self.assertEqual(envs, set(["firstenv"]))
Example #23
0
    def test_resolved_relation_already_running(self):
        """
        'juju resolved <unit_name> <rel_name>' will report
        if the relation is already running.
        """
        service2 = yield self.service_state_manager.get_service_state(
            "wordpress")
        service_unit1 = yield service2.add_unit_state()

        service_relation = yield self.get_named_service_relation(
            service2, "db")
        yield self.setup_unit_relations(
            service_relation, (service_unit1, "up"))

        self.setup_exit(0)
        finished = self.setup_cli_reactor()
        self.mocker.replay()

        main(["resolved", "wordpress/0", "db"])
        yield finished

        self.assertIn("Matched relations are all running",
                      self.output.getvalue())
        self.assertEqual(
            (yield service_unit1.get_relation_resolved()),
            None)
Example #24
0
    def test_resolved_relation_some_already_resolved_conflict(self):
        """
        'juju resolved <service_name> <rel_name>' will mark
        resolved all down units that are not already marked resolved.
        """

        service2 = yield self.service_state_manager.get_service_state(
            "wordpress")
        service_unit1 = yield service2.add_unit_state()

        service_relation = yield self.get_named_service_relation(
            service2, "db")
        yield self.setup_unit_relations(service_relation,
                                        (service_unit1, "down"))

        yield service_unit1.set_relation_resolved(
            {service_relation.internal_relation_id: NO_HOOKS})

        self.setup_exit(0)
        finished = self.setup_cli_reactor()
        self.mocker.replay()

        main(["resolved", "--retry", "wordpress/0", "db"])
        yield finished

        self.assertEqual((yield service_unit1.get_relation_resolved()),
                         {service_relation.internal_relation_id: NO_HOOKS})

        self.assertIn(
            "Service unit 'wordpress/0' already has relations marked as resol",
            self.output.getvalue())
Example #25
0
    def test_relation_resolved(self):
        """
        'juju relation <unit_name> <rel_name>' will schedule
        the broken unit relations for being resolved.
        """
        service_relation = yield self.get_named_service_relation(
            self.service1, "server")

        yield self.setup_unit_relations(
            service_relation,
            (self.service_unit1, "down"),
            (self.service_unit2, "up"))

        yield self.unit1_workflow.set_state("start_error")
        self.setup_exit(0)
        finished = self.setup_cli_reactor()
        self.mocker.replay()

        self.assertEqual(
            (yield self.service_unit1.get_relation_resolved()), None)

        main(["resolved", "--retry", "mysql/0",
              service_relation.relation_name])
        yield finished

        self.assertEqual(
            (yield self.service_unit1.get_relation_resolved()),
            {service_relation.internal_relation_id: RETRY_HOOKS})
        self.assertEqual(
            (yield self.service_unit2.get_relation_resolved()),
            None)
        self.assertIn(
            "Marked unit 'mysql/0' relation 'server' as resolved",
            self.output.getvalue())
Example #26
0
    def test_resolved_already_running(self):
        """
        'juju resolved <unit_name>' will report if
        the unit is already running.
        """
        # Just verify we don't accidentally mark up another unit of the service
        unit2_workflow = UnitWorkflowState(
            self.client, self.service_unit2, None, self.makeDir())
        unit2_workflow.set_state("start_error")

        self.setup_exit(0)
        finished = self.setup_cli_reactor()
        self.mocker.replay()

        main(["resolved", "mysql/0"])
        yield finished

        self.assertEqual(
            (yield self.service_unit2.get_resolved()), None)
        self.assertEqual(
            (yield self.service_unit1.get_resolved()), None)

        self.assertNotIn(
            "Unit 'mysql/0 already running: started",
            self.output.getvalue())
Example #27
0
    def test_latest_local_leapfrog_dry_run(self):
        """Do nothing; log that local charm would be re-revisioned and used"""
        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()

        metadata = self.charm.metadata.get_serialization_data()
        metadata["name"] = "mysql"
        repository = self.add_charm(metadata, 0)
        main(["upgrade-charm", "--dry-run",
                  "--repository", repository.path, "mysql"])
        yield finished
        charm_path = os.path.join(repository.path, "series", "mysql")
        self.assertIn(
            "%s would be set to revision 2" % charm_path,
            self.output.getvalue())
        self.assertIn(
            "Service would be upgraded from charm 'local:series/mysql-1' to "
            "'local:series/mysql-2'",
            self.output.getvalue())

        with open(os.path.join(charm_path, "revision")) as f:
            self.assertEquals(f.read(), "0")

        upgrade_flag = yield self.service_unit1.get_upgrade_flag()
        self.assertFalse(upgrade_flag)
    def test_terminate_unused_machine(self):
        """Verify a typical allocation, unassignment, and then termination."""
        wait_on_reactor_stopped = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        wordpress_service_state = \
            yield self.add_service_from_charm("wordpress")
        wordpress_unit_state = yield wordpress_service_state.add_unit_state()
        wordpress_machine_state = yield self.add_machine_state()
        yield wordpress_unit_state.assign_to_machine(wordpress_machine_state)
        riak_service_state = yield self.add_service_from_charm("riak")
        riak_unit_state = yield riak_service_state.add_unit_state()
        riak_machine_state = yield self.add_machine_state()
        yield riak_unit_state.assign_to_machine(riak_machine_state)
        mysql_service_state = yield self.add_service_from_charm("mysql")
        mysql_unit_state = yield mysql_service_state.add_unit_state()
        mysql_machine_state = yield self.add_machine_state()
        yield mysql_unit_state.assign_to_machine(mysql_machine_state)
        yield wordpress_unit_state.unassign_from_machine()
        yield mysql_unit_state.unassign_from_machine()
        yield self.assert_machine_states([0, 1, 2, 3], [])

        # trash environment to check syncing
        yield self.client.delete("/environment")
        main(["terminate-machine", "1", "3"])
        yield wait_on_reactor_stopped

        # check environment synced
        esm = EnvironmentStateManager(self.client)
        yield esm.get_config()

        self.assertIn(
            "Machines terminated: 1, 3", self.output.getvalue())
        yield self.assert_machine_states([0, 2], [1, 3])
Example #29
0
    def test_add_unit(self):
        """
        'juju add-unit <service_name>' will add a new service
        unit of the given service.
        """
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 1)

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        # trash environment to check syncing
        yield self.client.delete("/environment")
        main(["add-unit", "mysql"])
        yield finished

        # verify the env state was synced
        esm = EnvironmentStateManager(self.client)
        yield esm.get_config()

        # verify the unit and its machine assignment.
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 2)

        topology = yield self.get_topology()
        unit = yield self.service_state1.get_unit_state("mysql/1")
        machine_id = topology.get_service_unit_machine(self.service_state1.internal_id, unit.internal_id)
        self.assertNotEqual(machine_id, None)
        self.assertIn("Unit 'mysql/1' added to service 'mysql'", self.output.getvalue())
        yield self.assert_machine_assignments("mysql", [1, 2])
Example #30
0
    def test_add_multiple_units(self):
        """
        'juju add-unit <service_name>' will add a new service
        unit of the given service.
        """
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 1)

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main(["add-unit", "--num-units", "5", "mysql"])
        yield finished

        # verify the unit and its machine assignment.
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 6)

        topology = yield self.get_topology()
        unit = yield self.service_state1.get_unit_state("mysql/1")
        machine_id = topology.get_service_unit_machine(self.service_state1.internal_id, unit.internal_id)
        self.assertNotEqual(machine_id, None)
        for i in xrange(1, 6):
            self.assertIn("Unit 'mysql/%d' added to service 'mysql'" % i, self.output.getvalue())
        yield self.assert_machine_assignments("mysql", [1, 2, 3, 4, 5, 6])
Example #31
0
    def test_log_object(self):
        """Messages that utilize string interpolation are rendered correctly.
        """

        class Foobar(object):
            def __init__(self, v):
                self._v = v

            def __str__(self):
                return str("Foobar:%s" % self._v)

        log = yield self.get_configured_log("unit.workflow", "unit:mysql/1")

        log.info("found a %s", Foobar(21))
        log.info("jack jumped into a %s", Foobar("cauldron"))

        cli_done = self.setup_cli_reactor()
        self.setup_exit()
        self.mocker.replay()

        stream = self.capture_stream("stdout")
        main(["debug-log", "--limit", "2"])
        yield cli_done

        output = stream.getvalue()

        self.assertIn("Foobar:21", output)
        self.assertIn("Foobar:cauldron", output)
Example #32
0
    def test_policy_from_environment(self):
        config = {"environments": {"firstenv": {"placement": "local", "type": "dummy"}}}
        yield self.push_config("firstenv", config)

        ms0 = yield self.machine_state_manager.get_machine_state(0)
        yield self.service_unit1.unassign_from_machine()
        yield self.service_unit1.assign_to_machine(ms0)

        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 1)

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main(["add-unit", "mysql"])
        yield finished

        # Verify the local policy was used
        topology = yield self.get_topology()
        unit = yield self.service_state1.get_unit_state("mysql/1")
        machine_id = topology.get_service_unit_machine(self.service_state1.internal_id, unit.internal_id)
        self.assertNotEqual(machine_id, None)
        self.assertIn("Unit 'mysql/1' added to service 'mysql'", self.output.getvalue())
        # adding a second unit still assigns to machine 0 with local policy
        yield self.assert_machine_assignments("mysql", [0, 0])
Example #33
0
    def test_shell_with_machine_and_unconnected_machine_agent(self):
        """If a machine doesn't have a connected machine agent,
        the ssh command will wait till one exists before connecting.
        """
        mock_environment = self.mocker.patch(Environment)
        mock_environment.get_machine_provider()
        self.mocker.result(self.provider)

        mock_machine = self.mocker.patch(MachineState)
        mock_machine.watch_agent()
        self.mocker.result((succeed(False), succeed(True)))
        mock_exec = self.mocker.replace(os.execvp)
        mock_exec("ssh", [
            "ssh",
            "-o",
            "ControlPath " + self.tmp_home + "/.juju/ssh/master-%r@%h:%p",
            "-o", "ControlMaster no",
            "*****@*****.**"])

        # Track unwanted calls:
        calls = []
        mock_exec(ARGS, KWARGS)
        self.mocker.count(0, None)
        self.mocker.call(lambda *args, **kwargs: calls.append((args, kwargs)))

        finished = self.setup_cli_reactor()
        self.mocker.replay()
        yield self.machine.connect_agent()
        main(["ssh", "0"])
        yield finished

        self.assertEquals(calls, [])

        self.assertIn(
            "Waiting for machine to come up", self.output.getvalue())
Example #34
0
    def verify_hook_debug(self, *hook_names):
        """Utility function to verify hook debugging by name
        """
        mock_environment = self.mocker.patch(Environment)
        mock_environment.get_machine_provider()
        self.mocker.result(self.provider)

        system_mock = self.mocker.replace(os.system)
        system_mock(ANY)

        def on_ssh(command):
            self.assertStartsWith(command, "ssh -t [email protected]")
            self.assertEqual(
                (yield self.unit.get_hook_debug()),
                {"debug_hooks": list(hook_names)})
            returnValue(True)

        self.mocker.call(on_ssh)

        finished = self.setup_cli_reactor()
        self.mocker.replay()

        yield self.unit.set_public_address("x11.example.com")

        args = ["debug-hooks", "mysql/0"]
        args.extend(hook_names)
        main(args)

        yield finished

        self.assertIn(
            "Connecting to remote machine", self.output.getvalue())

        self.assertIn(
            "Debug session ended.", self.output.getvalue())
Example #35
0
    def test_debug_hook(self):
        """The debug cli will setup unit debug setting and ssh to a screen.
        """
        system_mock = self.mocker.replace(os.system)
        system_mock(ANY)

        def on_ssh(command):
            self.assertStartsWith(command, "ssh -t [email protected]")
            # In the function, os.system yields to faciliate testing.
            self.assertEqual(
                (yield self.unit.get_hook_debug()),
                {"debug_hooks": ["*"]})
            returnValue(True)

        self.mocker.call(on_ssh)

        finished = self.setup_cli_reactor()
        self.mocker.replay()

        # Setup the unit address.
        yield self.unit.set_public_address("x2.example.com")

        main(["debug-hooks", "mysql/0"])
        yield finished

        self.assertIn(
            "Connecting to remote machine", self.output.getvalue())

        self.assertIn(
            "Debug session ended.", self.output.getvalue())
Example #36
0
    def test_get_service_config(self):
        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()

        self.service_state = yield self.add_service_from_charm("wordpress")
        config = yield self.service_state.get_config()
        # The value which isn't in the config won't be displayed.
        settings = {"blog-title": "Hello World", "world": 123}
        config.update(settings)
        yield config.write()

        output = self.capture_stream("stdout")
        main(["get", "wordpress"])

        yield finished
        data = yaml.load(output.getvalue())
        self.assertEqual(
            {
                "service": "wordpress",
                "charm": "local:series/wordpress-3",
                'settings': {
                    'blog-title': {
                        'description':
                        'A descriptive title used for the blog.',
                        'type': 'string',
                        'value': 'Hello World'
                    }
                }
            }, data)
Example #37
0
 def test_add_unit_unknown_service(self):
     finished = self.setup_cli_reactor()
     self.setup_exit(0)
     self.mocker.replay()
     main(["add-unit", "volcano"])
     yield finished
     self.assertIn("Service 'volcano' was not found", self.stderr.getvalue())
Example #38
0
    def test_upgrade_charm_dryrun_reports_unupgradeable_units(self):
        """If there are units that won't be upgraded, dry-run will report them.
        """
        repository = self.increment_charm(self.charm)
        service_unit2 = yield self.service_state1.add_unit_state()

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()

        main(["upgrade-charm", "-n",
              "--repository", repository.path, "mysql"])
        yield finished

        # Verify dry run
        self.assertIn(
            "Service would be upgraded from charm", self.output.getvalue())
        # Verify report of unupgradeable units
        self.assertIn(
            ("Unit 'mysql/1' is not in a running state "
            "(state: 'uninitialized'), won't upgrade"),
            self.output.getvalue())

        # Verify no flags have been set.
        value = (yield service_unit2.get_upgrade_flag())
        self.assertFalse(value)
        value = (yield self.service_unit1.get_upgrade_flag())
        self.assertFalse(value)
Example #39
0
    def test_deploy_with_environment_specified(self):
        self.setup_cli_reactor()
        self.setup_exit(0)

        command = self.mocker.replace("juju.control.deploy.deploy")
        config = {
            "environments": {
                "firstenv": {
                    "type": "dummy", "admin-secret": "homer"},
                "secondenv": {
                    "type": "dummy", "admin-secret": "marge"}}}

        self.write_config(yaml.dump(config))

        def match_config(config):
            return isinstance(config, EnvironmentsConfig)

        def match_environment(environment):
            return isinstance(environment, Environment) and \
                   environment.name == "secondenv"

        command(MATCH(match_config), MATCH(match_environment),
                self.unbundled_repo_path, "local:sample", None,
                MATCH(lambda x: isinstance(x, logging.Logger)),
                ["cpu=36", "mem=64G"], None, False, num_units=1)
        self.mocker.replay()
        self.mocker.result(succeed(True))

        main(["deploy", "--environment", "secondenv", "--repository",
              self.unbundled_repo_path, "--constraints", "cpu=36 mem=64G",
              "local:sample"])
Example #40
0
    def test_charm_upgrade(self):
        """
        'juju charm-upgrade <service_name>' will schedule
        a charm for upgrade.
        """
        repository = self.increment_charm(self.charm)

        mock_environment = self.mocker.patch(Environment)
        mock_environment.get_machine_provider()
        self.mocker.result(self.provider)

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main(["upgrade-charm", "--repository", repository.path, "mysql"])
        yield finished

        # Verify the service has a new charm reference
        charm_id = yield self.service_state1.get_charm_id()
        self.assertEqual(charm_id, "local:series/mysql-2")

        # Verify the provider storage has been updated
        charm = yield repository.find(CharmURL.parse("local:series/mysql"))
        storage = self.provider.get_file_storage()
        try:
            yield storage.get(
                "local_3a_series_2f_mysql-2_3a_%s" % charm.get_sha256())
        except FileNotFound:
            self.fail("New charm not uploaded")

        # Verify the upgrade flag on the service units.
        upgrade_flag = yield self.service_unit1.get_upgrade_flag()
        self.assertTrue(upgrade_flag)
Example #41
0
    def test_deploy_informs_with_subordinate(self):
        """Verify subordinate charm doesn't deploy.

        And that it properly notifies the user.
        """
        log = self.capture_logging()
        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()

        # missing config file
        main(["deploy",
            "--repository", self.unbundled_repo_path, "local:logging"])
        yield finished
        self.assertIn(
            "Subordinate 'logging' awaiting relationship to "
            "principal for deployment.\n",
            log.getvalue())

        # and verify no units assigned to service
        service_state = yield self.service_state_manager.get_service_state("logging")
        self.assertEqual(service_state.service_name, "logging")

        units = yield service_state.get_unit_names()
        self.assertEqual(units, [])
Example #42
0
    def test_bootstrap(self):
        """
        'juju-control bootstrap' will invoke the bootstrap method of all
        configured machine providers in all environments.
        """
        config = {
            "environments": {
                "firstenv": {"type": "dummy", "default-series": "homer"},
                "secondenv": {"type": "dummy", "default-series": "marge"},
            }
        }

        self.write_config(dump(config))
        finished = self.setup_cli_reactor()
        self.setup_exit(0)

        provider = self.mocker.patch(MachineProvider)
        provider.bootstrap(
            {"ubuntu-series": "homer", "provider-type": "dummy", "arch": "arm", "cpu": 2.0, "mem": 512.0}
        )
        self.mocker.result(succeed(True))
        self.mocker.replay()

        self.capture_stream("stderr")
        main(["bootstrap", "-e", "firstenv", "--constraints", "arch=arm cpu=2"])
        yield finished

        lines = filter(None, self.log.getvalue().split("\n"))
        self.assertEqual(
            lines,
            [
                ("Bootstrapping environment 'firstenv' " "(origin: distro type: dummy)..."),
                "'bootstrap' command finished successfully",
            ],
        )
Example #43
0
    def test_deploy_legacy_keys_in_fresh_env(self):
        yield self.push_default_config()
        local_config = {
            "environments": {"firstenv": {
                    "type": "dummy",
                    "some-legacy-key": "blah",
                    "default-series": "series"}}}
        self.write_config(yaml.dump(local_config))
        self.config.load()
        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        stderr = self.capture_stream("stderr")

        main(["deploy", "--repository", self.unbundled_repo_path,
              "local:sample", "beekeeper"])
        yield finished

        self.assertIn(
            "Your environments.yaml contains deprecated keys",
            stderr.getvalue())
        service_manager = ServiceStateManager(self.client)
        yield self.assertFailure(
            service_manager.get_service_state("beekeeper"),
            ServiceStateNotFound)
Example #44
0
    def test_resolved_relation_some_already_resolved_conflict(self):
        """
        'juju resolved <service_name> <rel_name>' will mark
        resolved all down units that are not already marked resolved.
        """

        service2 = yield self.service_state_manager.get_service_state(
            "wordpress")
        service_unit1 = yield service2.add_unit_state()

        service_relation = yield self.get_named_service_relation(
            service2, "db")
        yield self.setup_unit_relations(
            service_relation, (service_unit1, "down"))

        yield service_unit1.set_relation_resolved(
            {service_relation.internal_relation_id: NO_HOOKS})

        self.setup_exit(0)
        finished = self.setup_cli_reactor()
        self.mocker.replay()

        main(["resolved", "--retry", "wordpress/0", "db"])
        yield finished

        self.assertEqual(
            (yield service_unit1.get_relation_resolved()),
            {service_relation.internal_relation_id: NO_HOOKS})

        self.assertIn(
            "Service unit 'wordpress/0' already has relations marked as resol",
            self.output.getvalue())
Example #45
0
    def test_remove_multiple_units(self):
        """
        'juju remove-unit <unit_name1> <unit_name2>...' removes desired units.
        """
        unit_names = yield self.service_state1.get_unit_names()
        self.assertEqual(len(unit_names), 3)

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()
        main(["remove-unit", "mysql/0", "mysql/2"])
        yield finished

        topology = yield self.get_topology()
        self.assertFalse(topology.has_service_unit(
            self.service_state1.internal_id, self.service_unit1.internal_id))

        topology = yield self.get_topology()
        self.assertTrue(topology.has_service_unit(
            self.service_state1.internal_id, self.service_unit2.internal_id))

        self.assertFalse(
            topology.get_service_units_in_machine(self.machine.internal_id))

        self.assertIn(
            "Unit 'mysql/0' removed from service 'mysql'",
            self.output.getvalue())
        self.assertIn(
            "Unit 'mysql/2' removed from service 'mysql'",
            self.output.getvalue())
Example #46
0
    def test_resolved_already_resolved(self):
        """
        'juju resolved <unit_name>' will report if
        the unit is already resolved.
        """
        # Mark the unit as resolved and as in an error state.
        yield self.service_unit1.set_resolved(RETRY_HOOKS)
        yield self.unit1_workflow.set_state("start_error")

        unit2_workflow = UnitWorkflowState(
            self.client, self.service_unit1, None, self.makeDir())
        unit2_workflow.set_state("start_error")

        self.assertEqual(
            (yield self.service_unit2.get_resolved()), None)

        self.setup_exit(0)
        finished = self.setup_cli_reactor()
        self.mocker.replay()

        main(["resolved", "mysql/0"])
        yield finished

        self.assertEqual(
            (yield self.service_unit1.get_resolved()),
            {"retry": RETRY_HOOKS})
        self.assertNotIn(
            "Marked unit 'mysql/0' as resolved",
            self.output.getvalue())
        self.assertIn(
            "Service unit 'mysql/0' is already marked as resolved.",
            self.stderr.getvalue(), "")
Example #47
0
    def test_get_service_config(self):
        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()

        self.service_state = yield self.add_service_from_charm("wordpress")
        config = yield self.service_state.get_config()
        # The value which isn't in the config won't be displayed.
        settings = {"blog-title": "Hello World", "world": 123}
        config.update(settings)
        yield config.write()

        output = self.capture_stream("stdout")
        main(["get", "wordpress"])

        yield finished
        data = yaml.load(output.getvalue())
        self.assertEqual(
            {"service": "wordpress",
             "charm": "local:series/wordpress-3",
             'settings': {'blog-title': {
                 'description': 'A descriptive title used for the blog.',
                 'type': 'string',
                 'value': 'Hello World'}}},
            data)
Example #48
0
    def test_relation_resolved(self):
        """
        'juju relation <unit_name> <rel_name>' will schedule
        the broken unit relations for being resolved.
        """
        service_relation = yield self.get_named_service_relation(
            self.service1, "server")

        yield self.setup_unit_relations(service_relation,
                                        (self.service_unit1, "down"),
                                        (self.service_unit2, "up"))

        yield self.unit1_workflow.set_state("start_error")
        self.setup_exit(0)
        finished = self.setup_cli_reactor()
        self.mocker.replay()

        self.assertEqual((yield self.service_unit1.get_relation_resolved()),
                         None)

        main(
            ["resolved", "--retry", "mysql/0", service_relation.relation_name])
        yield finished

        self.assertEqual((yield self.service_unit1.get_relation_resolved()),
                         {service_relation.internal_relation_id: RETRY_HOOKS})
        self.assertEqual((yield self.service_unit2.get_relation_resolved()),
                         None)
        self.assertIn("Marked unit 'mysql/0' relation 'server' as resolved",
                      self.output.getvalue())
Example #49
0
    def test_upgrade_charm_with_unupgradeable_units(self):
        """If there are units that won't be upgraded, they will be reported,
        other units will be upgraded.
        """
        repository = self.increment_charm(self.charm)
        service_unit2 = yield self.service_state1.add_unit_state()

        finished = self.setup_cli_reactor()
        self.setup_exit(0)
        self.mocker.replay()

        main(["upgrade-charm", "--repository", repository.path, "mysql"])
        yield finished

        # Verify report of unupgradeable units
        self.assertIn(
            ("Unit 'mysql/1' is not in a running state "
            "(state: 'uninitialized'), won't upgrade"),
            self.output.getvalue())

        # Verify flags only set on upgradeable unit.
        value = (yield service_unit2.get_upgrade_flag())
        self.assertFalse(value)
        value = (yield self.service_unit1.get_upgrade_flag())
        self.assertTrue(value)
Example #50
0
    def test_resolved_already_resolved(self):
        """
        'juju resolved <unit_name>' will report if
        the unit is already resolved.
        """
        # Mark the unit as resolved and as in an error state.
        yield self.service_unit1.set_resolved(RETRY_HOOKS)
        yield self.unit1_workflow.set_state("start_error")

        unit2_workflow = UnitWorkflowState(self.client, self.service_unit1,
                                           None, self.makeDir())
        unit2_workflow.set_state("start_error")

        self.assertEqual((yield self.service_unit2.get_resolved()), None)

        self.setup_exit(0)
        finished = self.setup_cli_reactor()
        self.mocker.replay()

        main(["resolved", "mysql/0"])
        yield finished

        self.assertEqual((yield self.service_unit1.get_resolved()),
                         {"retry": RETRY_HOOKS})
        self.assertNotIn("Marked unit 'mysql/0' as resolved",
                         self.output.getvalue())
        self.assertIn("Service unit 'mysql/0' is already marked as resolved.",
                      self.stderr.getvalue(), "")
Example #51
0
    def test_complex_filter(self):
        """Messages can be filtered to include only certain log channels."""
        log = yield self.get_configured_log("hook.output", "unit:cassandra/1")
        log2 = yield self.get_configured_log("hook.output", "unit:cassandra/2")
        log3 = yield self.get_configured_log("hook.output", "unit:cassandra/3")

        for i in range(5):
            log.info(str(i))

        for i in range(5):
            log2.info(str(i))

        for i in range(5):
            log3.info(str(i))

        cli_done = self.setup_cli_reactor()
        self.setup_exit()
        self.mocker.replay()

        stream = self.capture_stream("stdout")
        main(
            ["debug-log", "-i", "cassandra/*", "-x", "cassandra/1", "-n", "8"])
        yield cli_done

        output = stream.getvalue()
        self.assertNotIn("cassandra/1", output)
        self.assertIn("cassandra/2", output)
        self.assertIn("cassandra/3", output)
Example #52
0
 def test_upgrade_charm_unknown_service(self):
     finished = self.setup_cli_reactor()
     self.setup_exit(0)
     self.mocker.replay()
     main(["upgrade-charm", "--repository", self.makeDir(), "volcano"])
     yield finished
     self.assertIn(
         "Service 'volcano' was not found", self.stderr.getvalue())
Example #53
0
 def test_unexpose_unknown_service(self):
     """Test subcommand fails if service does not exist."""
     finished = self.setup_cli_reactor()
     self.setup_exit(0)  # XXX change when bug 697093 is fixed
     self.mocker.replay()
     main(["unexpose", "foobar"])
     yield finished
     self.assertIn("Service 'foobar' was not found", self.stderr.getvalue())