Skip to content

Conversation

@scottduan
Copy link

What changes were proposed in this pull request?

When we post the REST api to create servicegroups, each sericegroup must include one and only one mpack name.

How was this patch tested?

(1) I have written an unit test to verify it
(2) I deployed a 3-node cluster and manually tested with REST API. This patch will break cluster deployment from webUI, so webUI needs another patch to support this change.

@scottduan
Copy link
Author

@jayush @mradha25

@scottduan
Copy link
Author

@swapanshridhar

@asfgit
Copy link

asfgit commented Jan 30, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/349/
Test FAILed.
Test FAILured.

if (!mpackNames.isEmpty()) {
sb.append(",mpackNames=");
mpackNames.stream().map(mpackName -> sb.append(mpackName + ","));
sb.deleteCharAt(sb.length()-1);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think simply using built-in Set.toString() would be OK. If you prefer explicit formatting, instead of map(append) please use Collectors.joining, which is side-effect free, and also makes deleteCharAt unnecessary.

Copy link
Author

Choose a reason for hiding this comment

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

Updated

public String toString() {
return String.format("clusterName=%s, serviceGroupName=%s", clusterName, serviceGroupName);
StringBuilder sb = new StringBuilder();
sb.append("clusterName="+clusterName+",serviceGroupName="+serviceGroupName);
Copy link
Contributor

Choose a reason for hiding this comment

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

Please avoid + inside append().

* @param mpackNames a list of associated mpack names
*/
public void setMpackNames(Set<String> mpackNames) {
this.mpackNames.addAll(mpackNames);
Copy link
Contributor

Choose a reason for hiding this comment

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

The method name says set, but it adds to existing ones.

Copy link
Author

Choose a reason for hiding this comment

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

You are right. I copied and wrote,but forgot to update the name.

ServiceGroupRequest svcRequest = new ServiceGroupRequest(clusterName, serviceGroupName);
Set<Object> mpackNames = (Set<Object>) properties.get(SERVICE_GROUP_SERVICE_GROUP_MPACKNAME_PROPERTY_ID);
if (mpackNames != null) {
Set<String> mpackNamesSet = mpackNames.stream().flatMap(mpack -> ((Map<String, String>)mpack).values().stream()).collect(Collectors.toSet());
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you minimize the number of unchecked casts by avoiding the intermediate Set<Object> type, and casting to Set<Map<String,String>> (or better yet, Collection<Map<String,String>>) in the first place?

private List<ServiceGroupDependencyEntity> dependencies;

@ElementCollection
@Column(name = "name")
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we need a corresponding change in the DDL scripts?
(ambari-server/src/main/resources/Ambari-DDL-*-CREATE.sql)

ERROR: relation "servicegroupentity_mpacknames" does not exist


void addServiceGroupMpackNames(Set<String> mpackNames);

void setServiceGroupMpackNames(Set<String> mpackNames);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please omit ServiceGroup from the method names?

Copy link
Author

Choose a reason for hiding this comment

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

Seems other methods have ServiceGroup, anyway, I will remove it.

if (!mpackNames.isEmpty()) {
sb.append(", mpackNames=");
mpackNames.stream().map(mpackName ->sb.append(mpackName + ","));
sb.deleteCharAt(sb.length()-1);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above for similar logic in ServiceGroupRequest.toString().

Copy link
Author

Choose a reason for hiding this comment

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

Updated

serviceGroupNames.get(clusterName).add(serviceGroupName);

if (request.getMpackNames().size() != 1) {
String errmsg = "Invalid arguments, only one mpack is allowed in the service group " + serviceGroupName;
Copy link
Contributor

Choose a reason for hiding this comment

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

Please distinguish between 0 mpacks and 2+ mpacks. The error message "only one mpack is allowed" is a bit confusing when the request doesn't specify any mpacks for the service group.

Copy link
Author

Choose a reason for hiding this comment

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

I did not write the description of this bug clearly. At this time, temporarily we only support one mpack per servicegroup, but finally each servicegroup must have one or more mpacks when multiple mpacks support code is implemented. Again, I will add more clearer errmsg here.

Copy link
Contributor

Choose a reason for hiding this comment

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

if (request.getMpackNames().size() < 1)
Error should be that "Invalid arguments, atleast one mpack should be specified for a service group"
From backend, we should not restrict the number of mpacks associated to a service group.
@jayush , please correct me if wrong.

System.out.println("++++++ Test invalid request successfully ++++++");
}

private static void runTestCreateServiceGroupsWithMpacks(String body) throws Exception{
Copy link
Contributor

Choose a reason for hiding this comment

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

If the same sequence is OK for both valid and invalid request, then what is being tested?

Copy link
Author

Choose a reason for hiding this comment

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

For invalid request, this is the negative test. As I mentioned above, actually at this time we only support 1 mpck per servicegroup. So in invalid test case, if we can detect it is invalid request, this test case succeeds. I will update the code to make it more clear.

public static final String SERVICE_GROUP_CLUSTER_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_name";
public static final String SERVICE_GROUP_SERVICE_GROUP_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "service_group_id";
public static final String SERVICE_GROUP_SERVICE_GROUP_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "service_group_name";
public static final String SERVICE_GROUP_SERVICE_GROUP_MPACKNAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "mpacks";
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we simply call it SERVICE_GROUP_MPACKNAME_PROPERTY_ID?

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Author

Choose a reason for hiding this comment

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

OK, I will change it to SERVICE_GROUP_MPACKNAME_PROPERTY_ID

serviceGroupNames.get(clusterName).add(serviceGroupName);

if (request.getMpackNames().size() != 1) {
String errmsg = "Invalid arguments, only one mpack is allowed in the service group " + serviceGroupName;
Copy link
Contributor

Choose a reason for hiding this comment

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

if (request.getMpackNames().size() < 1)
Error should be that "Invalid arguments, atleast one mpack should be specified for a service group"
From backend, we should not restrict the number of mpacks associated to a service group.
@jayush , please correct me if wrong.

@asfgit
Copy link

asfgit commented Feb 2, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/404/
Test FAILed.
Test FAILured.

Copy link
Contributor

@adoroszlai adoroszlai left a comment

Choose a reason for hiding this comment

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

Thanks for addressing previous comments.

try {
runTestCreateServiceGroupsWithMpacks(body);
} catch (IllegalArgumentException e) {
System.out.println("++++++ Test invalid request successfully ++++++");
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, the test is much clearer now for the reader. However, unit tests should fail in case of unexpected results, not print a message. Can you please:

  • extract the 2 test cases into separate methods
  • get rid of the try-catch in both cases
  • add @Test(expected = IllegalArgumentException.class) for the invalid request case

This will allow the test suite to catch any regression automatically, instead of relying on the developer to run it and look for text output. Thanks.

}
serviceGroupNames.get(clusterName).add(serviceGroupName);

if (request.getMpackNames().size() != 1) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this change introduces mpacks for service groups, and it also makes exactly one mpack a requirement, it breaks existing code that uses ServiceGroupResourceProvider to create mpacks. For one, it increases the number of failing/erroring unit tests:

[ERROR] Tests run: 5122, Failures: 39, Errors: 231, Skipped: 37
->
[ERROR] Tests run: 5123, Failures: 42, Errors: 296, Skipped: 37

Can you please address those? I think most could be fixed by adding some dummy mpack name in

public static void createServiceGroup(AmbariManagementController controller, String clusterName, String serviceGroupName)
throws AmbariException, AuthorizationException {
ServiceGroupRequest request = new ServiceGroupRequest(clusterName, serviceGroupName);
createServiceGroups(controller, Collections.singleton(request));
}

@asfgit
Copy link

asfgit commented Feb 5, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/425/
Test FAILed.
Test FAILured.

@jayush jayush requested a review from swapanshridhar February 5, 2018 15:43
@scottduan
Copy link
Author

@swapanshridhar

mpack_name VARCHAR(255) NOT NULL,
CONSTRAINT PK_servicegroup_mpackname PRIMARY KEY (service_group_id, service_group_cluster_id, mpack_name),
FOREIGN KEY (service_group_id) REFERENCES servicegroups(service_group_id),
FOREIGN KEY (service_group_cluster_id) REFERENCES servicegroups(service_group_cluster_id)
Copy link
Contributor

Choose a reason for hiding this comment

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

Constraints/foreign keys in this table are different than in the other DBMS schemas.

Copy link
Author

Choose a reason for hiding this comment

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

will update. Seems I forgot to update it.

service_group_cluster_id BIGINT NOT NULL,
mpack_name VARCHAR(255) NOT NULL UNIQUE,
CONSTRAINT PK_servicegroup_mpacknames PRIMARY KEY (service_group_id, service_group_cluster_id, mpack_name),
CONSTRAINT UQ_servicegroup_mpacknames UNIQUE (service_group_id, service_group_cluster_id),
Copy link
Contributor

Choose a reason for hiding this comment

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

These unique constraints will require upgrade logic for dropping them when Ambari wants to allow multiple mpacks per service group.

Copy link
Author

Choose a reason for hiding this comment

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

I will remove mapck_name unique constraint. Finally we should allow many-many relationship between servicegroup and mpack.

FOREIGN KEY (history_id) REFERENCES alert_history(alert_id)
);

CREATE TABLE servicegroup_mpackname (
Copy link
Contributor

Choose a reason for hiding this comment

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

Table name is different in this schema (servicegroup_mpackname vs servicegroup_mpacknames).

Copy link
Author

Choose a reason for hiding this comment

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

Typo, will change it.

CONSTRAINT PK_servicegroup_mpacknames PRIMARY KEY (service_group_id, service_group_cluster_id, mpack_name),
CONSTRAINT UQ_servicegroup_mpacknames UNIQUE (service_group_id, service_group_cluster_id),
CONSTRAINT FK_servicgroups FOREIGN KEY (service_group_id, service_group_cluster_id) REFERENCES servicegroups(id, cluster_id) ON DELETE CASCADE
);DatabaseConsistencyCheckHelper
Copy link
Contributor

Choose a reason for hiding this comment

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

DatabaseConsistencyCheckHelper does not seem to belong here, and will cause syntax error.

Copy link
Author

Choose a reason for hiding this comment

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

I donot know where it comes from. I will delete it.

@CollectionTable(name = "servicegroup_mpacknames",
joinColumns = {@JoinColumn(name = "service_group_id", referencedColumnName = "id"),
@JoinColumn(name = "service_group_cluster_id", referencedColumnName = "cluster_id")})
@Column(name = "mpack_name", unique = true, nullable = false)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think the mpack_name in itself should be unique. This causes unit test failures with the current constant "dummy" mpack name for tests. (eg. AmbariManagementControllerTest)

Copy link
Author

Choose a reason for hiding this comment

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

Actually mpack_name should not be unique. It should allow different service group to have the same mpack_name. I will remove this contraint.

@jonathan-hurley jonathan-hurley self-requested a review February 5, 2018 19:48
Copy link
Member

@jonathan-hurley jonathan-hurley left a comment

Choose a reason for hiding this comment

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

The SG -> Mpack association should be ManyToOne so that a given SG has a direct association to 1 (and only 1) Mpack at a given point. Something like this:

+  mpack_id BIGINT NOT NULL,
   CONSTRAINT PK_servicegroups PRIMARY KEY (id, cluster_id),
-  CONSTRAINT FK_servicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+  CONSTRAINT FK_servicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id),
+  CONSTRAINT FK_servicegroups_mpack_id FOREIGN KEY (mpack_id) REFERENCES mpacks (id));

Copy link
Contributor

@ncole ncole left a comment

Choose a reason for hiding this comment

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

It seems like there's a design issue here. MPacks have to be 1:1 to SG. In addition, you have to associate MPacks by ID. You can't just say "SG for HDPCORE" - if you have more than one registered, which one do you pick? We have to design this relationship a bit more tightly.

@Override
public String toString() {
return String.format("clusterName=%s, serviceGroupName=%s", clusterName, serviceGroupName);
StringBuilder sb = new StringBuilder();
Copy link
Contributor

Choose a reason for hiding this comment

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

We've been gradually moving to ToStringBuilder here instead

Copy link
Member

Choose a reason for hiding this comment

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

Yes, we should switch this to ToStringBuilder.

public static final String SERVICE_GROUP_CLUSTER_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_name";
public static final String SERVICE_GROUP_SERVICE_GROUP_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "service_group_id";
public static final String SERVICE_GROUP_SERVICE_GROUP_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "service_group_name";
public static final String SERVICE_GROUP_MPACKNAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "mpacks";
Copy link
Contributor

Choose a reason for hiding this comment

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

This is an awkward construct. Either do the string directly or use PropertyHelper.getPropertyId(...).

Copy link
Contributor

Choose a reason for hiding this comment

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

@ncole This is useful for when we document the API using Swagger annotations. The compiler does not allow using strings generated by getPropertyId() method call in annotation parameters. Using the string directly in multiple places is prone to typos. Hence this awkward construct was born.

Anyway, this question does not have much to do with this PR, as @scottduan just followed the existing usage pattern in the lines above.

Copy link
Author

Choose a reason for hiding this comment

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

I think mpack:sg is many to many relationship finally. At this time, we just have temporary restriction for 1:1, also I did not validate mpack information. This will be done in the following mpack work.

Copy link
Member

@jonathan-hurley jonathan-hurley Feb 6, 2018

Choose a reason for hiding this comment

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

I don't think it should be M2M - it should be M2O. Since upgrade workflow is based off of SGs, it doesn't make sense to have the ability to mix them at this point. It creates more complexity that will not be used.

Also, this relationship shouldn't be based on names, but on specific IDs of the mpack. There shouldn't be ambiguity about which MPack a SG is based off of.

Copy link
Contributor

Choose a reason for hiding this comment

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

@adoroszlai - it's a constant, spelling should not be an issue. You can't use constants in Swagger? That would be extremely disappointing.

Copy link
Author

Choose a reason for hiding this comment

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

@jayush , how do you think? Based on my understand, SG can pick up service from different mpacks, so this should be M2M.
@jonathan-hurley , because we do not consider version. If we use mpack id, that means we also consider mpack version. As far as I know, now we only consider mpack name, not including version.

Copy link
Member

Choose a reason for hiding this comment

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

A SG should not be able to pickup services from different mpacks - it will break a lot of upgrade flow and assumptions. Additionally, it needs to be associated with a specific mpack in order to provide a way of querying what SG's are compatible with given mpack.

Copy link
Author

Choose a reason for hiding this comment

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

mpack provides with service dependence list. So when SG picks up service, theoratically it can choose proper service with the right version (it should be a range). There has a mpack design doc, https://docs.google.com/document/d/13y2T_uN8_nrMsNRuqXLnQAm64Edie0k8_WVNOFvKq0U/edit#heading=h.ykmhjj9wbfa8
We may need to schedule a meeting to clarify how to implement mpack feature in HDP3.

Copy link
Contributor

Choose a reason for hiding this comment

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

@ncole It's a limitation of annotation "element value" in Java, not specific to Swagger. The value must be a constant expression, not just any runtime constant.

serviceGroupNames.get(clusterName).add(serviceGroupName);

if (request.getMpackNames().size() != 1) {
String errmsg = "Invalid arguments, " + request.getMpackNames().size() + " mpack(s) found in the service group " + serviceGroupName + ", only one mpack is allowed";
Copy link
Contributor

Choose a reason for hiding this comment

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

Use String.format() here.

Copy link
Author

Choose a reason for hiding this comment

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

It seems that concatenation has better performance than string.format().

Copy link
Contributor

@ncole ncole Feb 6, 2018

Choose a reason for hiding this comment

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

For messages like this, we're more interested in readability in code than performance. We've been using String.format() in more and more places to be a bit more consistent with logging syntax (even if they are not identical).

Copy link
Author

Choose a reason for hiding this comment

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

Ok, I will update it.

Copy link
Author

Choose a reason for hiding this comment

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

Should I use StringBuilder instead? I saw your another comment mentioned it.

@OneToMany(mappedBy="serviceGroupDependency")
private List<ServiceGroupDependencyEntity> dependencies;

@ElementCollection()
Copy link
Contributor

Choose a reason for hiding this comment

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

Formatting

Copy link
Author

Choose a reason for hiding this comment

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

Can you explain a little more there? Format what? Thanks.

Copy link
Contributor

Choose a reason for hiding this comment

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

I may have meant the next lines down - seems like a lot of whitespace.

Copy link
Author

Choose a reason for hiding this comment

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

I will remove all those whitespace, and put them on the same line.

…nto AMBARI-22878-branch-feature-AMBARI-14714
@asfgit
Copy link

asfgit commented Feb 9, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/501/
Test FAILed.
Test FAILured.

@scottduan
Copy link
Author

Just pushed a new patch. The manual test:

POST http://c6801.ambari.apache.org:8080/api/v1/clusters/c1/servicegroups
[
{
"ServiceGroupInfo": {
"service_group_name": "CORE2",
"stack_id": "HDP-1.2.3"
}
},
{
"ServiceGroupInfo": {
"service_group_name": "EDW-MKTG",
"stack_id": "EWD-1.1.1"
}
}
]

Response:
{
"resources" : [
{
"href" : "http://c6801.ambari.apache.org:8080/api/v1/clusters/c1/servicegroups/CORE2",
"ServiceGroupInfo" : {
"cluster_id" : 102,
"cluster_name" : "c1",
"service_group_id" : 54,
"service_group_name" : "CORE2",
"stack_id" : "HDP-1.2.3"
}
},
{
"href" : "http://c6801.ambari.apache.org:8080/api/v1/clusters/c1/servicegroups/EDW-MKTG",
"ServiceGroupInfo" : {
"cluster_id" : 102,
"cluster_name" : "c1",
"service_group_id" : 53,
"service_group_name" : "EDW-MKTG",
"stack_id" : "EWD-1.1.1"
}
}
]
}

For GET http://c6801.ambari.apache.org:8080/api/v1/clusters/c1/servicegroups

{
"href" : "http://c6801.ambari.apache.org:8080/api/v1/clusters/c1/servicegroups",
"items" : [
{
"href" : "http://c6801.ambari.apache.org:8080/api/v1/clusters/c1/servicegroups/EDW-MKTG",
"ServiceGroupInfo" : {
"cluster_name" : "c1",
"service_group_name" : "EDW-MKTG",
"stack_id" : "EWD-1.1.1"
}
},
{
"href" : "http://c6801.ambari.apache.org:8080/api/v1/clusters/c1/servicegroups/CORE2",
"ServiceGroupInfo" : {
"cluster_name" : "c1",
"service_group_name" : "CORE2",
"stack_id" : "HDP-1.2.3"
}
},
{
"href" : "http://c6801.ambari.apache.org:8080/api/v1/clusters/c1/servicegroups/core",
"ServiceGroupInfo" : {
"cluster_name" : "c1",
"service_group_name" : "core",
"stack_id" : "HDP-3.0.0.0"
}
}
]
}

@scottduan
Copy link
Author

The relation between servicegroup and mpack(stack-id) is mang-to-one, each servicegroup can have only one mpack. The same mpack can be used in multiple servicegroups

@asfgit
Copy link

asfgit commented Feb 10, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/527/
Test FAILed.
Test FAILured.

@ishanbha ishanbha force-pushed the branch-feature-AMBARI-14714 branch from 6436488 to 260876c Compare February 13, 2018 00:03
@asfgit
Copy link

asfgit commented Feb 16, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/637/
Test FAILed.
Test FAILured.

stackVersion = "HDP-2.0.6";
request.setStackId(stackVersion);
LOG.info("***** Add fake stack id in order to create cluster from web UI, this code will be removed after web UI adds default stack id");
}
Copy link
Member

Choose a reason for hiding this comment

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

Why is this fake code needed? If the web client is sending down any information about mpacks, then you should be able to use that, right? If no, then just get the first mpack registered for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

Don't hardcode this. Take the value from cluster/version to make it work for single mpack install for now.


@Column(name = "stack_id", nullable = false, insertable = true, updatable = true)
private Long stackId;

Copy link
Member

Choose a reason for hiding this comment

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

I think we need to make this an entity relationship instead since it's most likely that we'll need the entity data when dealing with service groups.

Copy link
Author

Choose a reason for hiding this comment

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

this stackId is the foreign key of stack table. We can get stack entity from this key.

Copy link
Member

Choose a reason for hiding this comment

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

That is true, but this means we'd need an extra step, like this:

@Inject StackDAO stackDAO;
stackDAO.findById(ServiceGroupEntity.getStackId())

vs just
ServiceGroupEntity.getStackEntity();

I guess I'm OK leaving it, but why not change it now before consumers begin using it?


String getStackId();

void setStackId(String stackId);
Copy link
Member

Choose a reason for hiding this comment

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

Add documentation here. "StackID" can mean anything - it should be explicitly stated that a Stack ID represents a specific mpack version: MPackName-version

So, for example:
Foo-1.0.0.0-b25
Bar-3.1.0.4-b2

Copy link
Author

Choose a reason for hiding this comment

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

In ambari code, StackId is widely used as the combination of stackName-stackVersion, there has a class StackId is for this, so I do not think it is caused confusion.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why not use StackId then instead of String?

Copy link
Member

Choose a reason for hiding this comment

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

In Ambari < 3.0, the Stack ID was typically a 2-digit umbrella, like "HDP 2.6". It did not represent unique versions, like HDP 2.6.0.0-1234. We're changing this now so that Stack ID refers to the unique, fully-qualified version. I guess that's why it's a bit confusing to me.

Copy link
Member

@jonathan-hurley jonathan-hurley left a comment

Choose a reason for hiding this comment

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

I think the term StackId is getting overloaded and is becoming quite confusing.

A stackId is a foreign key reference to a specific entry in the stack table. Each entry in the stack table also has a foreign key to a unique mpack. We need to make this a non-NULL key as well.

Whatever we call the combination of stack name and stack version, it shouldn't be stackId, since that indicates something else.

private String stackId; // Associated stack version info

public ServiceGroupRequest(String clusterName, String serviceGroupName) {
public ServiceGroupRequest(String clusterName, String serviceGroupName, String stackId) {
Copy link
Member

Choose a reason for hiding this comment

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

I think using the term "stackId" is a bit confusing here - it should be differentiated from the "stackId" foreign key value. In this case, it's actually the Mpack Name and specific MPack version (with build number), right?

@scottduan
Copy link
Author

@jonathan-hurley @jayush I need to clarify what information should be saved in servicegroups? If api only passes in version which is stackName+stackVersion, backend can get stackId by querfying stack table with stackname and stackversion, so servicegroup table can save stack_id(real stack id), the mpack info can also get from quarified stack entity, so I do not think it is necessary to save mpack info in servicegroup. If that is ok, I will keep my current change in servicegroups table schema. The only change is to use "version" to replace "stackId" to avoid confustion. Also this is for 3.0+, not for 2.7-.

@jonathan-hurley
Copy link
Member

At the end of the day, the service group must have a direct, foreign key relationship to an entry in the stack table. The stack table, in turn, has a direct foreign key relationship to a single mpack. So, one can do this:

ServiceGroupEntity.getStackEntity().getMpackEntity()

As long as this is satisfied, then we're good. We don't want to do extra queries in the DAO by name/version since this causes a hit agains the DB instead of object cache.

As for the Ambari 3.0/2.7 ... yes, I know that this work is for 3.0, however we still need to operate on older style stacks after upgrade. The term stackId was being overloaded (in some cases it meant version, in some cases an ID, etc) ... I just wanted it to be a bit clearer, which is either documentation or some name changes.

@scottduan
Copy link
Author

The updated patch includes:

  1. Remove StackId, instead use version to represent "stackName-stackVersion" to avoid any confusion with stack_id;
  2. Follows Jonathan's suggestion, a new API in servicegroup is implemented: StackEntity getStackEntity(), so that we can get mapck info from stackEntity and from serviceGroup.

this.serviceGroupName = serviceGroupName;
// version is actually stackName-stackVersion
int idx = version.indexOf('-');
StackId stackId = new StackId(version.substring(0, idx), version.substring(idx+1));
Copy link
Member

Choose a reason for hiding this comment

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

I think there's still a little bit of disconnect - I think it would be clearer to separate out the mpack name and the mpack version into separate fields. That way, we don't need to parse dashes and things like that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, you could just use the ctor of StackId that does the parsing for you


public ServiceGroupRequest(String clusterName, String serviceGroupName) {
public ServiceGroupRequest(String clusterName, String serviceGroupName, String version) {
this.clusterName = clusterName;
Copy link
Member

Choose a reason for hiding this comment

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

I think there's still a misunderstanding here - I thought it would be cleaner to separate this out into 2 fields so that it's clear to the user what is expected: mpack name and then mpack version. You can combine this and call it a stack ID internally, that's fine - but we should take 2 different properties.

Same goes for API requests where we're currently given name-version as a string. This should be broken out into 2 fields.

Copy link
Author

Choose a reason for hiding this comment

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

I am ok for this change.

Copy link
Author

Choose a reason for hiding this comment

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

@jayush What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Lets keep it as "version" for now for legacy purposes. When we upgrade to ambari 3.0 assuming the existing cluster is on HDP-2.6 stack, calling this as mpack name and mpack version would be misleading.

We should handle this in a separate JIRA if we really want to change this convention for all APIs.

Copy link
Member

Choose a reason for hiding this comment

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

But "version" in legacy terms meant only the numeric value. If we don't want to break it out into 2 references, I think we'd rather use stackId, right?

@scottduan
Copy link
Author

@jonathan-hurley @adoroszlai @ncole I have updated the patch and could you please review it again? Thanks.

@Override
public ServiceGroup addServiceGroup(String serviceGroupName) throws AmbariException {
public ServiceGroup addServiceGroup(String serviceGroupName, String version) throws AmbariException {
if (serviceGroups.containsKey(serviceGroupName)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

addServiceGroup(serviceGroupName, stackId) already has the same check. Remove duplicate code.

Copy link
Author

Choose a reason for hiding this comment

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

I will remove the check in addServiceGroup(String serviceGroupName, String version)

* @throws AmbariException
*/
ServiceGroup addServiceGroup(String serviceGroupName) throws AmbariException;
ServiceGroup addServiceGroup(String serviceGroupName, String stackId) throws AmbariException;
Copy link
Contributor

Choose a reason for hiding this comment

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

Rename "String stackId" to "String version" in the interface.

Copy link
Author

Choose a reason for hiding this comment

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

The change is already there.

Copy link
Author

Choose a reason for hiding this comment

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

ok, changed it.


Set<ServiceGroupRequest> serviceGroupRequests = serviceGroups.stream()
.map(serviceGroupName -> new ServiceGroupRequest(clusterName, serviceGroupName))
.map(serviceGroupName -> new ServiceGroupRequest(clusterName, serviceGroupName, Iterables.getFirst(topology.getBlueprint().getStackIds(), null).getStackId()))
Copy link
Contributor

Choose a reason for hiding this comment

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

@adoroszlai do we have a follow up JIRA for this?

Copy link
Member

@jonathan-hurley jonathan-hurley left a comment

Choose a reason for hiding this comment

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

OK - this commit is far along enough where it can go in since there are Jiras which are blocked by it. However, I think we need to address the version vs stackId discussion.

My original request was to make the one value broken out into 2 - mpack name and version. Instead, we made it just "version" which I think is more confusing than StackId. If we don't want to break it out into 2 properties, can we just move it back to stackID to be consistent?

@jayush jayush merged commit d370602 into apache:branch-feature-AMBARI-14714 Feb 22, 2018
@asfgit
Copy link

asfgit commented Feb 22, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/761/
Test FAILed.
Test FAILured.

@asfgit
Copy link

asfgit commented Feb 23, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/762/
Test FAILed.
Test FAILured.

@scottduan scottduan deleted the AMBARI-22878-branch-feature-AMBARI-14714 branch March 15, 2018 05:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants