This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
The following commit(s) were added to refs/heads/master by this push: new 603680b add rest api methods for modifying entity tags 603680b is described below commit 603680bc44294ac85562cbd23f1e1a77c92d2393 Author: Alex Heneveld <alex.henev...@cloudsoftcorp.com> AuthorDate: Tue Oct 26 15:59:19 2021 +0100 add rest api methods for modifying entity tags --- .../apache/brooklyn/core/mgmt/BrooklynTags.java | 12 +++++ .../org/apache/brooklyn/rest/api/EntityApi.java | 57 ++++++++++++++++++++++ .../brooklyn/rest/resources/EntityResource.java | 25 ++++++++++ .../rest/resources/EntityResourceTest.java | 43 +++++++++++++++- 4 files changed, 136 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTags.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTags.java index a9188c1..7c13fd0 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTags.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTags.java @@ -25,6 +25,7 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; +import org.apache.brooklyn.api.objs.BrooklynObject.TagSupport; import org.apache.brooklyn.core.resolve.jackson.BeanWithTypeUtils; import org.apache.brooklyn.util.collections.MutableList; @@ -104,6 +105,17 @@ public class BrooklynTags { } } + public static <T> void upsertSingleKeyMapValueTag(TagSupport tagS, String key, T value) { + MutableList<Object> matchingKeyTags = MutableList.of(); + tagS.getTags().stream().forEach(t -> { + if (isTagSingleKeyMap(t, key)) { + matchingKeyTags.add(t); + } + }); + matchingKeyTags.forEach(tagS::removeTag); + tagS.addTag(MutableMap.of(key, value)); + } + public static NamedStringTag findFirstNamedStringTag(String kind, Iterable<Object> tags) { return findFirstOfKind(kind, NamedStringTag.class, tags); } diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityApi.java index 6c35f69..b5dc946 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityApi.java @@ -167,6 +167,63 @@ public interface EntityApi { @ApiParam(value = "Application ID or name", required = true) @PathParam("application") String applicationId, @ApiParam(value = "Entity ID or name", required = true) @PathParam("entity") String entityId); + // this feels too dangerous; see other items +// @POST +// @Path("/{entity}/tags") +// @ApiOperation(value = "Set the tags on this entity (replaces all, use with care)") +// @ApiResponses(value = { +// @ApiResponse(code = 404, message = "Could not find application or entity") +// }) +// public void setTags( +// @ApiParam(value = "Application ID or name", required = true) @PathParam("application") String applicationId, +// @ApiParam(value = "Entity ID or name", required = true) @PathParam("entity") String entityId, +// @ApiParam(value = "Tags to set", required = true) List<Object> tags); + + @POST + @Path("/{entity}/tag/add") + @ApiOperation(value = "Add a tag on this entity") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application or entity") + }) + public void addTag( + @ApiParam(value = "Application ID or name", required = true) @PathParam("application") String applicationId, + @ApiParam(value = "Entity ID or name", required = true) @PathParam("entity") String entityId, + @ApiParam(value = "Tag to add", required = true) Object tag); + + @POST + @Path("/{entity}/tag/delete") + @ApiOperation(value = "Delete a tag on this entity, returning whether the tag was found (and deleted)") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application or entity") + }) + public boolean deleteTag( + @ApiParam(value = "Application ID or name", required = true) @PathParam("application") String applicationId, + @ApiParam(value = "Entity ID or name", required = true) @PathParam("entity") String entityId, + @ApiParam(value = "Tag to delete", required = true) Object tag); + + @POST + @Path("/{entity}/tag/upsert/{tagKey}") + @ApiOperation(value = "Inserts a tag which is a single-key map with the given key (path parameter) and value (post body), removing any existing tag matching the key") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application or entity") + }) + public void upsertTag( + @ApiParam(value = "Application ID or name", required = true) @PathParam("application") String applicationId, + @ApiParam(value = "Entity ID or name", required = true) @PathParam("entity") String entityId, + @ApiParam(value = "Entity ID or name", required = true) @PathParam("tagKey") String tagKey, + @ApiParam(value = "Tag map value to upsert for the given key", required = true) Object tagValue); + + @GET + @Path("/{entity}/tag/get/{tagKey}") + @ApiOperation(value = "Returns the tag value for a tag which is a single-key map with the given key, or null (not 404 for missing tag key)") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application or entity") + }) + public Object getTag( + @ApiParam(value = "Application ID or name", required = true) @PathParam("application") String applicationId, + @ApiParam(value = "Entity ID or name", required = true) @PathParam("entity") String entityId, + @ApiParam(value = "Entity ID or name", required = true) @PathParam("tagKey") String tagKey); + @POST @ApiOperation( value = "Rename an entity" diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java index a068402..dc17a21 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java @@ -21,6 +21,7 @@ package org.apache.brooklyn.rest.resources; import static javax.ws.rs.core.Response.created; import static javax.ws.rs.core.Response.status; import static javax.ws.rs.core.Response.Status.ACCEPTED; +import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.core.mgmt.BrooklynTags.SpecSummary; import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceAbsoluteUriBuilder; @@ -257,6 +258,30 @@ public class EntityResource extends AbstractBrooklynRestResource implements Enti } @Override + public void addTag(String applicationId, String entityId, Object tag) { + Entity entity = brooklyn().getEntity(applicationId, entityId); + entity.tags().addTag(tag); + } + + @Override + public boolean deleteTag(String applicationId, String entityId, Object tag) { + Entity entity = brooklyn().getEntity(applicationId, entityId); + return entity.tags().removeTag(tag); + } + + @Override + public void upsertTag(String applicationId, String entityId, String tagKey, Object tagValue) { + Entity entity = brooklyn().getEntity(applicationId, entityId); + BrooklynTags.upsertSingleKeyMapValueTag(entity.tags(), tagKey, tagValue); + } + + @Override + public Object getTag(String applicationId, String entityId, String tagKey) { + Entity entity = brooklyn().getEntity(applicationId, entityId); + return BrooklynTags.findSingleKeyMapValue(tagKey, Object.class, entity.tags().getTags()); + } + + @Override public Response getIcon(String applicationId, String entityId) { Entity entity = brooklyn().getEntity(applicationId, entityId); String url = RegisteredTypes.getIconUrl(entity); diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityResourceTest.java index 59af350..00e41d3 100644 --- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityResourceTest.java +++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityResourceTest.java @@ -18,6 +18,8 @@ */ package org.apache.brooklyn.rest.resources; +import org.apache.brooklyn.test.Asserts; +import org.apache.brooklyn.util.collections.MutableMap; import static org.testng.Assert.assertEquals; import java.util.Collection; @@ -227,5 +229,44 @@ public class EntityResourceTest extends BrooklynRestResourceTest { Assert.assertEquals( ((Entity)appTag).getId(), entity.getApplicationId(), "Wrong ID: "+appTag); Assert.assertTrue(appTag instanceof BasicApplication, "Should have deserialized BasicApplication: "+appTag); } - + + @Test + public void testTagsChangingViaRest() throws Exception { + entity.tags().addTag("foo"); + + Response response; + + response = client().path(entityEndpoint + "/tag/add").accept(MediaType.APPLICATION_JSON).post(toJsonEntity("bar")); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); + + response = client().path(entityEndpoint + "/tag/add").accept(MediaType.APPLICATION_JSON).post(toJsonEntity(MutableMap.of("baz_key", "baz_value"))); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); + + String raw; + response = client().path(entityEndpoint + "/tags").accept(MediaType.APPLICATION_JSON).get(); + raw = response.readEntity(String.class); + log.info("TAGS raw: "+raw); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); + Asserts.assertStringContains(raw, "foo"); + Asserts.assertStringContains(raw, "bar"); + Asserts.assertStringContains(raw, "baz_key", "baz_value"); + + response = client().path(entityEndpoint + "/tag/upsert/baz_key").accept(MediaType.APPLICATION_JSON).post(toJsonEntity("baz2_value")); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); + response = client().path(entityEndpoint + "/tags").accept(MediaType.APPLICATION_JSON).get(); + raw = response.readEntity(String.class); + Asserts.assertStringContains(raw, "baz_key", "baz2_value"); + Asserts.assertStringDoesNotContain(raw, "baz_value"); + + response = client().path(entityEndpoint + "/tag/delete").accept(MediaType.APPLICATION_JSON).post(toJsonEntity("bar")); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); + response = client().path(entityEndpoint + "/tag/delete").accept(MediaType.APPLICATION_JSON).post(toJsonEntity(MutableMap.of("baz_key", "baz2_value"))); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); + response = client().path(entityEndpoint + "/tags").accept(MediaType.APPLICATION_JSON).get(); + raw = response.readEntity(String.class); + Asserts.assertStringDoesNotContain(raw, "bar"); + Asserts.assertStringDoesNotContain(raw, "baz_key"); + Asserts.assertStringContains(raw, "foo"); + } + }