From 4122cfe1183340e5417c3e02ad56388811184641 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Wed, 7 Sep 2016 18:07:07 +0200 Subject: [PATCH] move rest-client to brooklyn-client update brooklyn-client/cli/README.md --- .gitignore | 5 +- LICENSE => cli/LICENSE | 0 NOTICE => cli/NOTICE | 0 README.md => cli/README.md | 8 +- .../api}/access_control/access_control.go | 0 {api => cli/api}/activities/activities.go | 0 {api => cli/api}/application/applications.go | 0 {api => cli/api}/catalog/catalog.go | 0 {api => cli/api}/entities/entities.go | 0 {api => cli/api}/entity_config/config.go | 0 .../api}/entity_effectors/effectors.go | 0 {api => cli/api}/entity_policies/policies.go | 0 .../api}/entity_policy_config/config.go | 0 {api => cli/api}/entity_sensors/sensors.go | 0 {api => cli/api}/locations/locations.go | 0 {api => cli/api}/server/server.go | 0 {api => cli/api}/usage/usage.go | 0 {api => cli/api}/version/version.go | 0 {app => cli/app}/app.go | 0 {br => cli/br}/brooklyn.go | 0 build.xml => cli/build.xml | 0 {command => cli/command}/command.go | 0 {command => cli/command}/supercommand.go | 0 .../command_factory}/factory.go | 0 .../command_metadata}/command_metadata.go | 0 .../command_runner}/runner.go | 0 {commands => cli/commands}/access.go | 0 {commands => cli/commands}/activity-stream.go | 0 {commands => cli/commands}/activity.go | 0 {commands => cli/commands}/add-catalog.go | 0 {commands => cli/commands}/add-children.go | 0 {commands => cli/commands}/add-location.go | 0 {commands => cli/commands}/add-policy.go | 0 {commands => cli/commands}/application.go | 0 .../commands}/catalog-applications.go | 0 .../commands}/catalog-entities.go | 0 {commands => cli/commands}/catalog-entity.go | 0 .../commands}/catalog-location.go | 0 .../commands}/catalog-locations.go | 0 .../commands}/catalog-policies.go | 0 {commands => cli/commands}/catalog-policy.go | 0 {commands => cli/commands}/catalog.go | 0 {commands => cli/commands}/config.go | 0 .../commands}/delete-catalog-application.go | 0 .../commands}/delete-catalog-entity.go | 0 .../commands}/delete-catalog-policy.go | 0 {commands => cli/commands}/delete.go | 0 {commands => cli/commands}/deploy.go | 0 {commands => cli/commands}/destroy-policy.go | 0 {commands => cli/commands}/effector.go | 0 {commands => cli/commands}/entity.go | 0 {commands => cli/commands}/invoke.go | 0 {commands => cli/commands}/list.go | 0 {commands => cli/commands}/locations.go | 0 {commands => cli/commands}/login.go | 0 {commands => cli/commands}/policy.go | 0 {commands => cli/commands}/rename.go | 0 {commands => cli/commands}/reset-catalog.go | 0 {commands => cli/commands}/sensor.go | 0 {commands => cli/commands}/set.go | 0 {commands => cli/commands}/spec.go | 0 {commands => cli/commands}/start-policy.go | 0 {commands => cli/commands}/stop-policy.go | 0 {commands => cli/commands}/tree.go | 0 {commands => cli/commands}/utils.go | 0 {commands => cli/commands}/version.go | 0 {error_handler => cli/error_handler}/error.go | 0 glide.lock => cli/glide.lock | 0 glide.yaml => cli/glide.yaml | 0 {io => cli/io}/config.go | 0 {models => cli/models}/access.go | 0 {models => cli/models}/applications.go | 0 {models => cli/models}/catalog.go | 0 {models => cli/models}/config.go | 0 {models => cli/models}/effectors.go | 0 {models => cli/models}/entities.go | 0 {models => cli/models}/locations.go | 0 {models => cli/models}/policies.go | 0 {models => cli/models}/sensors.go | 0 {models => cli/models}/version.go | 0 {net => cli/net}/net.go | 0 cli/pom.xml | 132 ++++ {release => cli/release}/assembly.xml | 0 {release => cli/release}/build.bat | 0 {release => cli/release}/build.sh | 0 {release => cli/release}/files/README | 0 .../release}/license/files/LICENSE | 0 .../release}/license/source-inclusions.yaml | 0 {scope => cli/scope}/scope.go | 0 {terminal => cli/terminal}/table.go | 0 {test => cli/test}/test.sh | 0 {test => cli/test}/test_app.yaml | 0 java/pom.xml | 719 ++++++++++++++++++ .../brooklyn/rest/client/BrooklynApi.java | 419 ++++++++++ .../brooklyn/rest/client/BrooklynApiUtil.java | 154 ++++ .../http/BuiltResponsePreservingError.java | 79 ++ .../ApplicationResourceIntegrationTest.java | 190 +++++ .../client/BrooklynApiRestClientTest.java | 163 ++++ .../rest/client/BrooklynApiUtilTest.java | 129 ++++ .../test/resources/catalog/test-catalog.bom | 33 + java/src/test/webapp/WEB-INF/web.xml | 129 ++++ pom.xml | 538 ++++++++++--- 102 files changed, 2602 insertions(+), 96 deletions(-) rename LICENSE => cli/LICENSE (100%) rename NOTICE => cli/NOTICE (100%) rename README.md => cli/README.md (94%) rename {api => cli/api}/access_control/access_control.go (100%) rename {api => cli/api}/activities/activities.go (100%) rename {api => cli/api}/application/applications.go (100%) rename {api => cli/api}/catalog/catalog.go (100%) rename {api => cli/api}/entities/entities.go (100%) rename {api => cli/api}/entity_config/config.go (100%) rename {api => cli/api}/entity_effectors/effectors.go (100%) rename {api => cli/api}/entity_policies/policies.go (100%) rename {api => cli/api}/entity_policy_config/config.go (100%) rename {api => cli/api}/entity_sensors/sensors.go (100%) rename {api => cli/api}/locations/locations.go (100%) rename {api => cli/api}/server/server.go (100%) rename {api => cli/api}/usage/usage.go (100%) rename {api => cli/api}/version/version.go (100%) rename {app => cli/app}/app.go (100%) rename {br => cli/br}/brooklyn.go (100%) rename build.xml => cli/build.xml (100%) rename {command => cli/command}/command.go (100%) rename {command => cli/command}/supercommand.go (100%) rename {command_factory => cli/command_factory}/factory.go (100%) rename {command_metadata => cli/command_metadata}/command_metadata.go (100%) rename {command_runner => cli/command_runner}/runner.go (100%) rename {commands => cli/commands}/access.go (100%) rename {commands => cli/commands}/activity-stream.go (100%) rename {commands => cli/commands}/activity.go (100%) rename {commands => cli/commands}/add-catalog.go (100%) rename {commands => cli/commands}/add-children.go (100%) rename {commands => cli/commands}/add-location.go (100%) rename {commands => cli/commands}/add-policy.go (100%) rename {commands => cli/commands}/application.go (100%) rename {commands => cli/commands}/catalog-applications.go (100%) rename {commands => cli/commands}/catalog-entities.go (100%) rename {commands => cli/commands}/catalog-entity.go (100%) rename {commands => cli/commands}/catalog-location.go (100%) rename {commands => cli/commands}/catalog-locations.go (100%) rename {commands => cli/commands}/catalog-policies.go (100%) rename {commands => cli/commands}/catalog-policy.go (100%) rename {commands => cli/commands}/catalog.go (100%) rename {commands => cli/commands}/config.go (100%) rename {commands => cli/commands}/delete-catalog-application.go (100%) rename {commands => cli/commands}/delete-catalog-entity.go (100%) rename {commands => cli/commands}/delete-catalog-policy.go (100%) rename {commands => cli/commands}/delete.go (100%) rename {commands => cli/commands}/deploy.go (100%) rename {commands => cli/commands}/destroy-policy.go (100%) rename {commands => cli/commands}/effector.go (100%) rename {commands => cli/commands}/entity.go (100%) rename {commands => cli/commands}/invoke.go (100%) rename {commands => cli/commands}/list.go (100%) rename {commands => cli/commands}/locations.go (100%) rename {commands => cli/commands}/login.go (100%) rename {commands => cli/commands}/policy.go (100%) rename {commands => cli/commands}/rename.go (100%) rename {commands => cli/commands}/reset-catalog.go (100%) rename {commands => cli/commands}/sensor.go (100%) rename {commands => cli/commands}/set.go (100%) rename {commands => cli/commands}/spec.go (100%) rename {commands => cli/commands}/start-policy.go (100%) rename {commands => cli/commands}/stop-policy.go (100%) rename {commands => cli/commands}/tree.go (100%) rename {commands => cli/commands}/utils.go (100%) rename {commands => cli/commands}/version.go (100%) rename {error_handler => cli/error_handler}/error.go (100%) rename glide.lock => cli/glide.lock (100%) rename glide.yaml => cli/glide.yaml (100%) rename {io => cli/io}/config.go (100%) rename {models => cli/models}/access.go (100%) rename {models => cli/models}/applications.go (100%) rename {models => cli/models}/catalog.go (100%) rename {models => cli/models}/config.go (100%) rename {models => cli/models}/effectors.go (100%) rename {models => cli/models}/entities.go (100%) rename {models => cli/models}/locations.go (100%) rename {models => cli/models}/policies.go (100%) rename {models => cli/models}/sensors.go (100%) rename {models => cli/models}/version.go (100%) rename {net => cli/net}/net.go (100%) create mode 100644 cli/pom.xml rename {release => cli/release}/assembly.xml (100%) rename {release => cli/release}/build.bat (100%) rename {release => cli/release}/build.sh (100%) rename {release => cli/release}/files/README (100%) rename {release => cli/release}/license/files/LICENSE (100%) rename {release => cli/release}/license/source-inclusions.yaml (100%) rename {scope => cli/scope}/scope.go (100%) rename {terminal => cli/terminal}/table.go (100%) rename {test => cli/test}/test.sh (100%) rename {test => cli/test}/test_app.yaml (100%) create mode 100644 java/pom.xml create mode 100644 java/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java create mode 100644 java/src/main/java/org/apache/brooklyn/rest/client/BrooklynApiUtil.java create mode 100644 java/src/main/java/org/apache/brooklyn/rest/client/util/http/BuiltResponsePreservingError.java create mode 100644 java/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java create mode 100644 java/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java create mode 100644 java/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiUtilTest.java create mode 100644 java/src/test/resources/catalog/test-catalog.bom create mode 100644 java/src/test/webapp/WEB-INF/web.xml diff --git a/.gitignore b/.gitignore index 08d4901..6dacd7f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ target .classpath .settings/ .metadata/ -vendor/ \ No newline at end of file +vendor/ + +*.log +brooklyn*.log.* diff --git a/LICENSE b/cli/LICENSE similarity index 100% rename from LICENSE rename to cli/LICENSE diff --git a/NOTICE b/cli/NOTICE similarity index 100% rename from NOTICE rename to cli/NOTICE diff --git a/README.md b/cli/README.md similarity index 94% rename from README.md rename to cli/README.md index e45eacb..1602759 100644 --- a/README.md +++ b/cli/README.md @@ -22,8 +22,8 @@ Optional: ## Workspace Setup Go is very particular about the layout of a source tree, and the naming of packages. It is therefore important to -get the code from github.com/apache/brooklyn-client and not your own fork. If you want to contribute to the -project, the procedure to follow is still to get the code from github.com/apache/brooklyn-client, and then to add your +get the code from github.com/apache/brooklyn-client/cli and not your own fork. If you want to contribute to the +project, the procedure to follow is still to get the code from github.com/apache/brooklyn-client/cli, and then to add your own fork as a remote. - Ensure your [$GOPATH](http://golang.org/cmd/go/#hdr-GOPATH_environment_variable) is set correctly @@ -31,7 +31,7 @@ own fork as a remote. - Get the Brooklyn CLI and dependencies. ```bash -go get github.com/apache/brooklyn-client/br +go get github.com/apache/brooklyn-client/cli/br ``` @@ -42,7 +42,7 @@ code currently uses [Glide](https://github.com/Masterminds/glide). The dependenc ```bash go get github.com/Masterminds/glide -cd $GOPATH/src/github.com/apache/brooklyn-client +cd $GOPATH/src/github.com/apache/brooklyn-client/cli glide install ``` diff --git a/api/access_control/access_control.go b/cli/api/access_control/access_control.go similarity index 100% rename from api/access_control/access_control.go rename to cli/api/access_control/access_control.go diff --git a/api/activities/activities.go b/cli/api/activities/activities.go similarity index 100% rename from api/activities/activities.go rename to cli/api/activities/activities.go diff --git a/api/application/applications.go b/cli/api/application/applications.go similarity index 100% rename from api/application/applications.go rename to cli/api/application/applications.go diff --git a/api/catalog/catalog.go b/cli/api/catalog/catalog.go similarity index 100% rename from api/catalog/catalog.go rename to cli/api/catalog/catalog.go diff --git a/api/entities/entities.go b/cli/api/entities/entities.go similarity index 100% rename from api/entities/entities.go rename to cli/api/entities/entities.go diff --git a/api/entity_config/config.go b/cli/api/entity_config/config.go similarity index 100% rename from api/entity_config/config.go rename to cli/api/entity_config/config.go diff --git a/api/entity_effectors/effectors.go b/cli/api/entity_effectors/effectors.go similarity index 100% rename from api/entity_effectors/effectors.go rename to cli/api/entity_effectors/effectors.go diff --git a/api/entity_policies/policies.go b/cli/api/entity_policies/policies.go similarity index 100% rename from api/entity_policies/policies.go rename to cli/api/entity_policies/policies.go diff --git a/api/entity_policy_config/config.go b/cli/api/entity_policy_config/config.go similarity index 100% rename from api/entity_policy_config/config.go rename to cli/api/entity_policy_config/config.go diff --git a/api/entity_sensors/sensors.go b/cli/api/entity_sensors/sensors.go similarity index 100% rename from api/entity_sensors/sensors.go rename to cli/api/entity_sensors/sensors.go diff --git a/api/locations/locations.go b/cli/api/locations/locations.go similarity index 100% rename from api/locations/locations.go rename to cli/api/locations/locations.go diff --git a/api/server/server.go b/cli/api/server/server.go similarity index 100% rename from api/server/server.go rename to cli/api/server/server.go diff --git a/api/usage/usage.go b/cli/api/usage/usage.go similarity index 100% rename from api/usage/usage.go rename to cli/api/usage/usage.go diff --git a/api/version/version.go b/cli/api/version/version.go similarity index 100% rename from api/version/version.go rename to cli/api/version/version.go diff --git a/app/app.go b/cli/app/app.go similarity index 100% rename from app/app.go rename to cli/app/app.go diff --git a/br/brooklyn.go b/cli/br/brooklyn.go similarity index 100% rename from br/brooklyn.go rename to cli/br/brooklyn.go diff --git a/build.xml b/cli/build.xml similarity index 100% rename from build.xml rename to cli/build.xml diff --git a/command/command.go b/cli/command/command.go similarity index 100% rename from command/command.go rename to cli/command/command.go diff --git a/command/supercommand.go b/cli/command/supercommand.go similarity index 100% rename from command/supercommand.go rename to cli/command/supercommand.go diff --git a/command_factory/factory.go b/cli/command_factory/factory.go similarity index 100% rename from command_factory/factory.go rename to cli/command_factory/factory.go diff --git a/command_metadata/command_metadata.go b/cli/command_metadata/command_metadata.go similarity index 100% rename from command_metadata/command_metadata.go rename to cli/command_metadata/command_metadata.go diff --git a/command_runner/runner.go b/cli/command_runner/runner.go similarity index 100% rename from command_runner/runner.go rename to cli/command_runner/runner.go diff --git a/commands/access.go b/cli/commands/access.go similarity index 100% rename from commands/access.go rename to cli/commands/access.go diff --git a/commands/activity-stream.go b/cli/commands/activity-stream.go similarity index 100% rename from commands/activity-stream.go rename to cli/commands/activity-stream.go diff --git a/commands/activity.go b/cli/commands/activity.go similarity index 100% rename from commands/activity.go rename to cli/commands/activity.go diff --git a/commands/add-catalog.go b/cli/commands/add-catalog.go similarity index 100% rename from commands/add-catalog.go rename to cli/commands/add-catalog.go diff --git a/commands/add-children.go b/cli/commands/add-children.go similarity index 100% rename from commands/add-children.go rename to cli/commands/add-children.go diff --git a/commands/add-location.go b/cli/commands/add-location.go similarity index 100% rename from commands/add-location.go rename to cli/commands/add-location.go diff --git a/commands/add-policy.go b/cli/commands/add-policy.go similarity index 100% rename from commands/add-policy.go rename to cli/commands/add-policy.go diff --git a/commands/application.go b/cli/commands/application.go similarity index 100% rename from commands/application.go rename to cli/commands/application.go diff --git a/commands/catalog-applications.go b/cli/commands/catalog-applications.go similarity index 100% rename from commands/catalog-applications.go rename to cli/commands/catalog-applications.go diff --git a/commands/catalog-entities.go b/cli/commands/catalog-entities.go similarity index 100% rename from commands/catalog-entities.go rename to cli/commands/catalog-entities.go diff --git a/commands/catalog-entity.go b/cli/commands/catalog-entity.go similarity index 100% rename from commands/catalog-entity.go rename to cli/commands/catalog-entity.go diff --git a/commands/catalog-location.go b/cli/commands/catalog-location.go similarity index 100% rename from commands/catalog-location.go rename to cli/commands/catalog-location.go diff --git a/commands/catalog-locations.go b/cli/commands/catalog-locations.go similarity index 100% rename from commands/catalog-locations.go rename to cli/commands/catalog-locations.go diff --git a/commands/catalog-policies.go b/cli/commands/catalog-policies.go similarity index 100% rename from commands/catalog-policies.go rename to cli/commands/catalog-policies.go diff --git a/commands/catalog-policy.go b/cli/commands/catalog-policy.go similarity index 100% rename from commands/catalog-policy.go rename to cli/commands/catalog-policy.go diff --git a/commands/catalog.go b/cli/commands/catalog.go similarity index 100% rename from commands/catalog.go rename to cli/commands/catalog.go diff --git a/commands/config.go b/cli/commands/config.go similarity index 100% rename from commands/config.go rename to cli/commands/config.go diff --git a/commands/delete-catalog-application.go b/cli/commands/delete-catalog-application.go similarity index 100% rename from commands/delete-catalog-application.go rename to cli/commands/delete-catalog-application.go diff --git a/commands/delete-catalog-entity.go b/cli/commands/delete-catalog-entity.go similarity index 100% rename from commands/delete-catalog-entity.go rename to cli/commands/delete-catalog-entity.go diff --git a/commands/delete-catalog-policy.go b/cli/commands/delete-catalog-policy.go similarity index 100% rename from commands/delete-catalog-policy.go rename to cli/commands/delete-catalog-policy.go diff --git a/commands/delete.go b/cli/commands/delete.go similarity index 100% rename from commands/delete.go rename to cli/commands/delete.go diff --git a/commands/deploy.go b/cli/commands/deploy.go similarity index 100% rename from commands/deploy.go rename to cli/commands/deploy.go diff --git a/commands/destroy-policy.go b/cli/commands/destroy-policy.go similarity index 100% rename from commands/destroy-policy.go rename to cli/commands/destroy-policy.go diff --git a/commands/effector.go b/cli/commands/effector.go similarity index 100% rename from commands/effector.go rename to cli/commands/effector.go diff --git a/commands/entity.go b/cli/commands/entity.go similarity index 100% rename from commands/entity.go rename to cli/commands/entity.go diff --git a/commands/invoke.go b/cli/commands/invoke.go similarity index 100% rename from commands/invoke.go rename to cli/commands/invoke.go diff --git a/commands/list.go b/cli/commands/list.go similarity index 100% rename from commands/list.go rename to cli/commands/list.go diff --git a/commands/locations.go b/cli/commands/locations.go similarity index 100% rename from commands/locations.go rename to cli/commands/locations.go diff --git a/commands/login.go b/cli/commands/login.go similarity index 100% rename from commands/login.go rename to cli/commands/login.go diff --git a/commands/policy.go b/cli/commands/policy.go similarity index 100% rename from commands/policy.go rename to cli/commands/policy.go diff --git a/commands/rename.go b/cli/commands/rename.go similarity index 100% rename from commands/rename.go rename to cli/commands/rename.go diff --git a/commands/reset-catalog.go b/cli/commands/reset-catalog.go similarity index 100% rename from commands/reset-catalog.go rename to cli/commands/reset-catalog.go diff --git a/commands/sensor.go b/cli/commands/sensor.go similarity index 100% rename from commands/sensor.go rename to cli/commands/sensor.go diff --git a/commands/set.go b/cli/commands/set.go similarity index 100% rename from commands/set.go rename to cli/commands/set.go diff --git a/commands/spec.go b/cli/commands/spec.go similarity index 100% rename from commands/spec.go rename to cli/commands/spec.go diff --git a/commands/start-policy.go b/cli/commands/start-policy.go similarity index 100% rename from commands/start-policy.go rename to cli/commands/start-policy.go diff --git a/commands/stop-policy.go b/cli/commands/stop-policy.go similarity index 100% rename from commands/stop-policy.go rename to cli/commands/stop-policy.go diff --git a/commands/tree.go b/cli/commands/tree.go similarity index 100% rename from commands/tree.go rename to cli/commands/tree.go diff --git a/commands/utils.go b/cli/commands/utils.go similarity index 100% rename from commands/utils.go rename to cli/commands/utils.go diff --git a/commands/version.go b/cli/commands/version.go similarity index 100% rename from commands/version.go rename to cli/commands/version.go diff --git a/error_handler/error.go b/cli/error_handler/error.go similarity index 100% rename from error_handler/error.go rename to cli/error_handler/error.go diff --git a/glide.lock b/cli/glide.lock similarity index 100% rename from glide.lock rename to cli/glide.lock diff --git a/glide.yaml b/cli/glide.yaml similarity index 100% rename from glide.yaml rename to cli/glide.yaml diff --git a/io/config.go b/cli/io/config.go similarity index 100% rename from io/config.go rename to cli/io/config.go diff --git a/models/access.go b/cli/models/access.go similarity index 100% rename from models/access.go rename to cli/models/access.go diff --git a/models/applications.go b/cli/models/applications.go similarity index 100% rename from models/applications.go rename to cli/models/applications.go diff --git a/models/catalog.go b/cli/models/catalog.go similarity index 100% rename from models/catalog.go rename to cli/models/catalog.go diff --git a/models/config.go b/cli/models/config.go similarity index 100% rename from models/config.go rename to cli/models/config.go diff --git a/models/effectors.go b/cli/models/effectors.go similarity index 100% rename from models/effectors.go rename to cli/models/effectors.go diff --git a/models/entities.go b/cli/models/entities.go similarity index 100% rename from models/entities.go rename to cli/models/entities.go diff --git a/models/locations.go b/cli/models/locations.go similarity index 100% rename from models/locations.go rename to cli/models/locations.go diff --git a/models/policies.go b/cli/models/policies.go similarity index 100% rename from models/policies.go rename to cli/models/policies.go diff --git a/models/sensors.go b/cli/models/sensors.go similarity index 100% rename from models/sensors.go rename to cli/models/sensors.go diff --git a/models/version.go b/cli/models/version.go similarity index 100% rename from models/version.go rename to cli/models/version.go diff --git a/net/net.go b/cli/net/net.go similarity index 100% rename from net/net.go rename to cli/net/net.go diff --git a/cli/pom.xml b/cli/pom.xml new file mode 100644 index 0000000..7cfb782 --- /dev/null +++ b/cli/pom.xml @@ -0,0 +1,132 @@ + + + + + 4.0.0 + + org.apache.brooklyn + brooklyn-client + 0.10.0-SNAPSHOT + ../pom.xml + + + pom + + brooklyn-client-cli + Brooklyn Client Command Line Interface + + A command line client for Apache Brooklyn + + + + + + + 1.8 + 2.6 + all + + + + + + apache.snapshots + Apache Snapshot Repository + http://repository.apache.org/snapshots + + false + + + + + + + + maven-antrun-plugin + 1.8 + + + process-build-all + compile + + + + + + + run + + + + + + + + maven-assembly-plugin + ${maven.assembly.plugin.version} + + + release/assembly.xml + + + + + make-assembly + package + + single + + + + + + + org.apache.rat + apache-rat-plugin + 0.11 + + + vendor/** + glide.* + + + + + + + + + diff --git a/release/assembly.xml b/cli/release/assembly.xml similarity index 100% rename from release/assembly.xml rename to cli/release/assembly.xml diff --git a/release/build.bat b/cli/release/build.bat similarity index 100% rename from release/build.bat rename to cli/release/build.bat diff --git a/release/build.sh b/cli/release/build.sh similarity index 100% rename from release/build.sh rename to cli/release/build.sh diff --git a/release/files/README b/cli/release/files/README similarity index 100% rename from release/files/README rename to cli/release/files/README diff --git a/release/license/files/LICENSE b/cli/release/license/files/LICENSE similarity index 100% rename from release/license/files/LICENSE rename to cli/release/license/files/LICENSE diff --git a/release/license/source-inclusions.yaml b/cli/release/license/source-inclusions.yaml similarity index 100% rename from release/license/source-inclusions.yaml rename to cli/release/license/source-inclusions.yaml diff --git a/scope/scope.go b/cli/scope/scope.go similarity index 100% rename from scope/scope.go rename to cli/scope/scope.go diff --git a/terminal/table.go b/cli/terminal/table.go similarity index 100% rename from terminal/table.go rename to cli/terminal/table.go diff --git a/test/test.sh b/cli/test/test.sh similarity index 100% rename from test/test.sh rename to cli/test/test.sh diff --git a/test/test_app.yaml b/cli/test/test_app.yaml similarity index 100% rename from test/test_app.yaml rename to cli/test/test_app.yaml diff --git a/java/pom.xml b/java/pom.xml new file mode 100644 index 0000000..a305f4e --- /dev/null +++ b/java/pom.xml @@ -0,0 +1,719 @@ + + + + 4.0.0 + brooklyn-rest-client + jar + Brooklyn REST java Client + + Client library for Brooklyn REST interface + + + + org.apache.brooklyn + brooklyn-client + 0.10.0-SNAPSHOT + ../pom.xml + + + + + org.apache.brooklyn + brooklyn-rest-api + ${project.version} + + + org.apache.brooklyn + brooklyn-api + ${project.version} + + + org.jboss.resteasy + resteasy-jaxrs + + + org.slf4j + slf4j-simple + + + + + org.jboss.resteasy + resteasy-jackson2-provider + + + org.slf4j + slf4j-simple + + + + + org.apache.brooklyn + brooklyn-utils-common + ${project.version} + + + org.apache.httpcomponents + httpclient + + + com.google.code.findbugs + jsr305 + + + com.google.guava + guava + + + org.slf4j + slf4j-api + + + com.google.code.gson + gson + + + org.testng + testng + test + + + org.eclipse.jetty + jetty-server + test + + + org.apache.brooklyn + brooklyn-core + ${project.version} + test + + + org.apache.brooklyn + brooklyn-core + ${project.version} + tests + test + + + org.apache.brooklyn + brooklyn-rest-server + ${project.version} + test + + + org.apache.brooklyn + brooklyn-rest-resources + ${project.version} + tests + test + + + org.apache.brooklyn + brooklyn-rest-server + ${project.version} + tests + test + + + org.apache.brooklyn + brooklyn-test-support + ${project.version} + test + + + com.google.mockwebserver + mockwebserver + test + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + *,org.jboss.resteasy.client.core.marshallers + + + + + + + + + Documentation + + true + + + maven-project-info-reports-plugin + 2.4 + + + + index + modules + + + + + + maven-javadoc-plugin + 2.8 + + + http://download.oracle.com/javaee/6/api + + true + false + true + false + + + + todo + a + To-do: + + + + + + javadoc + + javadoc + + + + + + + + + Bundle + + + + ${basedir}/src + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + bundle-manifest + process-classes + + manifest + + + + + + jar + + + + + brooklyn.*,org.apache.brooklyn.* + ${buildNumber} + ${scmBranch} + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + + + + + Tests + + ${basedir}/src/test + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.version} + + + + listener + org.apache.brooklyn.test.support.LoggingVerboseReporter,org.apache.brooklyn.test.support.BrooklynLeakListener,org.apache.brooklyn.test.support.PlatformTestSelectorListener + + + true + ${includedTestGroups} + ${excludedTestGroups} + false + + -1 + ${project.build.directory}/cobertura/cobertura.ser + false + + true + + + + maven-jar-plugin + true + + + test-jar-creation + + test-jar + + + true + + + + + + + + + + Integration + + Integration + Acceptance,Live,WIP,Broken + + + + + maven-antrun-plugin + true + + + run-tests + + run + + integration-test + + + + + + + + Acceptance + + Acceptance + Integration,Live,WIP,Broken + + + + + maven-antrun-plugin + true + + + run-tests + + run + + integration-test + + + + + + + + Live + + Live + Acceptance,WIP,Broken + + + + + Live-sanity + + Live-sanity + Acceptance,WIP,Broken + + + + + CI + + + + org.codehaus.mojo + findbugs-maven-plugin + + true + target/site + + + + process-classes + + findbugs + + + + + + maven-source-plugin + + + maven-pmd-plugin + 2.5 + true + + false + true + ${project.build.sourceEncoding} + 100 + ${java.version} + + **/*Test.java + **/tests/**/*.java + + + + + ${pom.basedir}/target/generated-sources/groovy-stubs/main + + + + + + process-classes + + check + cpd-check + + + + + + + + + Coverage + + + org.codehaus.mojo + cobertura-maven-plugin + ${cobertura.plugin.version} + test + + + + + + maven-source-plugin + + + maven-antrun-plugin + true + + + run-tests + + + instrument classes + + run + + process-test-classes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + coverage report + + run + + post-integration-test + + + + + + + + + + + + + + + + + + + + + + + + + ant-contrib + ant-contrib + 1.0b3 + + + ant + ant + + + + + org.apache.ant + ant-launcher + ${ant.version} + + + org.apache.ant + ant + ${ant.version} + + + org.testng + testng + ${testng.version} + + + org.codehaus.mojo + cobertura-maven-plugin + ${cobertura.plugin.version} + + + + + maven-dependency-plugin + + + unpack-coverage-sources + generate-sources + + unpack-dependencies + + + sources + compile + brooklyn + + ${project.build.directory}/cobertura/dependency-sources + + false + + + + unpack-coverage-classes + compile + + unpack-dependencies + + + jar + compile + brooklyn + + ${project.build.directory}/cobertura/dependency-classes + + + + + + + maven-surefire-plugin + ${surefire.version} + true + + xml + ${project.build.directory}/cobertura/coverage-classes + + + net.sourceforge.cobertura.datafile + ${project.build.directory}/cobertura/cobertura.ser + + + + cobertura.user.java.nio + false + + + + + + maven-jar-plugin + + + test-jar-creation + + true + + + + + + maven-deploy-plugin + + true + + + + + + + + + make-sources-jar + !skipSources + + maven-source-plugin + + + + + + make-javadoc-jar + javadoc + + maven-javadoc-plugin + + + + + + make-more-things-when-deploying + brooklyn.deployTo + + + maven-javadoc-plugin + + + maven-gpg-plugin + + + + + apache-repo + brooklyn.deployToapache + + + + rat-check + + + + org.apache.rat + apache-rat-plugin + + + rat-check + verify + + check + + + + + + + + + eclipse-compiler + + + + + org.apache.maven.plugins + maven-compiler-plugin + + eclipse + true + + + + org.codehaus.plexus + plexus-compiler-eclipse + 2.6 + + + + + + + + + + diff --git a/java/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java b/java/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java new file mode 100644 index 0000000..822e296 --- /dev/null +++ b/java/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java @@ -0,0 +1,419 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.rest.client; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.annotation.Nullable; +import javax.ws.rs.core.Response; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.jboss.resteasy.client.ClientExecutor; +import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.client.ProxyBuilder; +import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor; +import org.jboss.resteasy.client.core.extractors.DefaultEntityExtractorFactory; +import org.jboss.resteasy.specimpl.BuiltResponse; +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.jboss.resteasy.util.GenericType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +import org.apache.brooklyn.rest.api.AccessApi; +import org.apache.brooklyn.rest.api.ActivityApi; +import org.apache.brooklyn.rest.api.ApplicationApi; +import org.apache.brooklyn.rest.api.CatalogApi; +import org.apache.brooklyn.rest.api.EffectorApi; +import org.apache.brooklyn.rest.api.EntityApi; +import org.apache.brooklyn.rest.api.EntityConfigApi; +import org.apache.brooklyn.rest.api.LocationApi; +import org.apache.brooklyn.rest.api.PolicyApi; +import org.apache.brooklyn.rest.api.PolicyConfigApi; +import org.apache.brooklyn.rest.api.ScriptApi; +import org.apache.brooklyn.rest.api.SensorApi; +import org.apache.brooklyn.rest.api.ServerApi; +import org.apache.brooklyn.rest.api.UsageApi; +import org.apache.brooklyn.rest.api.VersionApi; +import org.apache.brooklyn.rest.client.util.http.BuiltResponsePreservingError; +import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.javalang.AggregateClassLoader; +import org.apache.brooklyn.util.net.Urls; + +import io.swagger.annotations.ApiOperation; + +/** + * @author Adam Lowe + */ +@SuppressWarnings("deprecation") +public class BrooklynApi { + + private final String target; + private final ClientExecutor clientExecutor; + private final int maxPoolSize; + private final int timeOutInMillis; + private static final Logger LOG = LoggerFactory.getLogger(BrooklynApi.class); + + /** + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String)} instead + */ + @Deprecated + public BrooklynApi(URL endpoint) { + this(checkNotNull(endpoint, "endpoint").toString()); + } + + /** + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String)} instead + */ + @Deprecated + public BrooklynApi(String endpoint) { + // username/password cannot be null, but credentials can + this(endpoint, null); + } + + /** + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String, String, String)} instead + */ + @Deprecated + public BrooklynApi(URL endpoint, String username, String password) { + this(endpoint.toString(), new UsernamePasswordCredentials(username, password)); + } + + /** + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String, String, String)} instead + */ + @Deprecated + public BrooklynApi(String endpoint, String username, String password) { + this(endpoint, new UsernamePasswordCredentials(username, password)); + } + + /** + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String, String, String)} instead + */ + @Deprecated + public BrooklynApi(URL endpoint, @Nullable Credentials credentials) { + this(endpoint.toString(), credentials); + } + + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String, String, String)} instead + */ + @Deprecated + public BrooklynApi(String endpoint, @Nullable Credentials credentials) { + this(endpoint, credentials, 20, 5000); + } + + /** + * Creates a BrooklynApi using a custom ClientExecutor + * + * @param endpoint the Brooklyn endpoint + * @param clientExecutor the ClientExecutor + * @see #getClientExecutor(org.apache.http.auth.Credentials) + */ + public BrooklynApi(URL endpoint, ClientExecutor clientExecutor) { + this.target = addV1SuffixIfNeeded(checkNotNull(endpoint, "endpoint").toString()); + this.maxPoolSize = -1; + this.timeOutInMillis = -1; + this.clientExecutor = checkNotNull(clientExecutor, "clientExecutor"); + } + + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @param credentials user credentials or null + * @param maxPoolSize maximum pool size + * @param timeOutInMillis connection timeout in milliseconds + */ + public BrooklynApi(String endpoint, @Nullable Credentials credentials, int maxPoolSize, int timeOutInMillis) { + try { + new URL(checkNotNull(endpoint, "endpoint")); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); + } + this.target = addV1SuffixIfNeeded(endpoint); + this.maxPoolSize = maxPoolSize; + this.timeOutInMillis = timeOutInMillis; + this.clientExecutor = getClientExecutor(credentials); + } + + private String addV1SuffixIfNeeded(String endpoint) { + if (!endpoint.endsWith("/v1/") && !endpoint.endsWith("/v1")) { + return Urls.mergePaths(endpoint, "v1"); + } else { + return endpoint; + } + } + + private Supplier connectionManagerSupplier = Suppliers.memoize(new Supplier() { + @Override + public PoolingHttpClientConnectionManager get() { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setMaxTotal(maxPoolSize); + connManager.setDefaultMaxPerRoute(maxPoolSize); + return connManager; + } + }); + + private Supplier reqConfSupplier = Suppliers.memoize(new Supplier() { + @Override + public RequestConfig get() { + return RequestConfig.custom() + .setConnectTimeout(timeOutInMillis) + .setConnectionRequestTimeout(timeOutInMillis) + .build(); + } + }); + + /** + * Creates a ClientExecutor for this BrooklynApi + */ + protected ClientExecutor getClientExecutor(Credentials credentials) { + CredentialsProvider provider = new BasicCredentialsProvider(); + if (credentials != null) provider.setCredentials(AuthScope.ANY, credentials); + + CloseableHttpClient httpClient = HttpClients.custom() + .setDefaultCredentialsProvider(provider) + .setDefaultRequestConfig(reqConfSupplier.get()) + .setConnectionManager(connectionManagerSupplier.get()) + .build(); + + return new ApacheHttpClient4Executor(httpClient); + } + + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @return a new BrooklynApi instance + */ + public static BrooklynApi newInstance(String endpoint) { + return new BrooklynApi(endpoint, null); + } + + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @param maxPoolSize maximum connection pool size + * @param timeOutInMillis connection timeout in millisecond + * @return a new BrooklynApi instance + */ + public static BrooklynApi newInstance(String endpoint, int maxPoolSize, int timeOutInMillis) { + return new BrooklynApi(endpoint, null, maxPoolSize, timeOutInMillis); + } + + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @param username for authentication + * @param password for authentication + * @return a new BrooklynApi instance + */ + public static BrooklynApi newInstance(String endpoint, String username, String password) { + return new BrooklynApi(endpoint, new UsernamePasswordCredentials(username, password)); + } + + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @param username for authentication + * @param password for authentication + * @param maxPoolSize maximum connection pool size + * @param timeOutInMillis connection timeout in millisecond + * @return a new BrooklynApi instance + */ + public static BrooklynApi newInstance(String endpoint, String username, String password, int maxPoolSize, int timeOutInMillis) { + return new BrooklynApi(endpoint, new UsernamePasswordCredentials(username, password), maxPoolSize, timeOutInMillis); + } + + @SuppressWarnings("unchecked") + private T proxy(Class clazz) { + AggregateClassLoader aggregateClassLoader = AggregateClassLoader.newInstanceWithNoLoaders(); + aggregateClassLoader.addLast(clazz.getClassLoader()); + aggregateClassLoader.addLast(getClass().getClassLoader()); + + final T result0 = ProxyBuilder.build(clazz, target) + .executor(clientExecutor) + .classloader(aggregateClassLoader) + .providerFactory(ResteasyProviderFactory.getInstance()) + .extractorFactory(new DefaultEntityExtractorFactory()) + .requestAttributes(MutableMap.of()) + .now(); + + return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + try { + Object result1 = method.invoke(result0, args); + Class type = String.class; + if (result1 instanceof Response) { + Response resp = (Response)result1; + if(isStatusCodeHealthy(resp.getStatus()) && method.isAnnotationPresent(ApiOperation.class)) { + type = getClassFromMethodAnnotationOrDefault(method, type); + } + // wrap the original response so it self-closes + result1 = BuiltResponsePreservingError.copyResponseAndClose(resp, type); + } + return result1; + } catch (Throwable e) { + if (e instanceof InvocationTargetException) { + // throw the original exception + e = ((InvocationTargetException)e).getTargetException(); + } + throw Exceptions.propagate(e); + } + } + + private boolean isStatusCodeHealthy(int code) { return (code>=200 && code<=299); } + + private Class getClassFromMethodAnnotationOrDefault(Method method, Class def){ + Class type; + try{ + type = method.getAnnotation(ApiOperation.class).response(); + } catch (Exception e) { + type = def; + LOG.debug("Unable to get class from annotation: {}. Defaulting to {}", e.getMessage(), def.getName()); + Exceptions.propagateIfFatal(e); + } + return type; + } + }); + } + + public ActivityApi getActivityApi() { + return proxy(ActivityApi.class); + } + + public ApplicationApi getApplicationApi() { + return proxy(ApplicationApi.class); + } + + public CatalogApi getCatalogApi() { + return proxy(CatalogApi.class); + } + + public EffectorApi getEffectorApi() { + return proxy(EffectorApi.class); + } + + public EntityConfigApi getEntityConfigApi() { + return proxy(EntityConfigApi.class); + } + + public EntityApi getEntityApi() { + return proxy(EntityApi.class); + } + + public LocationApi getLocationApi() { + return proxy(LocationApi.class); + } + + public PolicyConfigApi getPolicyConfigApi() { + return proxy(PolicyConfigApi.class); + } + + public PolicyApi getPolicyApi() { + return proxy(PolicyApi.class); + } + + public ScriptApi getScriptApi() { + return proxy(ScriptApi.class); + } + + public SensorApi getSensorApi() { + return proxy(SensorApi.class); + } + + public ServerApi getServerApi() { + return proxy(ServerApi.class); + } + + public UsageApi getUsageApi() { + return proxy(UsageApi.class); + } + + public VersionApi getVersionApi() { + return proxy(VersionApi.class); + } + + public AccessApi getAccessApi() { + return proxy(AccessApi.class); + } + + public static T getEntity(Response response, Class type) { + if (response instanceof ClientResponse) { + ClientResponse clientResponse = (ClientResponse) response; + return clientResponse.getEntity(type); + } else if (response instanceof BuiltResponse) { + // Handle BuiltResponsePreservingError turning objects into Strings + if (response.getEntity() instanceof String && !type.equals(String.class)) { + return new Gson().fromJson(response.getEntity().toString(), type); + } + } + // Last-gasp attempt. + return type.cast(response.getEntity()); + } + + public static T getEntity(Response response, GenericType type) { + if (response instanceof ClientResponse) { + ClientResponse clientResponse = (ClientResponse) response; + return clientResponse.getEntity(type); + } else if (response instanceof BuiltResponse) { + // Handle BuiltResponsePreservingError turning objects into Strings + if (response.getEntity() instanceof String) { + return new Gson().fromJson(response.getEntity().toString(), type.getGenericType()); + } + } + // Last-gasp attempt. + return type.getType().cast(response.getEntity()); + } + + /** + * @deprecated since 0.8.0-incubating. Use {@link #getEntity(Response, GenericType)} instead. + */ + @Deprecated + public static T getEntityGeneric(Response response, GenericType type) { + return getEntity(response, type); + } + +} diff --git a/java/src/main/java/org/apache/brooklyn/rest/client/BrooklynApiUtil.java b/java/src/main/java/org/apache/brooklyn/rest/client/BrooklynApiUtil.java new file mode 100644 index 0000000..ce57da5 --- /dev/null +++ b/java/src/main/java/org/apache/brooklyn/rest/client/BrooklynApiUtil.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.brooklyn.rest.client; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Date; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicReference; +import javax.ws.rs.core.Response; + +import org.apache.brooklyn.rest.api.EffectorApi; +import org.apache.brooklyn.rest.domain.Status; +import org.apache.brooklyn.rest.domain.TaskSummary; +import org.apache.brooklyn.util.repeat.Repeater; +import org.apache.brooklyn.util.time.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableMap; + +public class BrooklynApiUtil { + + private static final Logger LOG = LoggerFactory.getLogger(BrooklynApiUtil.class); + private static final Duration DEFAULT_POLL_PERIOD = Duration.FIVE_SECONDS; + private static final Duration DEFAULT_TIMEOUT = Duration.FIVE_MINUTES; + + private BrooklynApiUtil() {} + + /** + * Deploys the blueprint and returns the task summary. + * @throws Exception If the response from the server when deploying was {@link #isUnhealthyResponse unhealthy}. + */ + public static TaskSummary deployBlueprint(BrooklynApi api, String blueprint) throws Exception { + Response r = api.getApplicationApi().createFromYaml(blueprint); + if (isUnhealthyResponse(r)) { + throw new Exception("Unexpected response deploying blueprint to server: " + r.getStatus()); + } else { + LOG.debug("Server response to deploy blueprint: " + r.getStatus()); + } + return BrooklynApi.getEntity(r, TaskSummary.class); + } + + /** + * Waits for the application with the given ID to be running. + * + * @throws IllegalStateException If the application was not running after {@link #DEFAULT_TIMEOUT}. + */ + public static void waitForRunningAndThrowOtherwise(BrooklynApi api, String applicationId, String taskId) throws IllegalStateException { + waitForRunningAndThrowOtherwise(api, applicationId, taskId, DEFAULT_TIMEOUT); + } + + /** + * Waits for the application with the given ID to be running. + * + * @throws IllegalStateException If the application was not running after the given timeout. + */ + public static void waitForRunningAndThrowOtherwise(BrooklynApi api, String applicationId, String taskId, Duration timeout) throws IllegalStateException { + Status finalStatus = waitForAppStatus(api, applicationId, Status.RUNNING, timeout, DEFAULT_POLL_PERIOD); + if (!Status.RUNNING.equals(finalStatus)) { + LOG.error("Application is not running. Is: " + finalStatus.name().toLowerCase()); + + StringBuilder message = new StringBuilder(); + message.append("Application ").append(applicationId) + .append(" should be running but is ").append(finalStatus.name().toLowerCase()) + .append(". "); + + if (Status.ERROR.equals(finalStatus) || Status.UNKNOWN.equals(finalStatus)) { + String result = getTaskResult(api, taskId); + message.append("\nThe result of the task on the server was:\n") + .append(result); + } + throw new IllegalStateException(message.toString()); + } + } + + /** + * Polls Brooklyn until the given application has the given status. Quits early if the + * application's status is {@link org.apache.brooklyn.rest.domain.Status#ERROR} or + * {@link org.apache.brooklyn.rest.domain.Status#UNKNOWN} and desiredStatus is something else. + * + * @return The final polled status. + */ + public static Status waitForAppStatus(final BrooklynApi api, final String application, final Status desiredStatus, + Duration timeout, Duration pollPeriod) { + final AtomicReference appStatus = new AtomicReference<>(Status.UNKNOWN); + final boolean shortcutOnError = !Status.ERROR.equals(desiredStatus) && !Status.UNKNOWN.equals(desiredStatus); + LOG.info("Waiting " + timeout + " from " + new Date() + " for application " + application + " to be " + desiredStatus); + boolean finalAppStatusKnown = Repeater.create("Waiting for application " + application + " status to be " + desiredStatus) + .every(pollPeriod) + .limitTimeTo(timeout) + .rethrowExceptionImmediately() + .until(new Callable() { + @Override + public Boolean call() throws Exception { + Status status = api.getApplicationApi().get(application).getStatus(); + LOG.debug("Application " + application + " status is: " + status); + appStatus.set(status); + return desiredStatus.equals(status) || (shortcutOnError && + (Status.ERROR.equals(status) || Status.UNKNOWN.equals(status))); + } + }) + .run(); + if (appStatus.get().equals(desiredStatus)) { + LOG.info("Application " + application + " is " + desiredStatus.name()); + } else { + LOG.warn("Application is not " + desiredStatus.name() + " within " + timeout + + ". Status is: " + appStatus.get()); + } + return appStatus.get(); + } + + /** + * Use the {@link EffectorApi effector API} to invoke the stop effector on the given application. + */ + public static void attemptStop(BrooklynApi api, String application, Duration timeout) { + api.getEffectorApi().invoke(application, application, "stop", String.valueOf(timeout.toMilliseconds()), + ImmutableMap.of()); + } + + /** + * @return The result of the task with the given id, or "unknown" if it could not be found. + */ + public static String getTaskResult(BrooklynApi api, String taskId) { + checkNotNull(taskId, "taskId"); + TaskSummary summary = api.getActivityApi().get(taskId); + return summary == null || summary.getResult() == null ? "unknown" : summary.getResult().toString(); + } + + /** + * @return true if response's status code is not between 200 and 299 inclusive. + */ + public static boolean isUnhealthyResponse(Response response) { + return response.getStatus() < 200 || response.getStatus() >= 300; + } + +} diff --git a/java/src/main/java/org/apache/brooklyn/rest/client/util/http/BuiltResponsePreservingError.java b/java/src/main/java/org/apache/brooklyn/rest/client/util/http/BuiltResponsePreservingError.java new file mode 100644 index 0000000..d011172 --- /dev/null +++ b/java/src/main/java/org/apache/brooklyn/rest/client/util/http/BuiltResponsePreservingError.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.rest.client.util.http; + +import java.lang.annotation.Annotation; + +import javax.ws.rs.core.Response; + +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.jboss.resteasy.client.core.BaseClientResponse; +import org.jboss.resteasy.core.Headers; +import org.jboss.resteasy.specimpl.BuiltResponse; + +/** + * Allows wrapping a {@link Response} with the stream fully read and closed so that the client can be re-used. + *

