Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REST API for accessing adjuncts (including highlights) #821

Merged
merged 10 commits into from
Oct 3, 2017

Conversation

ahgittin
Copy link
Contributor

@ahgittin ahgittin commented Sep 13, 2017

NB: builds on #810 and #818, review and merge those first

This is then just one commit (currently) which:

  • adds an AdjunctApi combining all the functionality of PolicyApi and PolicyConfigApi generalized across adjunct types
  • same for AdjunctConfigSummary
  • deprecates the replaced policy-specific endpoints and related classes, and also the CatalogApi /catalog endpoint (since we are deprecating; also there is some overlap at CatalogPolicyItem and PolicyConfigSummary etc)

This is mostly a drop-in replacement for the /applications/XXX/entities/XXX/policies/* endpoints, now using /applications/XXX/entities/XXX/adjuncts/* and returning other items. Note also that:

  • GET /v1/applications/XXX/entities/XXX/adjuncts?adjunctType=policy filters by policy (same for other types)
  • adjunctType is included in the returned object
  • the detail object if you GET /v1/applications/XXX/entities/XXX/adjuncts/XXX includes more info (config keys aka parameters, and values)
  • the links on the detail object include links to start and stop if and only if the adjunct supports that; it is recommended that clients use this value or at least check its presence rather than assume the declared .../start and .../stop endpoints will always be supported, as some adjuncts don't support (such as enrichers ... though we could and might change that ... so doing this check will be future-proof)

@ahgittin
Copy link
Contributor Author

These are the API calls, for reference. The Entity Policy and Entity Policy Config resources shown at bottom are now redundant (and deprecated).

screen shot 2017-09-13 at 17 21 26

@ahgittin ahgittin force-pushed the adjunct-rest-api-and-highlights branch from 07247e8 to 45261c7 Compare September 13, 2017 16:35
@ahgittin ahgittin force-pushed the adjunct-rest-api-and-highlights branch from 4a148f9 to 83c3d50 Compare September 25, 2017 12:08
@ahgittin
Copy link
Contributor Author

rebased to incorporate deprecation around the multiple config REST classes and add a tidy API for that

@tbouron
Copy link
Member

tbouron commented Sep 28, 2017

@ahgittin The description says This is then just one commit (currently) which: but there is still 1000+ additions. Is this up to date and rebase on master?

@ahgittin
Copy link
Contributor Author

@tbouron It's up to date. Primarily it is still just the one commit adding the Adjunct API -- it does have a lot of lines but they are mostly boilerplate (like a couple hundred just to declare the API) ... REST cruft and annotations.

However the merge of the XxxConfig deprecation had conflicts and there is a fair bit here tidying and improving that. Still pretty straightforward though.

@tbouron
Copy link
Member

tbouron commented Sep 28, 2017

Cool, thanks @ahgittin. I'm reviewing it right now.

Copy link
Member

@tbouron tbouron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ahgittin for the PR. There are few minor comments but most importantly, I tested it and found 2 interesting things:

  1. If you run in karaf mode (which is the default now) the new endpoint is not available! It's not the case for classic though.
  2. on the swagger page, it is never mentioned that the entire Entity Policy and Entity Policy Config are deprecated.

@@ -43,7 +43,7 @@

/**
* True if everything has been _started_ (or it is starting) but not stopped,
* even if it is suspended; see also {@link #isActive()}
* even if it is suspended; see also {@link #isRunning()}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither of isRunning or isActive methods are available in the class. Did you want to link to somewhere else?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isRunning is inherited from EntityAdjunct, so I think this javadoc link is ok.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isRunning() is avail, inherited from EntityAdjunct

@@ -189,7 +189,7 @@
void remove(AttributeSensor<?> attribute);
}

public interface FeedSupport {
public interface FeedSupport extends Iterable<Feed> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary to extend from Iterable and have an iterator() method here where we can get it from the getFeed().iterator() method (which always returns a collection) ? I don't see the benefit of creating this small shortcut

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this gives consistency with entity's enrichers() and policies() which both return something that implements Iterable<T>. I therefore think it's a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is to bring it in line with other AdjunctSupport classes. have made more steps in this direction in a new commit.

return Lifecycle.CREATED;
}

return Lifecycle.STOPPED;
Copy link
Member

@tbouron tbouron Sep 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What other adjunct should it be to arrive here? Enrichers? In this case, is an enricher really STOPPED instead of CREATED?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right, changed

}

@Beta
public static Lifecycle inferAdjunctStatus(EntityAdjunct a) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like this method is not in a right class. Would be more meaningful inside an Adjuncts class for example (an since it's static, it is not an issue to move it)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also deprecate the entire Policies class as all methods are already deprecated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good spot. moved to EntityAdjuncts and deprecated this class, removing previously deprecated methods

@ApiParam(value = "Entity ID or name", required = true)
@PathParam("entity") final String entityToken,
@ApiParam(value = "Filter by adjunct type", required = false)
@QueryParam("adjunctType") final String adjunctType);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type would be better here as we already have the context, i.e. we are looking at a specific type for an adjunct. But no strong feelings. It will also be consistent with the POST operation below

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wondered about type as well. Problem is we don't support filtering by the actual type (e.g. if someone is looking for AutoScalerPolicy only). It's a very similar discussion to the subtype/supertype/category discussion for PR https://github.com/apache/brooklyn-server/pull/810/files#diff-53a117c93b2d8af2b0b2198599c0c6d1. I think we should follow the same naming here as we do there - i.e. supertype.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, the POST takes a specific registered type, whereas this is essentially the adjunct kind; have improved comments to make clear. would adjunctKind be a better name? or supertype for consistency with /catalog/types ?

EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId);
if (adjunct instanceof Policy) ((Policy)adjunct).resume();
else if (adjunct instanceof Feed) ((Feed)adjunct).resume();
else throw WebResourceUtils.badRequest("%s does not support start/resume", adjunct);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think enrichers should support suspend/resume? If so, worth adding a TODO here.

EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId);
if (adjunct instanceof Policy) ((Policy)adjunct).suspend();
else if (adjunct instanceof Feed) ((Feed)adjunct).suspend();
else throw WebResourceUtils.badRequest("%s does not support suspend", adjunct);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

return Response.status(Response.Status.OK).build();
}

public static String getStringValueForDisplay(BrooklynRestResourceUtils utils, EntityAdjunct policy, Object value) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is unused, can be deleted

@@ -71,6 +71,8 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

/** @deprecated since 0.13.0 use RegisteredType methods */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Javadoc link for RegisteredType

}
for (Feed p: ((EntityInternal)entity).feeds()) {
if (adjunct.equals(p.getDisplayName())) return p;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can group the loops of the same type, that would reduce in half the processing time

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends whether we worry about a display name being the same as an id anywhere - and thus what guarantees we're trying to give.

I probably agree @tbouron. If we do want to keep them separate, we should iterate over all ids (policies, enrichers, feeds) before going on to display names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no - in perverse case where we have feed<ID=1 name=2> and feed<ID=2 name=foo> a call to get "2" should return the latter, whereas combining loops would return the former

we do need to compare all by ID's first however

agree it's an edge case and isn't significant but think the code should stay with separate loops.

PS processing time change would not be as large as you say as the string comparison dominates execution time and that is unchanged by combining loops.

@tbouron
Copy link
Member

tbouron commented Sep 28, 2017

BTW, I just realised that there is no tests coverage for the new endpoints Entity Adjuncts and Entity Adjuncts Config. Can you add that please @ahgittin ?

Copy link
Contributor

@aledsage aledsage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - only minor comments.

AbstractBrooklynObjectSpec<?, ?> spec;
if (rt!=null) {
spec = brooklyn().getTypeRegistry().createSpec(rt, null, null);
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I see this code is taken from PolicyResource.addPolicy, and has been approved - therefore no strong feelings for this PR.)

Do we really need the fallback to java, or can we assume that it must be in the catalog? (we don't even support feeds, which aren't in the catalog yet).

Ideally I'd like us to not have to support this code path, or to have a deprecation warning logged in that else branch (telling people to add it to the catalog).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd like to switch to yaml for this, have added comment

@ApiResponse(code = 404, message = "Could not find application or entity"),
@ApiResponse(code = 400, message = "Type is not a suitable adjunct")
})
public AdjunctSummary addAdjunct(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I compared the EntityApi.addChildren to this. It would be really nice if one could just pass in YAML for the adjunct being added (similar to addChildren).

How feasible would that be? I'm guessing our yaml parser just doesn't have the right entry points for that.

Perhaps we should mark this as @Beta (including in the swagger description text, and come back to it in a v2?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have added comment about supporting yaml. this isn't an addition, it's just a migration, so i wouldn't deprecate until we have the yaml parser for it. (with yoml it should be easy to plug in to the right place. not too hard even so.)

*
* @throws 404 or 412 (unless input is null in which case output is null) */
public EntityAdjunct getAdjunct(Entity entity, String adjunct) {
if (adjunct==null) return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels wrong to return null if the adjunct param is null.
Looking at the uses of it, that results in a subsequent NPE (i.e. a 500 response code).
I'd change this method to return an appropriate 4xx response code (not sure which one - writing this offline!)

I know that in this PR you've just followed the same convention as for getPolicy(), getEntity(), etc. But I think they are wrong as well! Happy for us to do that in a different PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make it separate just in case -- agree no use case for null input. i'd probably make it a fail-fast NPE (500 or 412 precondition failed) rather than a 404.

EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId);
if (adjunct instanceof Policy) ((Policy)adjunct).resume();
else if (adjunct instanceof Feed) ((Feed)adjunct).resume();
else throw WebResourceUtils.badRequest("%s does not support start/resume", adjunct);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think enrichers should support suspend/resume? If so, worth adding a TODO here.

return result;
}

// TODO support parameters ?show=value,summary&name=xxx &format={string,json,xml}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd move that comment to the AdjunctsApi interface, rather than in the impl (given it's about the api rather than the implementation).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already there

public String getConfig(String application, String entityToken, String adjunctToken, String configKeyName) {
EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctToken);
Set<ConfigKey<?>> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName)));
if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "in adjunct ", rather than "in policy ".


EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken);
Set<ConfigKey<?>> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName)));
if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "in adjunct ", rather than "in policy ".

public ConfigSummary transform() {
MutableMap.Builder<String, URI> lb = new MutableMap.Builder<String, URI>();

if (ub!=null && entity!=null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like a programming error if someone called includeLinks (to supply a UriBuilder), but the entity is null. Perhaps fail-fast rather than just missing out the links? Otherwise our unit tests may well all pass if such a programming error is introduced.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there might be a context where someone wants to include whatever links are possible but an entity may or may not be present. i wouldn't say it's necessarily a programming error. if inclusion in links is wanted unit tests should check it explicitly rather than constrain this method to fail-fast.

i'll update javadoc on includeLinks methods

@@ -36,6 +36,8 @@
@Api("Entity Policies")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
/** @deprecated since 0.12.0 use AdjunctApi */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be "since 0.13.0"?

(Please search https://github.com/apache/brooklyn-server/pull/821/files for that text)

}
for (Feed p: ((EntityInternal)entity).feeds()) {
if (adjunct.equals(p.getDisplayName())) return p;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends whether we worry about a display name being the same as an id anywhere - and thus what guarantees we're trying to give.

I probably agree @tbouron. If we do want to keep them separate, we should iterate over all ids (policies, enrichers, feeds) before going on to display names.

@ahgittin ahgittin force-pushed the adjunct-rest-api-and-highlights branch from e2c3f4c to 28dbb83 Compare October 3, 2017 11:29
@ahgittin
Copy link
Contributor Author

ahgittin commented Oct 3, 2017

one question from above to call out special @tbouron (given how github hides things) regarding the list method which takes argument

@QueryParam("adjunctType") final String adjunctType

you've suggested type but that normally refers to registered type which is wrong here; i think either leave as is, or change to supertype or adjunctKind. wdyt?

@ahgittin
Copy link
Contributor Author

ahgittin commented Oct 3, 2017

left it as adjunctType for now - could evolve to supertype in future

tests added

that's everything addresses i think

@tbouron
Copy link
Member

tbouron commented Oct 3, 2017

@ahgittin Sorry, I did miss your comment. I was suggesting type to be consistent with the DELETE method. I guess adjunctType is fine for now (superType is really confusing for me) but I would really like to fix this in the future, across all endpoints

ahgittin added a commit to ahgittin/brooklyn-server that referenced this pull request Oct 3, 2017
@asfgit asfgit merged commit d5d72cb into apache:master Oct 3, 2017
@ahgittin
Copy link
Contributor Author

ahgittin commented Oct 5, 2017

@tbouron totally forgot about your point karaf is missing this; have fixed that in #854 if you could take a quick look

@tbouron
Copy link
Member

tbouron commented Oct 5, 2017

@ahgittin I'll review #854 now. Although, there is another point that is missing from this PR: Swagger still don't show the deprecation warning for the entity policy endpoints.

For example, here is the one for /v1/locations:
screen shot 2017-10-05 at 10 24 12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants