Skip to content

Commit fb24522

Browse files
ketanvarshavaradarajan
authored andcommitted
Add API to perform CRUD operations on elastic profiles (#2688)
1 parent dd99f2f commit fb24522

File tree

39 files changed

+1582
-34
lines changed

39 files changed

+1582
-34
lines changed

common/src/com/thoughtworks/go/domain/JobConfigIdentifier.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
/*************************GO-LICENSE-START*********************************
2-
* Copyright 2014 ThoughtWorks, Inc.
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
15-
*************************GO-LICENSE-END***********************************/
15+
*/
1616

1717
package com.thoughtworks.go.domain;
1818

19+
import com.thoughtworks.go.config.CaseInsensitiveString;
20+
1921
public class JobConfigIdentifier {
2022
private final String pipelineName;
2123
private final String stageName;
@@ -27,6 +29,10 @@ public JobConfigIdentifier(String pipelineName, String stageName, String jobName
2729
this.jobName = jobName;
2830
}
2931

32+
public JobConfigIdentifier(CaseInsensitiveString pipelineName, CaseInsensitiveString stageName, CaseInsensitiveString jobName) {
33+
this(pipelineName.toString(), stageName.toString(), jobName.toString());
34+
}
35+
3036
public boolean equals(Object o) {
3137
if (this == o) {
3238
return true;

config/config-api/src/com/thoughtworks/go/config/BasicCruiseConfig.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -1258,7 +1258,7 @@ public void copyErrorsTo(CruiseConfig to) {
12581258
copyErrors(this, to);
12591259
}
12601260

1261-
public static void copyErrors(Object from, Object to) {
1261+
public static <T> void copyErrors(T from, T to) {
12621262
GoConfigParallelGraphWalker walker = new GoConfigParallelGraphWalker(from, to);
12631263
walker.walk(new GoConfigParallelGraphWalker.Handler() {
12641264
public void handle(Validatable rawObject, Validatable objectWithErrors) {

config/config-api/src/com/thoughtworks/go/config/PipelineConfig.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -252,7 +252,7 @@ public List<ConfigErrors> getAllErrors() {
252252
return ErrorCollector.getAllErrors(this);
253253
}
254254

255-
public List<StageConfig> getStages() {
255+
public PipelineConfig getStages() {
256256
return this;
257257
}
258258

config/config-api/src/com/thoughtworks/go/config/elastic/ElasticProfile.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package com.thoughtworks.go.config.elastic;
1818

1919
import com.thoughtworks.go.config.*;
20+
import com.thoughtworks.go.config.builder.ConfigurationPropertyBuilder;
21+
import com.thoughtworks.go.config.validation.NameTypeValidator;
2022
import com.thoughtworks.go.domain.ConfigErrors;
2123
import com.thoughtworks.go.domain.config.Configuration;
2224
import com.thoughtworks.go.domain.config.ConfigurationProperty;
@@ -95,6 +97,20 @@ public void validate(ValidationContext validationContext) {
9597
if (isBlank(pluginId)) {
9698
addError(PLUGIN_ID, "Elastic profile cannot have a blank plugin id.");
9799
}
100+
101+
if (new NameTypeValidator().isNameInvalid(id)) {
102+
addError(ID, String.format("Invalid id '%s'. %s", id, NameTypeValidator.ERROR_MESSAGE));
103+
}
104+
}
105+
106+
public void addConfigurations(List<ConfigurationProperty> configurations) {
107+
ConfigurationPropertyBuilder builder = new ConfigurationPropertyBuilder();
108+
for (ConfigurationProperty property : configurations) {
109+
add(builder.create(property.getConfigKeyName(),
110+
property.getConfigValue(),
111+
null,
112+
false));
113+
}
98114
}
99115

100116
@Override

config/config-api/test/com/thoughtworks/go/config/builder/ConfigurationPropertyBuilderTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public void shouldCreatePropertyInAbsenceOfPlainAndEncryptedTextInputForSecurePr
4141

4242
ConfigurationProperty property = new ConfigurationPropertyBuilder().create("key", null, null, true);
4343

44+
assertThat(property.errors().size(), is(0));
4445
assertThat(property.getConfigKeyName(), is("key"));
4546
assertNull(property.getEncryptedConfigurationValue());
4647
assertNull(property.getConfigurationValue());

config/config-api/test/com/thoughtworks/go/config/elastic/ElasticProfileTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ public void shouldNotAllowNullPluginIdOrProfileId() throws Exception {
3535
assertThat(profile.errors().on(ElasticProfile.ID), is("Elastic profile cannot have a blank id."));
3636
}
3737

38+
@Test
39+
public void shouldValidateElasticPluginIdPattern() throws Exception {
40+
ElasticProfile profile = new ElasticProfile("!123", "docker");
41+
profile.validate(null);
42+
assertThat(profile.errors().size(), is(1));
43+
assertThat(profile.errors().on(ElasticProfile.ID), is("Invalid id '!123'. This must be alphanumeric and can contain underscores and periods (however, it cannot start with a period). The maximum allowed length is 255 characters."));
44+
}
45+
3846
@Test
3947
public void shouldValidateConfigPropertyNameUniqueness() throws Exception {
4048
ConfigurationProperty prop1 = ConfigurationPropertyMother.create("USERNAME");
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.thoughtworks.go.config.update;
18+
19+
import com.thoughtworks.go.config.BasicCruiseConfig;
20+
import com.thoughtworks.go.config.CruiseConfig;
21+
import com.thoughtworks.go.config.commands.EntityConfigUpdateCommand;
22+
import com.thoughtworks.go.config.elastic.ElasticProfile;
23+
import com.thoughtworks.go.config.elastic.ElasticProfiles;
24+
import com.thoughtworks.go.i18n.LocalizedMessage;
25+
import com.thoughtworks.go.server.domain.Username;
26+
import com.thoughtworks.go.server.service.GoConfigService;
27+
import com.thoughtworks.go.server.service.result.LocalizedOperationResult;
28+
import com.thoughtworks.go.serverhealth.HealthStateType;
29+
30+
abstract class ElasticAgentProfileCommand implements EntityConfigUpdateCommand<ElasticProfile> {
31+
32+
protected ElasticProfile preprocessedElasticProfile;
33+
protected final ElasticProfile elasticProfile;
34+
protected final GoConfigService goConfigService;
35+
protected final Username currentUser;
36+
protected final LocalizedOperationResult result;
37+
38+
public ElasticAgentProfileCommand(ElasticProfile elasticProfile, GoConfigService goConfigService, Username currentUser, LocalizedOperationResult result) {
39+
this.elasticProfile = elasticProfile;
40+
this.goConfigService = goConfigService;
41+
this.currentUser = currentUser;
42+
this.result = result;
43+
}
44+
45+
@Override
46+
public void clearErrors() {
47+
BasicCruiseConfig.clearErrors(elasticProfile);
48+
}
49+
50+
@Override
51+
public ElasticProfile getPreprocessedEntityConfig() {
52+
return preprocessedElasticProfile;
53+
}
54+
55+
@Override
56+
public boolean canContinue(CruiseConfig cruiseConfig) {
57+
return isAuthorized();
58+
}
59+
60+
@Override
61+
public boolean isValid(CruiseConfig preprocessedConfig) {
62+
preprocessedElasticProfile = findExistingProfile(preprocessedConfig);
63+
preprocessedElasticProfile.validate(null);
64+
65+
if (preprocessedElasticProfile.errors().isEmpty()) {
66+
ElasticProfiles profiles = preprocessedConfig.server().getElasticConfig().getProfiles();
67+
profiles.validate(null);
68+
BasicCruiseConfig.copyErrors(preprocessedElasticProfile, elasticProfile);
69+
return preprocessedElasticProfile.getAllErrors().isEmpty() && elasticProfile.errors().isEmpty();
70+
}
71+
72+
BasicCruiseConfig.copyErrors(preprocessedElasticProfile, elasticProfile);
73+
return false;
74+
}
75+
76+
protected boolean isAuthorized() {
77+
if (!(goConfigService.isUserAdmin(currentUser) || goConfigService.isGroupAdministrator(currentUser.getUsername()))) {
78+
result.unauthorized(LocalizedMessage.string("UNAUTHORIZED_TO_EDIT"), HealthStateType.unauthorised());
79+
return false;
80+
}
81+
return true;
82+
}
83+
84+
protected ElasticProfile findExistingProfile(CruiseConfig cruiseConfig) {
85+
return cruiseConfig.server().getElasticConfig().getProfiles().find(elasticProfile.getId());
86+
}
87+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.thoughtworks.go.config.update;
18+
19+
import com.thoughtworks.go.config.CruiseConfig;
20+
import com.thoughtworks.go.config.elastic.ElasticProfile;
21+
import com.thoughtworks.go.server.domain.Username;
22+
import com.thoughtworks.go.server.service.GoConfigService;
23+
import com.thoughtworks.go.server.service.result.LocalizedOperationResult;
24+
25+
public class ElasticAgentProfileCreateCommand extends ElasticAgentProfileCommand {
26+
public ElasticAgentProfileCreateCommand(ElasticProfile elasticProfile, GoConfigService goConfigService, Username currentUser, LocalizedOperationResult result) {
27+
super(elasticProfile, goConfigService, currentUser, result);
28+
}
29+
30+
@Override
31+
public void update(CruiseConfig preprocessedConfig) throws Exception {
32+
preprocessedConfig.server().getElasticConfig().getProfiles().add(elasticProfile);
33+
}
34+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.thoughtworks.go.config.update;
18+
19+
import com.thoughtworks.go.config.*;
20+
import com.thoughtworks.go.config.elastic.ElasticProfile;
21+
import com.thoughtworks.go.config.exceptions.GoConfigInvalidException;
22+
import com.thoughtworks.go.domain.JobConfigIdentifier;
23+
import com.thoughtworks.go.i18n.LocalizedMessage;
24+
import com.thoughtworks.go.server.domain.Username;
25+
import com.thoughtworks.go.server.service.ElasticProfileNotFoundException;
26+
import com.thoughtworks.go.server.service.GoConfigService;
27+
import com.thoughtworks.go.server.service.result.LocalizedOperationResult;
28+
29+
import java.util.ArrayList;
30+
import java.util.List;
31+
32+
public class ElasticAgentProfileDeleteCommand extends ElasticAgentProfileCommand {
33+
34+
public ElasticAgentProfileDeleteCommand(ElasticProfile elasticProfile, GoConfigService goConfigService, Username currentUser, LocalizedOperationResult result) {
35+
super(elasticProfile, goConfigService, currentUser, result);
36+
}
37+
38+
@Override
39+
public void update(CruiseConfig preprocessedConfig) throws Exception {
40+
ElasticProfile existingProfile = findExistingProfile(preprocessedConfig);
41+
42+
if (existingProfile == null) {
43+
throw new ElasticProfileNotFoundException();
44+
}
45+
46+
preprocessedConfig.server().getElasticConfig().getProfiles().remove(existingProfile);
47+
}
48+
49+
@Override
50+
public boolean isValid(CruiseConfig preprocessedConfig) {
51+
List<PipelineConfig> allPipelineConfigs = preprocessedConfig.getAllPipelineConfigs();
52+
53+
List<JobConfigIdentifier> usedByPipelines = new ArrayList<>();
54+
55+
for (PipelineConfig pipelineConfig : allPipelineConfigs) {
56+
populateDups(usedByPipelines, pipelineConfig);
57+
}
58+
59+
if (!usedByPipelines.isEmpty()) {
60+
result.unprocessableEntity(LocalizedMessage.string("CANNOT_DELETE_ELASTIC_AGENT_PROFILE", elasticProfile.getId(), usedByPipelines));
61+
throw new GoConfigInvalidException(preprocessedConfig, String.format("The elastic agent profile '%s' is being referenced by pipeline(s): %s.", elasticProfile.getId(), usedByPipelines));
62+
}
63+
return true;
64+
}
65+
66+
private void populateDups(List<JobConfigIdentifier> usedByPipelines, PipelineConfig pipelineConfig) {
67+
for (StageConfig stage : pipelineConfig) {
68+
JobConfigs jobs = stage.getJobs();
69+
for (JobConfig job : jobs) {
70+
String id = elasticProfile.getId();
71+
if (id.equals(job.getElasticProfileId())) {
72+
usedByPipelines.add(new JobConfigIdentifier(pipelineConfig.name(), stage.name(), job.name()));
73+
}
74+
}
75+
}
76+
}
77+
78+
}

0 commit comments

Comments
 (0)