1 | package org.apache.continuum.web.action.admin; |
2 | |
3 | /* |
4 | * Licensed to the Apache Software Foundation (ASF) under one |
5 | * or more contributor license agreements. See the NOTICE file |
6 | * distributed with this work for additional information |
7 | * regarding copyright ownership. The ASF licenses this file |
8 | * to you under the Apache License, Version 2.0 (the |
9 | * "License"); you may not use this file except in compliance |
10 | * with the License. You may obtain a copy of the License at |
11 | * |
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
13 | * |
14 | * Unless required by applicable law or agreed to in writing, |
15 | * software distributed under the License is distributed on an |
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
17 | * KIND, either express or implied. See the License for the |
18 | * specific language governing permissions and limitations |
19 | * under the License. |
20 | */ |
21 | |
22 | import org.apache.commons.lang.StringEscapeUtils; |
23 | import org.apache.continuum.configuration.BuildAgentConfiguration; |
24 | import org.apache.continuum.configuration.BuildAgentGroupConfiguration; |
25 | import org.apache.continuum.web.util.AuditLog; |
26 | import org.apache.continuum.web.util.AuditLogConstants; |
27 | import org.apache.maven.continuum.ContinuumException; |
28 | import org.apache.maven.continuum.configuration.ConfigurationService; |
29 | import org.apache.maven.continuum.model.system.Installation; |
30 | import org.apache.maven.continuum.model.system.Profile; |
31 | import org.apache.maven.continuum.security.ContinuumRoleConstants; |
32 | import org.apache.maven.continuum.web.action.ContinuumConfirmAction; |
33 | import org.apache.struts2.ServletActionContext; |
34 | import org.codehaus.plexus.redback.rbac.Resource; |
35 | import org.codehaus.plexus.util.StringUtils; |
36 | import org.codehaus.redback.integration.interceptor.SecureAction; |
37 | import org.codehaus.redback.integration.interceptor.SecureActionBundle; |
38 | import org.codehaus.redback.integration.interceptor.SecureActionException; |
39 | import org.slf4j.Logger; |
40 | import org.slf4j.LoggerFactory; |
41 | |
42 | import java.util.ArrayList; |
43 | import java.util.Collections; |
44 | import java.util.List; |
45 | |
46 | /** |
47 | * @author Maria Catherine Tan |
48 | * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="buildAgent" |
49 | */ |
50 | public class BuildAgentAction |
51 | extends ContinuumConfirmAction |
52 | implements SecureAction |
53 | { |
54 | private static final Logger logger = LoggerFactory.getLogger( BuildAgentAction.class ); |
55 | |
56 | private List<BuildAgentConfiguration> buildAgents; |
57 | |
58 | private BuildAgentConfiguration buildAgent; |
59 | |
60 | private BuildAgentGroupConfiguration buildAgentGroup; |
61 | |
62 | private List<BuildAgentGroupConfiguration> buildAgentGroups; |
63 | |
64 | private List<BuildAgentConfiguration> selectedbuildAgents; |
65 | |
66 | private List<String> selectedBuildAgentIds; |
67 | |
68 | private List<Installation> installations; |
69 | |
70 | private boolean confirmed; |
71 | |
72 | private String message; |
73 | |
74 | private String type; |
75 | |
76 | private String typeGroup; |
77 | |
78 | public void prepare() |
79 | throws Exception |
80 | { |
81 | super.prepare(); |
82 | this.setBuildAgents( getContinuum().getConfiguration().getBuildAgents() ); |
83 | } |
84 | |
85 | public String input() |
86 | throws Exception |
87 | { |
88 | if ( buildAgent != null && !StringUtils.isBlank( buildAgent.getUrl() ) ) |
89 | { |
90 | String escapedBuildAgentUrl = StringEscapeUtils.escapeXml( buildAgent.getUrl() ); |
91 | buildAgent.setUrl( escapedBuildAgentUrl ); |
92 | |
93 | List<BuildAgentConfiguration> agents = getContinuum().getConfiguration().getBuildAgents(); |
94 | |
95 | for ( BuildAgentConfiguration agent : agents ) |
96 | { |
97 | if ( agent.getUrl().equals( escapedBuildAgentUrl ) ) |
98 | { |
99 | buildAgent = agent; |
100 | type = "edit"; |
101 | } |
102 | } |
103 | } |
104 | else |
105 | { |
106 | type = "new"; |
107 | } |
108 | |
109 | return INPUT; |
110 | } |
111 | |
112 | public String list() |
113 | throws Exception |
114 | { |
115 | String errorMessage = ServletActionContext.getRequest().getParameter( "errorMessage" ); |
116 | |
117 | if ( errorMessage != null ) |
118 | { |
119 | addActionError( errorMessage ); |
120 | } |
121 | |
122 | this.buildAgents = getContinuum().getConfiguration().getBuildAgents(); |
123 | this.buildAgentGroups = getContinuum().getConfiguration().getBuildAgentGroups(); |
124 | |
125 | return SUCCESS; |
126 | } |
127 | |
128 | public String view() |
129 | throws Exception |
130 | { |
131 | ConfigurationService configuration = getContinuum().getConfiguration(); |
132 | |
133 | if ( buildAgent != null ) |
134 | { |
135 | String escapedBuildAgentUrl = StringEscapeUtils.escapeXml( buildAgent.getUrl() ); |
136 | buildAgent.setUrl( escapedBuildAgentUrl ); |
137 | |
138 | for ( BuildAgentConfiguration agent : configuration.getBuildAgents() ) |
139 | { |
140 | if ( agent.getUrl().equals( escapedBuildAgentUrl ) ) |
141 | { |
142 | buildAgent = agent; |
143 | |
144 | try |
145 | { |
146 | installations = getContinuum().getDistributedBuildManager().getAvailableInstallations( escapedBuildAgentUrl ); |
147 | } |
148 | catch ( ContinuumException e ) |
149 | { |
150 | logger.error( "Unable to retrieve installations of build agent '" + agent.getUrl() + "'", e ); |
151 | } |
152 | |
153 | break; |
154 | } |
155 | } |
156 | } |
157 | |
158 | return SUCCESS; |
159 | } |
160 | |
161 | public String save() |
162 | throws Exception |
163 | { |
164 | boolean found = false; |
165 | |
166 | ConfigurationService configuration = getContinuum().getConfiguration(); |
167 | |
168 | // escape xml to prevent xss attacks |
169 | buildAgent.setDescription( StringEscapeUtils.escapeXml( StringEscapeUtils.unescapeXml( buildAgent.getDescription() ) ) ); |
170 | |
171 | if ( configuration.getBuildAgents() != null ) |
172 | { |
173 | for ( BuildAgentConfiguration agent : configuration.getBuildAgents() ) |
174 | { |
175 | if ( agent.getUrl().equals( buildAgent.getUrl() ) ) |
176 | { |
177 | agent.setDescription( buildAgent.getDescription() ); |
178 | agent.setEnabled( buildAgent.isEnabled() ); |
179 | |
180 | configuration.updateBuildAgent( agent ); |
181 | configuration.store(); |
182 | found = true; |
183 | } |
184 | } |
185 | } |
186 | |
187 | AuditLog event = new AuditLog( "Build Agent URL=" + buildAgent.getUrl(), AuditLogConstants.MODIFY_BUILD_AGENT ); |
188 | event.setCategory( AuditLogConstants.BUILD_AGENT ); |
189 | event.setCurrentUser( getPrincipal() ); |
190 | |
191 | if ( !found ) |
192 | { |
193 | configuration.addBuildAgent( buildAgent ); |
194 | configuration.store(); |
195 | event.setAction( AuditLogConstants.ADD_BUILD_AGENT ); |
196 | } |
197 | else |
198 | { |
199 | if ( type.equals( "new" ) ) |
200 | { |
201 | addActionError( getResourceBundle().getString( "buildAgent.error.duplicate" ) ); |
202 | return INPUT; |
203 | } |
204 | } |
205 | |
206 | getContinuum().getDistributedBuildManager().reload(); |
207 | event.log(); |
208 | |
209 | return SUCCESS; |
210 | } |
211 | |
212 | public String delete() |
213 | throws Exception |
214 | { |
215 | buildAgent.setUrl( StringEscapeUtils.escapeXml( StringEscapeUtils.unescapeXml( buildAgent.getUrl() ) ) ); |
216 | |
217 | if ( !confirmed ) |
218 | { |
219 | return CONFIRM; |
220 | } |
221 | |
222 | if ( getContinuum().getDistributedBuildManager().isBuildAgentBusy( buildAgent.getUrl() ) ) |
223 | { |
224 | message = getText( "buildAgent.error.delete.busy" ); |
225 | return ERROR; |
226 | } |
227 | |
228 | ConfigurationService configuration = getContinuum().getConfiguration(); |
229 | |
230 | if ( configuration.getBuildAgentGroups() != null ) |
231 | { |
232 | for ( BuildAgentGroupConfiguration buildAgentGroup : configuration.getBuildAgentGroups() ) |
233 | { |
234 | if ( configuration.containsBuildAgentUrl( buildAgent.getUrl(), buildAgentGroup ) ) |
235 | { |
236 | message = getText( "buildAgent.error.remove.in.use" ); |
237 | return ERROR; |
238 | } |
239 | } |
240 | } |
241 | |
242 | if ( configuration.getBuildAgents() != null ) |
243 | { |
244 | for ( BuildAgentConfiguration agent : configuration.getBuildAgents() ) |
245 | { |
246 | if ( buildAgent.getUrl().equals( agent.getUrl() ) ) |
247 | { |
248 | getContinuum().getDistributedBuildManager().removeDistributedBuildQueueOfAgent( buildAgent.getUrl() ); |
249 | configuration.removeBuildAgent( agent ); |
250 | configuration.store(); |
251 | |
252 | AuditLog event = new AuditLog( "Build Agent URL=" + agent.getUrl(), AuditLogConstants.REMOVE_BUILD_AGENT ); |
253 | event.setCategory( AuditLogConstants.BUILD_AGENT ); |
254 | event.setCurrentUser( getPrincipal() ); |
255 | event.log(); |
256 | |
257 | getContinuum().getDistributedBuildManager().reload(); |
258 | |
259 | return SUCCESS; |
260 | } |
261 | } |
262 | } |
263 | |
264 | message = getText( "buildAgent.error.notfound" ); |
265 | return ERROR; |
266 | } |
267 | |
268 | public String deleteGroup() |
269 | throws Exception |
270 | { |
271 | buildAgentGroup.setName( StringEscapeUtils.escapeXml( buildAgentGroup.getName() ) ); |
272 | |
273 | if ( !confirmed ) |
274 | { |
275 | return CONFIRM; |
276 | } |
277 | |
278 | List<Profile> profiles = getContinuum().getProfileService().getAllProfiles(); |
279 | for ( Profile profile : profiles ) |
280 | { |
281 | if ( buildAgentGroup.getName().equals( profile.getBuildAgentGroup() ) ) |
282 | { |
283 | message = getText( "buildAgentGroup.error.remove.in.use" ); |
284 | return ERROR; |
285 | } |
286 | } |
287 | |
288 | ConfigurationService configuration = getContinuum().getConfiguration(); |
289 | |
290 | for ( BuildAgentGroupConfiguration group : configuration.getBuildAgentGroups() ) |
291 | { |
292 | if ( buildAgentGroup.getName().equals( group.getName() ) ) |
293 | { |
294 | configuration.removeBuildAgentGroup( group ); |
295 | |
296 | AuditLog event = new AuditLog( "Build Agent Group=" + group.getName(), AuditLogConstants.REMOVE_BUILD_AGENT_GROUP ); |
297 | event.setCategory( AuditLogConstants.BUILD_AGENT ); |
298 | event.setCurrentUser( getPrincipal() ); |
299 | event.log(); |
300 | |
301 | return SUCCESS; |
302 | } |
303 | } |
304 | |
305 | message = getText( "buildAgentGroup.error.doesnotexist" ); |
306 | return ERROR; |
307 | } |
308 | |
309 | public String saveGroup() |
310 | throws Exception |
311 | { |
312 | boolean found = false; |
313 | |
314 | ConfigurationService configuration = getContinuum().getConfiguration(); |
315 | selectedbuildAgents = getBuildAgentsFromSelectedBuildAgents(); |
316 | |
317 | if ( buildAgentGroup.getName() != null ) |
318 | { |
319 | if ( buildAgentGroup.getName().equals( "" ) ) |
320 | { |
321 | addActionError( getResourceBundle().getString( "buildAgentGroup.error.name.required" ) ); |
322 | return INPUT; |
323 | } |
324 | else if ( buildAgentGroup.getName().trim().equals( "" ) ) |
325 | { |
326 | addActionError( getText( "buildAgentGroup.error.name.cannot.be.spaces" ) ); |
327 | return INPUT; |
328 | } |
329 | } |
330 | |
331 | if ( configuration.getBuildAgentGroups() != null ) |
332 | { |
333 | for ( BuildAgentGroupConfiguration group : configuration.getBuildAgentGroups() ) |
334 | { |
335 | if ( buildAgentGroup.getName().equals( group.getName() ) ) |
336 | { |
337 | group.setName( buildAgentGroup.getName() ); |
338 | configuration.updateBuildAgentGroup( group ); |
339 | found = true; |
340 | break; |
341 | } |
342 | } |
343 | } |
344 | |
345 | AuditLog event = new AuditLog( "Build Agent Group=" + buildAgentGroup.getName(), AuditLogConstants.MODIFY_BUILD_AGENT_GROUP ); |
346 | event.setCategory( AuditLogConstants.BUILD_AGENT ); |
347 | event.setCurrentUser( getPrincipal() ); |
348 | |
349 | if ( !found ) |
350 | { |
351 | buildAgentGroup.setBuildAgents( selectedbuildAgents ); |
352 | configuration.addBuildAgentGroup( buildAgentGroup ); |
353 | event.setAction( AuditLogConstants.ADD_BUILD_AGENT_GROUP ); |
354 | } |
355 | else |
356 | // found |
357 | { |
358 | if ( typeGroup.equals( "new" ) ) |
359 | { |
360 | addActionError( getResourceBundle().getString( "buildAgentGroup.error.duplicate" ) ); |
361 | return INPUT; |
362 | } |
363 | else if ( typeGroup.equals( "edit" ) ) |
364 | { |
365 | buildAgentGroup.setBuildAgents( selectedbuildAgents ); |
366 | configuration.updateBuildAgentGroup( buildAgentGroup ); |
367 | } |
368 | } |
369 | |
370 | getContinuum().getDistributedBuildManager().reload(); |
371 | event.log(); |
372 | |
373 | return SUCCESS; |
374 | } |
375 | |
376 | public String inputGroup() |
377 | throws Exception |
378 | { |
379 | ConfigurationService configuration = getContinuum().getConfiguration(); |
380 | |
381 | if ( buildAgentGroup != null && !StringUtils.isBlank( buildAgentGroup.getName() ) ) |
382 | { |
383 | String escapedBuildAgentGroupName = StringEscapeUtils.escapeXml( buildAgentGroup.getName() ); |
384 | buildAgentGroup.setName( escapedBuildAgentGroupName ); |
385 | |
386 | List<BuildAgentGroupConfiguration> agentGroups = configuration.getBuildAgentGroups(); |
387 | |
388 | for ( BuildAgentGroupConfiguration group : agentGroups ) |
389 | { |
390 | if ( group.getName().equals( escapedBuildAgentGroupName ) ) |
391 | { |
392 | buildAgentGroup = group; |
393 | typeGroup = "edit"; |
394 | |
395 | this.buildAgentGroup = configuration.getBuildAgentGroup( escapedBuildAgentGroupName ); |
396 | this.buildAgents = configuration.getBuildAgents(); |
397 | |
398 | this.selectedBuildAgentIds = new ArrayList<String>(); |
399 | if ( this.buildAgentGroup.getBuildAgents() != null ) |
400 | { |
401 | for ( BuildAgentConfiguration buildAgentConfiguration : buildAgentGroup.getBuildAgents() ) |
402 | { |
403 | this.selectedBuildAgentIds.add( buildAgentConfiguration.getUrl() ); |
404 | } |
405 | |
406 | } |
407 | |
408 | List<BuildAgentConfiguration> unusedBuildAgents = new ArrayList<BuildAgentConfiguration>(); |
409 | |
410 | for ( BuildAgentConfiguration agent : getBuildAgents() ) |
411 | { |
412 | if ( !this.selectedBuildAgentIds.contains( agent.getUrl() ) ) |
413 | { |
414 | unusedBuildAgents.add( agent ); |
415 | } |
416 | } |
417 | this.setBuildAgents( unusedBuildAgents ); |
418 | |
419 | break; |
420 | } |
421 | } |
422 | } |
423 | else |
424 | { |
425 | typeGroup = "new"; |
426 | } |
427 | return INPUT; |
428 | } |
429 | |
430 | public SecureActionBundle getSecureActionBundle() |
431 | throws SecureActionException |
432 | { |
433 | SecureActionBundle bundle = new SecureActionBundle(); |
434 | bundle.setRequiresAuthentication( true ); |
435 | bundle.addRequiredAuthorization( ContinuumRoleConstants.CONTINUUM_MANAGE_DISTRIBUTED_BUILDS, Resource.GLOBAL ); |
436 | |
437 | return bundle; |
438 | } |
439 | |
440 | private List<BuildAgentConfiguration> getBuildAgentsFromSelectedBuildAgents() |
441 | { |
442 | if ( this.selectedBuildAgentIds == null ) |
443 | { |
444 | return Collections.EMPTY_LIST; |
445 | } |
446 | |
447 | List<BuildAgentConfiguration> selectedbuildAgents = new ArrayList<BuildAgentConfiguration>(); |
448 | for ( String ids : selectedBuildAgentIds ) |
449 | { |
450 | BuildAgentConfiguration buildAgent = getContinuum().getConfiguration().getBuildAgent( ids ); |
451 | if ( buildAgent != null ) |
452 | { |
453 | selectedbuildAgents.add( buildAgent ); |
454 | } |
455 | } |
456 | return selectedbuildAgents; |
457 | } |
458 | |
459 | public List<BuildAgentConfiguration> getBuildAgents() |
460 | { |
461 | return buildAgents; |
462 | } |
463 | |
464 | public void setBuildAgents( List<BuildAgentConfiguration> buildAgents ) |
465 | { |
466 | this.buildAgents = buildAgents; |
467 | } |
468 | |
469 | public BuildAgentConfiguration getBuildAgent() |
470 | { |
471 | return buildAgent; |
472 | } |
473 | |
474 | public void setBuildAgent( BuildAgentConfiguration buildAgent ) |
475 | { |
476 | this.buildAgent = buildAgent; |
477 | } |
478 | |
479 | public List<Installation> getInstallations() |
480 | { |
481 | return installations; |
482 | } |
483 | |
484 | public void setInstallations( List<Installation> installations ) |
485 | { |
486 | this.installations = installations; |
487 | } |
488 | |
489 | public boolean isConfirmed() |
490 | { |
491 | return confirmed; |
492 | } |
493 | |
494 | public void setConfirmed( boolean confirmed ) |
495 | { |
496 | this.confirmed = confirmed; |
497 | } |
498 | |
499 | public String getMessage() |
500 | { |
501 | return this.message; |
502 | } |
503 | |
504 | public void setMessage( String message ) |
505 | { |
506 | this.message = message; |
507 | } |
508 | |
509 | public String getType() |
510 | { |
511 | return type; |
512 | } |
513 | |
514 | public void setType( String type ) |
515 | { |
516 | this.type = type; |
517 | } |
518 | |
519 | public List<BuildAgentGroupConfiguration> getBuildAgentGroups() |
520 | { |
521 | return buildAgentGroups; |
522 | } |
523 | |
524 | public void setBuildAgentGroups( List<BuildAgentGroupConfiguration> buildAgentGroups ) |
525 | { |
526 | this.buildAgentGroups = buildAgentGroups; |
527 | } |
528 | |
529 | public BuildAgentGroupConfiguration getBuildAgentGroup() |
530 | { |
531 | return buildAgentGroup; |
532 | } |
533 | |
534 | public void setBuildAgentGroup( BuildAgentGroupConfiguration buildAgentGroup ) |
535 | { |
536 | this.buildAgentGroup = buildAgentGroup; |
537 | } |
538 | |
539 | public String getTypeGroup() |
540 | { |
541 | return typeGroup; |
542 | } |
543 | |
544 | public void setTypeGroup( String typeGroup ) |
545 | { |
546 | this.typeGroup = typeGroup; |
547 | } |
548 | |
549 | public List<BuildAgentConfiguration> getSelectedbuildAgents() |
550 | { |
551 | return selectedbuildAgents; |
552 | } |
553 | |
554 | public void setSelectedbuildAgents( List<BuildAgentConfiguration> selectedbuildAgents ) |
555 | { |
556 | this.selectedbuildAgents = selectedbuildAgents; |
557 | } |
558 | |
559 | public List<String> getSelectedBuildAgentIds() |
560 | { |
561 | return selectedBuildAgentIds == null ? Collections.EMPTY_LIST : selectedBuildAgentIds; |
562 | } |
563 | |
564 | public void setSelectedBuildAgentIds( List<String> selectedBuildAgentIds ) |
565 | { |
566 | this.selectedBuildAgentIds = selectedBuildAgentIds; |
567 | } |
568 | } |