예제 #1
0
    def configure_admin(self):
        """Configure the admin user."""
        hookenv.log("Configuring user for jenkins")

        admin = self._admin_data()
        api = Api(packages=self._packages)
        api.update_password(admin.username, admin.password)

        # Save the password to a file. It's not used directly by this charm
        # but it's convenient for integration with third-party tools.
        host.write_file(paths.ADMIN_PASSWORD,
                        admin.password.encode("utf-8"),
                        owner="root",
                        group="root",
                        perms=0o0600)

        if not os.path.exists(paths.LAST_EXEC):
            # This mean it's the very first time we configure the user,
            # and we want to create this file in order to avoid Jenkins
            # presenting the setup wizard.
            host.write_file(paths.LAST_EXEC,
                            "{}\n".format(api.version()).encode("utf-8"),
                            owner="jenkins",
                            group="nogroup",
                            perms=0o0600)
예제 #2
0
    def configure_admin(self):
        """Configure the admin user."""
        hookenv.log("Configuring user for jenkins")

        admin = self._admin_data()
        api = Api()
        api.update_password(admin.username, admin.password)

        # Save the password to a file. It's not used directly by this charm
        # but it's convenient for integration with third-party tools.
        host.write_file(
            paths.ADMIN_PASSWORD, admin.password.encode("utf-8"),
            owner="root", group="root", perms=0o0600)

        if not os.path.exists(paths.LAST_EXEC):
            # This mean it's the very first time we configure the user,
            # and we want to create this file in order to avoid Jenkins
            # presenting the setup wizard.
            host.write_file(
                paths.LAST_EXEC, "{}\n".format(api.version()).encode("utf-8"),
                owner="jenkins", group="nogroup")