+ * The entity may be stored as a string as type info is not available when it is deserialized, + * and that's a relatively convenient common format. + * + * TODO It would be nice to support other parsing, storing the byte array. + */ +public class BuiltResponsePreservingError extends BuiltResponse { + + private Throwable error; + + public BuiltResponsePreservingError(int status, Headers headers, Object entity, Annotation[] annotations, Throwable error) { + super(status, headers, entity, annotations); + this.error = error; + } + + @SuppressWarnings("deprecation") + public static Response copyResponseAndClose(Response source, Class type) { + int status = -1; + Headers headers = new Headers(); + Object entity = null; + try { + status = source.getStatus(); + if (source instanceof BaseClientResponse) + headers.putAll(((BaseClientResponse)source).getMetadata()); + if (source instanceof org.jboss.resteasy.client.ClientResponse) { + entity = ((org.jboss.resteasy.client.ClientResponse)source).getEntity(type); + } else { + entity = source.getEntity(); + } + return new BuiltResponsePreservingError(status, headers, entity, new Annotation[0], null); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + return new BuiltResponsePreservingError(status, headers, entity, new Annotation[0], e); + } finally { + if (source instanceof BaseClientResponse) + ((BaseClientResponse)source).close(); + } + } + + @Override + public Object getEntity() { + if (error!=null) { + throw new IllegalStateException("getEntity called on BuiltResponsePreservingError, where an Error had been preserved", error); + } + return super.getEntity(); + } + +} diff --git a/java/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java b/java/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java new file mode 100644 index 0000000..81d789f --- /dev/null +++ b/java/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.rest.client; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.util.Collection; + +import javax.ws.rs.core.Response; + +import org.apache.brooklyn.api.entity.Application; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.core.entity.StartableApplication; +import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; +import org.apache.brooklyn.core.location.BasicLocationRegistry; +import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; +import org.apache.brooklyn.rest.BrooklynRestApiLauncher; +import org.apache.brooklyn.rest.BrooklynRestApiLauncherTest; +import org.apache.brooklyn.rest.domain.ApplicationSpec; +import org.apache.brooklyn.rest.domain.ApplicationSummary; +import org.apache.brooklyn.rest.domain.EntitySpec; +import org.apache.brooklyn.rest.domain.EntitySummary; +import org.apache.brooklyn.rest.domain.SensorSummary; +import org.apache.brooklyn.test.Asserts; +import org.apache.brooklyn.util.time.Duration; +import org.eclipse.jetty.server.Server; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import org.eclipse.jetty.server.NetworkConnector; + +@Test(singleThreaded = true) +public class ApplicationResourceIntegrationTest { + + private static final Logger log = LoggerFactory.getLogger(ApplicationResourceIntegrationTest.class); + + private static final Duration LONG_WAIT = Duration.minutes(10); + + private final String redisSpec = "{\"name\": \"redis-app\", \"type\": \"org.apache.brooklyn.entity.nosql.redis.RedisStore\", \"locations\": [ \"localhost\"]}"; + + private final ApplicationSpec legacyRedisSpec = ApplicationSpec.builder().name("redis-legacy-app") + .entities(ImmutableSet.of(new EntitySpec("redis-ent", "org.apache.brooklyn.entity.nosql.redis.RedisStore"))) + .locations(ImmutableSet.of("localhost")) + .build(); + + private ManagementContext manager; + + protected synchronized ManagementContext getManagementContext() throws Exception { + if (manager == null) { + manager = new LocalManagementContext(); + BrooklynRestApiLauncherTest.forceUseOfDefaultCatalogWithJavaClassPath(manager); + BasicLocationRegistry.addNamedLocationLocalhost(manager); + BrooklynRestApiLauncherTest.enableAnyoneLogin(manager); + } + return manager; + } + + BrooklynApi api; + + @BeforeClass(groups = "Integration") + public void setUp() throws Exception { + Server server = BrooklynRestApiLauncher.launcher() + .managementContext(getManagementContext()) + .start(); + + api = BrooklynApi.newInstance("http://localhost:" + ((NetworkConnector)server.getConnectors()[0]).getPort() + "/"); + } + + @AfterClass(alwaysRun = true) + public void tearDown() throws Exception { + for (Application app : getManagementContext().getApplications()) { + try { + ((StartableApplication) app).stop(); + } catch (Exception e) { + log.warn("Error stopping app " + app + " during test teardown: " + e); + } + } + } + + @Test(groups = "Integration") + public void testDeployRedisApplication() throws Exception { + Response response = api.getApplicationApi().createPoly(redisSpec.getBytes()); + assertEquals(response.getStatus(), 201); + assertEquals(getManagementContext().getApplications().size(), 1); + final String entityId = getManagementContext().getApplications().iterator().next().getChildren().iterator().next().getId(); + assertServiceStateEventually("redis-app", entityId, Lifecycle.RUNNING, LONG_WAIT); + } + + @Test(groups = "Integration", dependsOnMethods = "testDeployRedisApplication") + public void testDeployLegacyRedisApplication() throws Exception { + @SuppressWarnings("deprecation") + Response response = api.getApplicationApi().create(legacyRedisSpec); + assertEquals(response.getStatus(), 201); + assertEquals(getManagementContext().getApplications().size(), 2); + assertServiceStateEventually("redis-legacy-app", "redis-ent", Lifecycle.RUNNING, LONG_WAIT); + + // Tear the app down so it doesn't interfere with other tests + Response deleteResponse = api.getApplicationApi().delete("redis-legacy-app"); + assertEquals(deleteResponse.getStatus(), 202); + assertEquals(getManagementContext().getApplications().size(), 1); + } + + @Test(groups = "Integration", dependsOnMethods = "testDeployRedisApplication") + public void testListEntities() { + Collection entities = api.getEntityApi().list("redis-app"); + Assert.assertFalse(entities.isEmpty()); + } + + @Test(groups = "Integration", dependsOnMethods = "testDeployRedisApplication") + public void testListSensorsRedis() throws Exception { + String entityId = getManagementContext().getApplications().iterator().next().getChildren().iterator().next().getId(); + Collection sensors = api.getSensorApi().list("redis-app", entityId); + assertTrue(sensors.size() > 0); + SensorSummary uptime = Iterables.find(sensors, new Predicate() { + @Override + public boolean apply(SensorSummary sensorSummary) { + return sensorSummary.getName().equals("redis.uptime"); + } + }); + assertEquals(uptime.getType(), "java.lang.Integer"); + } + + @Test(groups = "Integration", dependsOnMethods = {"testListSensorsRedis", "testListEntities"}) + public void testTriggerRedisStopEffector() throws Exception { + final String entityId = getManagementContext().getApplications().iterator().next().getChildren().iterator().next().getId(); + Response response = api.getEffectorApi().invoke("redis-app", entityId, "stop", "5000", ImmutableMap.of()); + + assertEquals(response.getStatus(), Response.Status.ACCEPTED.getStatusCode()); + assertServiceStateEventually("redis-app", entityId, Lifecycle.STOPPED, LONG_WAIT); + } + + @Test(groups = "Integration", dependsOnMethods = "testTriggerRedisStopEffector") + public void testDeleteRedisApplication() throws Exception { + int size = getManagementContext().getApplications().size(); + Response response = api.getApplicationApi().delete("redis-app"); + Assert.assertNotNull(response); + try { + Asserts.succeedsEventually(ImmutableMap.of("timeout", Duration.minutes(1)), new Runnable() { + public void run() { + try { + ApplicationSummary summary = api.getApplicationApi().get("redis-app"); + fail("Redis app failed to disappear: summary="+summary); + } catch (Exception failure) { + // expected -- it will be a ClientResponseFailure but that class is deprecated so catching all + // and asserting contains the word 404 + Assert.assertTrue(failure.toString().indexOf("404") >= 0, "wrong failure, got: "+failure); + } + }}); + } catch (Exception failure) { + // expected -- as above + Assert.assertTrue(failure.toString().indexOf("404") >= 0, "wrong failure, got: "+failure); + } + + assertEquals(getManagementContext().getApplications().size(), size - 1); + } + + private void assertServiceStateEventually(final String app, final String entity, final Lifecycle state, Duration timeout) { + Asserts.succeedsEventually(ImmutableMap.of("timeout", timeout), new Runnable() { + public void run() { + Object status = api.getSensorApi().get(app, entity, "service.state", false); + assertTrue(state.toString().equalsIgnoreCase(status.toString()), "status="+status); + }}); + } +} diff --git a/java/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java b/java/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java new file mode 100644 index 0000000..96c898e --- /dev/null +++ b/java/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.rest.client; + +import static org.testng.Assert.assertEquals; + +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.Response; + +import org.apache.brooklyn.api.entity.Application; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.core.BrooklynVersion; +import org.apache.brooklyn.core.entity.Entities; +import org.apache.brooklyn.core.entity.StartableApplication; +import org.apache.brooklyn.core.location.BasicLocationRegistry; +import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; +import org.apache.brooklyn.core.test.entity.TestEntity; +import org.apache.brooklyn.rest.BrooklynRestApiLauncher; +import org.apache.brooklyn.rest.BrooklynRestApiLauncherTest; +import org.apache.brooklyn.rest.domain.ApplicationSummary; +import org.apache.brooklyn.rest.domain.CatalogLocationSummary; +import org.apache.brooklyn.rest.security.provider.TestSecurityProvider; +import org.apache.brooklyn.test.Asserts; +import org.apache.brooklyn.util.http.HttpAsserts; +import org.eclipse.jetty.server.NetworkConnector; +import org.eclipse.jetty.server.Server; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +@Test +public class BrooklynApiRestClientTest { + + private static final Logger log = LoggerFactory.getLogger(BrooklynApiRestClientTest.class); + + private ManagementContext manager; + private Server server; + private BrooklynApi api; + + protected synchronized ManagementContext getManagementContext() throws Exception { + if (manager == null) { + manager = new LocalManagementContext(); + BrooklynRestApiLauncherTest.forceUseOfDefaultCatalogWithJavaClassPath(manager); + BasicLocationRegistry.addNamedLocationLocalhost(manager); + BrooklynRestApiLauncherTest.enableAnyoneLogin(manager); + } + return manager; + } + + @BeforeClass + public void setUp() throws Exception { + server = BrooklynRestApiLauncher.launcher() + .managementContext(manager) + .securityProvider(TestSecurityProvider.class) + .start(); + + api = BrooklynApi.newInstance("http://localhost:" + ((NetworkConnector)server.getConnectors()[0]).getPort() + "/v1", + TestSecurityProvider.USER, TestSecurityProvider.PASSWORD); + } + + @AfterClass(alwaysRun = true) + public void tearDown() throws Exception { + for (Application app : getManagementContext().getApplications()) { + try { + ((StartableApplication) app).stop(); + } catch (Exception e) { + log.warn("Error stopping app " + app + " during test teardown: " + e); + } + } + Entities.destroyAll(getManagementContext()); + server.stop(); + } + + public void testNoV1InUrl() { + api = BrooklynApi.newInstance("http://localhost:" + ((NetworkConnector)server.getConnectors()[0]).getPort(), + TestSecurityProvider.USER, TestSecurityProvider.PASSWORD); + + assertEquals(api.getServerApi().getVersion().getVersion(), BrooklynVersion.get()); + } + + public void testLocationApi() throws Exception { + log.info("Testing location API"); + Map> locations = api.getLocationApi().getLocatedLocations(); + log.info("locations located are: "+locations); + } + + public void testCatalogApiLocations() throws Exception { + List locations = api.getCatalogApi().listLocations(".*", null, false); + log.info("locations from catalog are: "+locations); + } + + public void testCatalogCreate()throws Exception { + final Response response = api.getCatalogApi().create(getFileContentsAsString("catalog/test-catalog.bom")); + Asserts.assertEquals(response.getStatus(), 201); + Asserts.assertStringContains(String.valueOf(response.getEntity()), "simple-tomcat:1.0"); + } + + + + public void testApplicationApiList() throws Exception { + List apps = api.getApplicationApi().list(null); + log.info("apps are: "+apps); + } + + public void testApplicationApiCreate() throws Exception { + Response r1 = api.getApplicationApi().createFromYaml("name: test-1234\n" + + "services: [ { type: "+TestEntity.class.getName()+" } ]"); + HttpAsserts.assertHealthyStatusCode(r1.getStatus()); + log.info("creation result: "+r1.getEntity()); + List apps = api.getApplicationApi().list(null); + log.info("apps with test: "+apps); + Asserts.assertStringContains(apps.toString(), "test-1234"); + } + + public void testApplicationApiHandledError() throws Exception { + Response r1 = api.getApplicationApi().createFromYaml("name: test"); + HttpAsserts.assertNotHealthyStatusCode(r1.getStatus()); + // new-style messages first, old-style messages after (during switch to TypePlanTransformer) + Asserts.assertStringContainsAtLeastOne(r1.getEntity().toString().toLowerCase(), + "invalid plan", "no services"); + Asserts.assertStringContainsAtLeastOne(r1.getEntity().toString().toLowerCase(), + "format could not be recognized", "Unrecognized application blueprint format"); + } + + public void testApplicationApiThrownError() throws Exception { + try { + ApplicationSummary summary = api.getApplicationApi().get("test-5678"); + Asserts.shouldHaveFailedPreviously("got "+summary); + } catch (Exception e) { + Asserts.expectedFailureContainsIgnoreCase(e, "404", "not found"); + } + } + + private String getFileContentsAsString(final String filename) throws Exception { + final URL resource = getClass().getClassLoader().getResource(filename); + Asserts.assertNotNull(resource); + return new String(Files.readAllBytes(Paths.get(resource.toURI())), Charset.defaultCharset()); + } +} diff --git a/java/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiUtilTest.java b/java/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiUtilTest.java new file mode 100644 index 0000000..9cae021 --- /dev/null +++ b/java/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiUtilTest.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.brooklyn.rest.client; + +import static org.apache.brooklyn.test.Asserts.assertEquals; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; + +import org.apache.brooklyn.util.collections.Jsonya; +import org.apache.brooklyn.util.core.http.BetterMockWebServer; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Joiner; +import com.google.mockwebserver.MockResponse; +import com.google.mockwebserver.RecordedRequest; + +public class BrooklynApiUtilTest { + + private static final String APP_ID = "fedcba"; + + private static final String YAML = Joiner.on("\n").join( + "name: test-blueprint", + "location: localhost", + "services:", + "- type: brooklyn.entity.basic.EmptySoftwareProcess"); + + private BetterMockWebServer server; + + @BeforeMethod(alwaysRun = true) + public void newMockWebServer() { + server = BetterMockWebServer.newInstanceLocalhost(); + } + + @AfterMethod(alwaysRun = true) + public void shutDownServer() throws Exception { + if (server != null) server.shutdown(); + } + + @Test + public void testDeployBlueprint() throws Exception { + server.enqueue(taskSummaryResponse()); + server.play(); + + BrooklynApi api = BrooklynApi.newInstance(server.getUrl("/").toString()); + BrooklynApiUtil.deployBlueprint(api, YAML); + + RecordedRequest request = server.takeRequest(); + assertEquals(request.getPath(), "/v1/applications"); + assertEquals(request.getMethod(), "POST"); + assertEquals(new String(request.getBody()), YAML); + } + + @Test + public void testWaitForRunningExitsCleanlyWhenAppRunning() throws Exception { + server.enqueue(applicationStatusResponse("RUNNING")); + server.play(); + + BrooklynApi api = BrooklynApi.newInstance(server.getUrl("/").toString()); + BrooklynApiUtil.waitForRunningAndThrowOtherwise(api, "appId", "taskId"); + // i.e. no exception + } + + @Test(expectedExceptions = {IllegalStateException.class}) + public void testWaitForRunningFailsWhenAppStatusError() throws Exception { + server.enqueue(applicationStatusResponse("ERROR")); + // Method checks for status of task. + server.enqueue(taskSummaryResponse()); + server.play(); + + BrooklynApi api = BrooklynApi.newInstance(server.getUrl("/").toString()); + BrooklynApiUtil.waitForRunningAndThrowOtherwise(api, "appId", "taskId"); + } + + @Test(expectedExceptions = {IllegalStateException.class}) + public void testWaitForRunningFailsWhenAppStatusUnknown() throws Exception { + server.enqueue(applicationStatusResponse("UNKNOWN")); + // Method checks for status of task. + server.enqueue(taskSummaryResponse()); + server.play(); + + BrooklynApi api = BrooklynApi.newInstance(server.getUrl("/").toString()); + BrooklynApiUtil.waitForRunningAndThrowOtherwise(api, "appId", "taskId"); + } + + /** @return a response whose Content-Type header is application/json. */ + private MockResponse newJsonResponse() { + return new MockResponse() + .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + } + + private MockResponse taskSummaryResponse() { + String body = Jsonya.newInstance() + .put("id", "taskid") + .put("entityId", APP_ID) + .toString(); + return newJsonResponse().setBody(body); + } + + private MockResponse applicationStatusResponse(String status) { + String body = Jsonya.newInstance() + .put("status", status) + .at("spec", "locations").list().add("localhost") + .root() + .toString(); + return newJsonResponse() + .setBody(body); + } + +} diff --git a/java/src/test/resources/catalog/test-catalog.bom b/java/src/test/resources/catalog/test-catalog.bom new file mode 100644 index 0000000..698bcf2 --- /dev/null +++ b/java/src/test/resources/catalog/test-catalog.bom @@ -0,0 +1,33 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +brooklyn.catalog: + id: simple-tomcat + version: 1.0 + itemType: template + iconUrl: http://tomcat.apache.org/images/tomcat.png + name: Simple Tomcat + license: Apache-2.0 + item: + brooklyn.config: + simple.confg: someValue + services: + - type: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer + id: tomcat + name: Tomcat + war: https://tomcat.apache.org/tomcat-6.0-doc/appdev/sample/sample.war \ No newline at end of file diff --git a/java/src/test/webapp/WEB-INF/web.xml b/java/src/test/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..38b637a --- /dev/null +++ b/java/src/test/webapp/WEB-INF/web.xml @@ -0,0 +1,129 @@ + + + + + + Brooklyn REST API v1 + + + Brooklyn Request Tagging Filter + org.apache.brooklyn.rest.filter.RequestTaggingFilter + + + Brooklyn Request Tagging Filter + /* + + + + Brooklyn Properties Authentication Filter + org.apache.brooklyn.rest.filter.BrooklynPropertiesSecurityFilter + + + Brooklyn Properties Authentication Filter + /* + + + + Brooklyn Logging Filter + org.apache.brooklyn.rest.filter.LoggingFilter + + + Brooklyn Logging Filter + /* + + + + Brooklyn HA Master Filter + org.apache.brooklyn.rest.filter.HaMasterCheckFilter + + + Brooklyn HA Master Filter + /* + + + + + Brooklyn REST API v1 Filter + com.sun.jersey.spi.container.servlet.ServletContainer + + + + com.sun.jersey.config.property.resourceConfigClass + com.sun.jersey.api.core.ClassNamesResourceConfig + + + com.sun.jersey.config.property.classnames + + org.apache.brooklyn.rest.apidoc.ApidocHelpMessageBodyWriter; + org.apache.brooklyn.rest.util.FormMapProvider; + com.fasterxml.jackson.jaxrs.JacksonJsonProvider; + org.apache.brooklyn.rest.resources.ActivityResource; + org.apache.brooklyn.rest.resources.ApidocResource; + org.apache.brooklyn.rest.resources.ApplicationResource; + org.apache.brooklyn.rest.resources.CatalogResource; + org.apache.brooklyn.rest.resources.EffectorResource; + org.apache.brooklyn.rest.resources.EntityConfigResource; + org.apache.brooklyn.rest.resources.EntityResource; + org.apache.brooklyn.rest.resources.LocationResource; + org.apache.brooklyn.rest.resources.PolicyConfigResource; + org.apache.brooklyn.rest.resources.PolicyResource; + org.apache.brooklyn.rest.resources.ScriptResource; + org.apache.brooklyn.rest.resources.SensorResource; + org.apache.brooklyn.rest.resources.VersionResource; + + + + + com.sun.jersey.api.json.POJOMappingFeature + true + + + + + com.sun.jersey.config.feature.DisableWADL + true + + + + + Brooklyn REST API v1 Filter + /* + + + diff --git a/pom.xml b/pom.xml index 866ca04..292f835 100644 --- a/pom.xml +++ b/pom.xml @@ -17,116 +17,472 @@ specific language governing permissions and limitations under the License. --> - + 4.0.0 - org.apache.brooklyn - brooklyn-parent - 0.10.0-SNAPSHOT - ../brooklyn-server/parent/ + org.apache + apache + 17 + - + + org.apache.brooklyn + brooklyn-client + 0.10.0-SNAPSHOT pom - brooklyn-client-cli - Brooklyn Client Command Line Interface + Brooklyn Client - A command line client for Apache Brooklyn + Brooklyn Client project root, serving as the ancestor POM for all projects -- + declaring versions, profiles, and the modules to build + + scm:git:https://git-wip-us.apache.org/repos/asf/incubator-brooklyn.git + scm:git:https://git-wip-us.apache.org/repos/asf/brooklyn.git + https://git-wip-us.apache.org/repos/asf?p=incubator-brooklyn.git + HEAD + - - mvn -Dtarget=native clean install build for local platform - mvn -Dtarget=all clean install build for all supported platforms - mvn -Dtarget=cross -Dos=OS -Darch=ARCH clean install build for platform with operating system OS and architecture ARCH + 6.0.0 - --> + + 1.7 + UTF-8 + UTF-8 + + + + Integration,Acceptance,Live,Live-sanity,WIP,Broken + false + + + 1.0.7 + 1.6.6 + 16.0.1 + 3.0.8.Final + 3.1.4 + 4.4.1 + 2.0.1 + 2.3 + 9.2.13.v20150730 + 3.1.M0 + 20121111 + + + 6.8.8 + 1.10.8 + 2.2.0 + 2.7 + 2.18.1 + 6121 + 1.8.4 + + + 2.4 + 2.8 + 1.5.2 + 1.0.3 + 0.10.25 + 1.3.1.5 + 2.0.0 + 1.7 - - 1.8 - 2.6 - all - - - - apache.snapshots - Apache Snapshot Repository - http://repository.apache.org/snapshots - - false - - - + + + + com.google.guava + guava + ${guava.version} + + + + org.jboss.resteasy + resteasy-jaxrs + ${resteasy.version} + + + org.jboss.resteasy + resteasy-jackson2-provider + ${resteasy.version} + + + org.jboss.resteasy + jaxrs-api + ${resteasy.version} + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + com.google.code.findbugs + jsr305 + ${jsr305.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + com.google.code.gson + gson + ${gson.version} + + + org.testng + testng + ${testng.version} + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + com.google.mockwebserver + mockwebserver + ${mockwebserver.version} + + + + + + cli + java + - - - maven-antrun-plugin - 1.8 - - - process-build-all - compile - - - - - - - run - - - - - - - - maven-assembly-plugin - ${maven.assembly.plugin.version} - - - release/assembly.xml - - - - - make-assembly - package - - single - - - - - - - org.apache.rat - apache-rat-plugin - 0.11 - - - vendor/** - glide.* - - - - - + src/test/java + + + src/test/resources + + + + + + + maven-antrun-plugin + 1.8 + + + maven-clean-plugin + 2.6.1 + + + maven-compiler-plugin + 3.3 + + ${java.version} + ${java.version} + + + + maven-deploy-plugin + 2.8.2 + + + maven-eclipse-plugin + 2.10 + + + org.eclipse.jdt.groovy.core.groovyNature + + + + + maven-enforcer-plugin + 1.4.1 + + + maven-failsafe-plugin + 2.18.1 + + + maven-jar-plugin + + + 2.6 + + + maven-javadoc-plugin + 2.10.3 + + + false + + http://download.oracle.com/javaee/6/api + + true + false + true + false + false + + + + todo + a + To-do: + + + + + + attach-javadocs + + jar + + + + + + maven-resources-plugin + 2.7 + + + maven-shade-plugin + 2.3 + + + package + + shade + + + true + with-dependencies + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + maven-site-plugin + 3.4 + + + maven-source-plugin + 2.4 + + + attach-sources + verify + + jar-no-fork + test-jar-no-fork + + + + + + maven-surefire-plugin + ${surefire.version} + + -Xms768m -Xmx768m -XX:MaxPermSize=256m -verbose:gc + + + + org.apache.felix + maven-bundle-plugin + 2.5.4 + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.1 + + + org.codehaus.mojo + build-helper-maven-plugin + 1.9.1 + + + org.codehaus.mojo + cobertura-maven-plugin + ${cobertura.plugin.version} + + + com.google.code.maven-replacer-plugin + maven-replacer-plugin + 1.4.1 + + + org.codehaus.mojo + buildnumber-maven-plugin + 1.3 + + true + + + + org.apache.rat + apache-rat-plugin + 0.11 + + + + sandbox/** + + release/** + README.md + + **/nbactions.xml + **/nb-configuration.xml + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.apache.maven.plugins + maven-dependency-plugin + [2.8,) + + copy-dependencies + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + [2.4.1,) + + single + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + [1.7,) + + attach-artifact + + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + [1.3.1,) + + enforce + + + + + + + + + org.apache.maven.plugins + maven-remote-resources-plugin + [1.5,) + + process + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + [2.8,) + + unpack + copy + + + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + [2.13,) + + check + + + + + + + + + + + +