예제 #3
0
class ApiTest(JenkinsTest):
    def setUp(self):
        super(ApiTest, self).setUp()
        self.useFixture(JenkinsConfiguredAdmin(self.fakes))
        self.fakes.jenkins.scripts[GET_LEGACY_TOKEN_SCRIPT.format(
            "admin")] = "abc\n"
        self.fakes.jenkins.scripts[GET_NEW_TOKEN_SCRIPT.format(
            "admin")] = "xyz\n"
        self.apt = AptStub()
        self.packages = Packages(apt=self.apt)
        self.api = Api(packages=self.packages)

    def test_wait_transient_failure(self):
        """
        Wait for Jenkins to be fully up, even in spite of transient failures.
        """
        self.apt._set_jenkins_version('2.120.1')
        get_whoami = self.fakes.jenkins.get_whoami
        tries = []

        def transient_failure():
            try:
                if not tries:
                    raise JenkinsException("error")
                get_whoami()
            finally:
                tries.append(True)

        self.fakes.jenkins.get_whoami = transient_failure
        self.assertIsNone(self.api.wait())

    def test_update_password(self):
        """
        The update_password() method runs a groovy script to update the
        password for the given user.
        """
        self.apt._set_jenkins_version('2.120.1')
        username = "******"
        password = "******"
        script = UPDATE_PASSWORD_SCRIPT.format(username=username,
                                               password=password)
        self.fakes.jenkins.scripts[script] = ""
        self.assertIsNone(self.api.update_password(username, password))

    def test_version(self):
        """The version() method returns the version of the Jenkins server."""
        self.apt._set_jenkins_version('2.120.1')
        self.assertEqual("2.0.0", self.api.version())

    def test_new_token_script(self):
        self.apt._set_jenkins_version('2.150.1')
        self.assertEqual("2.0.0", self.api.version())

    def test_add(self):
        """
        A slave node can be added by specifying executors and labels.
        """
        self.apt._set_jenkins_version('2.120.1')
        self.api.add_node("slave-0", 1, labels=["python"])
        [node] = self.fakes.jenkins.nodes
        self.assertEqual("slave-0", node.host)
        self.assertEqual(1, node.executors)
        self.assertEqual("slave-0", node.description)
        self.assertEqual(["python"], node.labels)
        self.assertEqual("hudson.slaves.JNLPLauncher", node.launcher)

    def test_add_exists(self):
        """
        If a node already exists, nothing is done.
        """
        self.apt._set_jenkins_version('2.120.1')
        self.fakes.jenkins.create_node("slave-0", 1, "slave-0")
        self.api.add_node("slave-0", 1, labels=["python"])
        self.assertEqual(1, len(self.fakes.jenkins.nodes))

    def test_add_transient_failure(self):
        """
        Transient failures get retried.
        """
        self.apt._set_jenkins_version('2.120.1')
        create_node = self.fakes.jenkins.create_node
        tries = []

        def transient_failure(*args, **kwargs):
            try:
                if not tries:
                    raise JenkinsException("error")
                create_node(*args, **kwargs)
            finally:
                tries.append(True)

        self.fakes.jenkins.create_node = transient_failure
        self.api.add_node("slave-0", 1, labels=["python"])
        self.assertEqual(1, len(self.fakes.jenkins.nodes))

    def test_add_retry_give_up(self):
        """
        If errors persist, we give up.
        """
        self.apt._set_jenkins_version('2.120.1')

        def failure(*args, **kwargs):
            raise JenkinsException("error")

        self.fakes.jenkins.create_node = failure
        self.assertRaises(JenkinsException, self.api.add_node, "slave-0", 1)

    def test_add_spurious(self):
        """
        If adding a node apparently succeeds, but actually didn't then we
        log an error.
        """
        self.apt._set_jenkins_version('2.120.1')
        self.fakes.jenkins.create_node = lambda *args, **kwargs: None
        self.api.add_node("slave-0", 1, labels=["python"])
        self.assertEqual("ERROR: Failed to create node 'slave-0'",
                         self.fakes.juju.log[-1])

    def test_deleted(self):
        """
        A slave node can be deleted by specifyng its host name.
        """
        self.apt._set_jenkins_version('2.120.1')
        self.api.add_node("slave-0", 1, labels=["python"])
        self.api.delete_node("slave-0")
        self.assertEqual([], self.fakes.jenkins.nodes)

    def test_deleted_no_present(self):
        """
        If a slave node doesn't exists, deleting it is a no-op.
        """
        self.apt._set_jenkins_version('2.120.1')
        self.api.delete_node("slave-0")
        self.assertEqual([], self.fakes.jenkins.nodes)

    def _make_httperror(self, url, status_code, reason):
        response = Response()
        response.reason = reason
        response.status_code = status_code
        response.url = url
        return HTTPError(request=Request('POST', url), response=response)

    def test_reload(self):
        """
        The reload method POSTs a request to the '/reload' URL, expecting
        a 503 on the homepage (which happens after redirection).
        """
        self.apt._set_jenkins_version('2.120.1')
        error = self._make_httperror(self.api.url, 503, "Service Unavailable")
        self.fakes.jenkins.responses[urljoin(self.api.url, "reload")] = error
        self.api.reload()

    def test_restart(self):
        """
        The reload method POSTs a request to the '/reload' URL, expecting
        a 503 on the homepage (which happens after redirection).
        """
        self.apt._set_jenkins_version('2.120.1')
        error = self._make_httperror(self.api.url, 503, "Service Unavailable")
        self.fakes.jenkins.responses[urljoin(self.api.url,
                                             "safeRestart")] = error
        self.api.restart()

    def test_reload_unexpected_error(self):
        """
        If the error code is not 403, the error is propagated.
        """
        self.apt._set_jenkins_version('2.120.1')
        error = self._make_httperror(self.api.url, 403, "Forbidden")
        self.fakes.jenkins.responses[urljoin(self.api.url, "reload")] = error
        self.assertRaises(HTTPError, self.api.reload)

    def test_reload_unexpected_url(self):
        """
        If the error URL is not the root, the error is propagated.
        """
        self.apt._set_jenkins_version('2.120.1')
        error = self._make_httperror(self.api.url, 503, "Service Unavailable")
        error.response.url = urljoin(self.api.url, "/foo")
        self.fakes.jenkins.responses[urljoin(self.api.url, "reload")] = error
        self.assertRaises(HTTPError, self.api.reload)

    def test_reload_unexpected_success(self):
        """
        If the request unexpectedly succeeds, an error is raised.
        """
        self.apt._set_jenkins_version('2.120.1')
        self.fakes.jenkins.responses[urljoin(self.api.url, "reload")] = "home"
        self.assertRaises(RuntimeError, self.api.reload)

    def test_url(self):
        """
        Verify the url always ends in a / and has the expected prefix
        """
        config = hookenv.config()
        orig_public_url = config["public-url"]
        try:
            config["public-url"] = ""
            self.assertEqual(self.api.url, 'http://localhost:8080/')

            config["public-url"] = "http://here:8080/jenkins"
            self.assertEqual(self.api.url, 'http://localhost:8080/jenkins/')
        finally:
            config["public-url"] = orig_public_url
예제 #4
0
class ApiTest(JenkinsTest):
    def setUp(self):
        super(ApiTest, self).setUp()
        self.useFixture(JenkinsConfiguredAdmin(self.fakes))
        self.fakes.jenkins.scripts[GET_TOKEN_SCRIPT.format("admin")] = "abc\n"
        self.api = Api()

    def test_wait_transient_failure(self):
        """
        Wait for Jenkins to be fully up, even in spite of transient failures.
        """
        get_whoami = self.fakes.jenkins.get_whoami
        tries = []

        def transient_failure():
            try:
                if not tries:
                    raise JenkinsException("error")
                get_whoami()
            finally:
                tries.append(True)

        self.fakes.jenkins.get_whoami = transient_failure
        self.assertIsNone(self.api.wait())

    def test_update_password(self):
        """
        The update_password() method runs a groovy script to update the
        password for the given user.
        """
        username = "******"
        password = "******"
        script = UPDATE_PASSWORD_SCRIPT.format(username=username,
                                               password=password)
        self.fakes.jenkins.scripts[script] = ""
        self.assertIsNone(self.api.update_password(username, password))

    def test_version(self):
        """The version() method returns the version of the Jenkins server."""
        self.assertEqual("2.0.0", self.api.version())

    def test_add(self):
        """
        A slave node can be added by specifying executors and labels.
        """
        self.api.add_node("slave-0", 1, labels=["python"])
        [node] = self.fakes.jenkins.nodes
        self.assertEqual("slave-0", node.host)
        self.assertEqual(1, node.executors)
        self.assertEqual("slave-0", node.description)
        self.assertEqual(["python"], node.labels)

    def test_add_exists(self):
        """
        If a node already exists, nothing is done.
        """
        self.fakes.jenkins.create_node("slave-0", 1, "slave-0")
        self.api.add_node("slave-0", 1, labels=["python"])
        self.assertEqual(1, len(self.fakes.jenkins.nodes))

    def test_add_transient_failure(self):
        """
        Transient failures get retried.
        """
        create_node = self.fakes.jenkins.create_node
        tries = []

        def transient_failure(*args, **kwargs):
            try:
                if not tries:
                    raise JenkinsException("error")
                create_node(*args, **kwargs)
            finally:
                tries.append(True)

        self.fakes.jenkins.create_node = transient_failure
        self.api.add_node("slave-0", 1, labels=["python"])
        self.assertEqual(1, len(self.fakes.jenkins.nodes))

    def test_add_retry_give_up(self):
        """
        If errors persist, we give up.
        """
        def failure(*args, **kwargs):
            raise JenkinsException("error")

        self.fakes.jenkins.create_node = failure
        self.assertRaises(JenkinsException, self.api.add_node, "slave-0", 1)

    def test_add_spurious(self):
        """
        If adding a node apparently succeeds, but actually didn't then we
        log an error.
        """
        self.fakes.jenkins.create_node = lambda *args, **kwargs: None
        self.api.add_node("slave-0", 1, labels=["python"])
        self.assertEqual("ERROR: Failed to create node 'slave-0'",
                         self.fakes.juju.log[-1])

    def test_deleted(self):
        """
        A slave node can be deleted by specifyng its host name.
        """
        self.api.add_node("slave-0", 1, labels=["python"])
        self.api.delete_node("slave-0")
        self.assertEqual([], self.fakes.jenkins.nodes)

    def test_deleted_no_present(self):
        """
        If a slave node doesn't exists, deleting it is a no-op.
        """
        self.api.delete_node("slave-0")
        self.assertEqual([], self.fakes.jenkins.nodes)

    def test_reload(self):
        """
        The reload method POSTs a request to the '/reload' URL, expecting
        a 503 on the homepage (which happens after redirection).
        """
        error = HTTPError(URL, 503, "Service Unavailable", {}, None)
        error.url = URL
        self.fakes.jenkins.responses[urljoin(URL, "/reload")] = error
        self.api.reload()

    def test_reload_unexpected_error(self):
        """
        If the error code is not 403, the error is propagated.
        """
        error = HTTPError(URL, 403, "Forbidden", {}, None)
        self.fakes.jenkins.responses[urljoin(URL, "/reload")] = error
        self.assertRaises(HTTPError, self.api.reload)

    def test_reload_unexpected_url(self):
        """
        If the error URL is not the root, the error is propagated.
        """
        error = HTTPError(URL, 503, "Service Unavailable", {}, None)
        error.url = "/foo"
        self.fakes.jenkins.responses[urljoin(URL, "/reload")] = error
        self.assertRaises(HTTPError, self.api.reload)

    def test_reload_unexpected_success(self):
        """
        If the request unexpectedly succeeds, an error is raised.
        """
        self.fakes.jenkins.responses[urljoin(URL, "/reload")] = "home"
        self.assertRaises(RuntimeError, self.api.reload)
예제 #5
0
class ApiTest(JenkinsTest):

    def setUp(self):
        super(ApiTest, self).setUp()
        self.useFixture(JenkinsConfiguredAdmin(self.fakes))
        self.fakes.jenkins.scripts[GET_TOKEN_SCRIPT.format("admin")] = "abc\n"
        self.api = Api()

    def test_wait_transient_failure(self):
        """
        Wait for Jenkins to be fully up, even in spite of transient failures.
        """
        get_whoami = self.fakes.jenkins.get_whoami
        tries = []

        def transient_failure():
            try:
                if not tries:
                    raise JenkinsException("error")
                get_whoami()
            finally:
                tries.append(True)

        self.fakes.jenkins.get_whoami = transient_failure
        self.assertIsNone(self.api.wait())

    def test_update_password(self):
        """
        The update_password() method runs a groovy script to update the
        password for the given user.
        """
        username = "******"
        password = "******"
        script = UPDATE_PASSWORD_SCRIPT.format(
            username=username, password=password)
        self.fakes.jenkins.scripts[script] = ""
        self.assertIsNone(self.api.update_password(username, password))

    def test_version(self):
        """The version() method returns the version of the Jenkins server."""
        self.assertEqual("2.0.0", self.api.version())

    def test_add(self):
        """
        A slave node can be added by specifying executors and labels.
        """
        self.api.add_node("slave-0", 1, labels=["python"])
        [node] = self.fakes.jenkins.nodes
        self.assertEqual("slave-0", node.host)
        self.assertEqual(1, node.executors)
        self.assertEqual("slave-0", node.description)
        self.assertEqual(["python"], node.labels)

    def test_add_exists(self):
        """
        If a node already exists, nothing is done.
        """
        self.fakes.jenkins.create_node("slave-0", 1, "slave-0")
        self.api.add_node("slave-0", 1, labels=["python"])
        self.assertEqual(1, len(self.fakes.jenkins.nodes))

    def test_add_transient_failure(self):
        """
        Transient failures get retried.
        """
        create_node = self.fakes.jenkins.create_node
        tries = []

        def transient_failure(*args, **kwargs):
            try:
                if not tries:
                    raise JenkinsException("error")
                create_node(*args, **kwargs)
            finally:
                tries.append(True)

        self.fakes.jenkins.create_node = transient_failure
        self.api.add_node("slave-0", 1, labels=["python"])
        self.assertEqual(1, len(self.fakes.jenkins.nodes))

    def test_add_retry_give_up(self):
        """
        If errors persist, we give up.
        """

        def failure(*args, **kwargs):
            raise JenkinsException("error")

        self.fakes.jenkins.create_node = failure
        self.assertRaises(
            JenkinsException, self.api.add_node, "slave-0", 1)

    def test_add_spurious(self):
        """
        If adding a node apparently succeeds, but actually didn't then we
        log an error.
        """
        self.fakes.jenkins.create_node = lambda *args, **kwargs: None
        self.api.add_node("slave-0", 1, labels=["python"])
        self.assertEqual(
            "ERROR: Failed to create node 'slave-0'", self.fakes.juju.log[-1])

    def test_deleted(self):
        """
        A slave node can be deleted by specifyng its host name.
        """
        self.api.add_node("slave-0", 1, labels=["python"])
        self.api.delete_node("slave-0")
        self.assertEqual([], self.fakes.jenkins.nodes)

    def test_deleted_no_present(self):
        """
        If a slave node doesn't exists, deleting it is a no-op.
        """
        self.api.delete_node("slave-0")
        self.assertEqual([], self.fakes.jenkins.nodes)

    def test_reload(self):
        """
        The reload method POSTs a request to the '/reload' URL, expecting
        a 503 on the homepage (which happens after redirection).
        """
        error = HTTPError(URL, 503, "Service Unavailable", {}, None)
        error.url = URL
        self.fakes.jenkins.responses[urljoin(URL, "/reload")] = error
        self.api.reload()

    def test_reload_unexpected_error(self):
        """
        If the error code is not 403, the error is propagated.
        """
        error = HTTPError(URL, 403, "Forbidden", {}, None)
        self.fakes.jenkins.responses[urljoin(URL, "/reload")] = error
        self.assertRaises(HTTPError, self.api.reload)

    def test_reload_unexpected_url(self):
        """
        If the error URL is not the root, the error is propagated.
        """
        error = HTTPError(URL, 503, "Service Unavailable", {}, None)
        error.url = "/foo"
        self.fakes.jenkins.responses[urljoin(URL, "/reload")] = error
        self.assertRaises(HTTPError, self.api.reload)

    def test_reload_unexpected_success(self):
        """
        If the request unexpectedly succeeds, an error is raised.
        """
        self.fakes.jenkins.responses[urljoin(URL, "/reload")] = "home"
        self.assertRaises(RuntimeError, self.api.reload)