Skip to content

Commit

Permalink
Add system selection to one-shot action execution
Browse files Browse the repository at this point in the history
Signed-off-by: Pascal Arlt <[email protected]>
  • Loading branch information
parlt91 committed Jan 24, 2024
1 parent 73eaa88 commit 0be4803
Show file tree
Hide file tree
Showing 10 changed files with 295 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import com.suse.manager.utils.PagedSqlQueryBuilder;
import com.suse.manager.webui.utils.gson.RecurringActionScheduleJson;
import com.suse.manager.webui.utils.gson.SimpleMinionJson;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -156,6 +157,42 @@ public static DataResult<RecurringActionScheduleJson> listAllRecurringActions(
.run(params, pc, parser, RecurringActionScheduleJson.class);
}

/**
* List all members of a given server group
*
* @param id the server group id
* @param pc the page control
* @param parser the parser for filters when building query
* @return the list of {@link SimpleMinionJson}s
*/
public static DataResult<SimpleMinionJson> listGroupMembers(Long id, PageControl pc, Function<Optional<PageControl>,
PagedSqlQueryBuilder.FilterWithValue> parser) {
Map<String, Object> params = Map.of("id", id);
return new PagedSqlQueryBuilder("s.id")
.select("s.id, s.name")
.from("rhnServer s join rhnServerGroupMembers sgm on s.id = sgm.server_id")
.where("sgm.server_group_id = :id")
.run(params, pc, parser, SimpleMinionJson.class);
}

/**
* List all members of a given organization
*
* @param id the id of the organization
* @param pc the page control
* @param parser the parser for filters when building query
* @return the list of {@link SimpleMinionJson}s
*/
public static DataResult<SimpleMinionJson> listOrgMembers(Long id, PageControl pc, Function<Optional<PageControl>,
PagedSqlQueryBuilder.FilterWithValue> parser) {
Map<String, Object> params = Map.of("id", id);
return new PagedSqlQueryBuilder("s.id")
.select("s.id, s.name")
.from("rhnServer s")
.where("s.org_id = :id")
.run(params, pc, parser, SimpleMinionJson.class);
}

/**
* Return a list of recurring actions that use given config channel
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9288,6 +9288,9 @@ Alternatively, you will want to download &lt;strong&gt;Incremental Channel Conte
<trans-unit id="recurring_action.invalid_action_type" xml:space="preserve">
<source>Recurring action has invalid type.</source>
</trans-unit>
<trans-unit id="recurring_action.not_in_maint_mode" xml:space="preserve">
<source>One or more selected systems don't have a maintenance window assigned at the current time. Please limit your selection to systems that are in maintenance mode.</source>
</trans-unit>
<trans-unit id="internal_state.certs" xml:space="preserve">
<source>Install the server's SSL certificate and trust it on the target system</source>
</trans-unit>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import com.suse.manager.webui.services.SaltStateGeneratorService;
import com.suse.manager.webui.utils.SaltFileUtils;
import com.suse.manager.webui.utils.gson.RecurringActionScheduleJson;
import com.suse.manager.webui.utils.gson.SimpleMinionJson;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -227,6 +228,39 @@ public static List<RecurringAction> listOrgRecurringActions(long orgId, User use
return RecurringActionFactory.listOrgRecurringActions(orgId);
}

/**
* List all members of a given entity
*
* @param type the type of the entity
* @param id the entity id
* @param user the user
* @param pc the page control
* @param parser the parser for filters when building query
* @return the actions visible to the user
*/
public static DataResult<SimpleMinionJson> listEntityMembers(
RecurringAction.TargetType type, Long id, User user, PageControl pc, Function<Optional<PageControl>,
PagedSqlQueryBuilder.FilterWithValue> parser) {
DataResult<SimpleMinionJson> members;
switch (type) {
case GROUP:
if (!user.hasRole(RoleFactory.SYSTEM_GROUP_ADMIN)) {
throw new PermissionException(String.format("User does not have access to group id %d", id));
}
members = RecurringActionFactory.listGroupMembers(id, pc, parser);
break;
case ORG:
if (!user.hasRole(RoleFactory.ORG_ADMIN)) {
throw new PermissionException("Org not accessible to user");
}
members = RecurringActionFactory.listOrgMembers(id, pc, parser);
break;
default:
throw new IllegalStateException("Unsupported type " + type);
}
return members;
}

/**
* List all {@link RecurringAction}s visible to the given user
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@
import com.redhat.rhn.taskomatic.TaskomaticApi;
import com.redhat.rhn.taskomatic.TaskomaticApiException;

import com.suse.manager.maintenance.MaintenanceManager;
import com.suse.manager.maintenance.NotInMaintenanceModeException;
import com.suse.manager.utils.PagedSqlQueryBuilder;
import com.suse.manager.webui.utils.PageControlHelper;
import com.suse.manager.webui.utils.gson.PagedDataResultJson;
import com.suse.manager.webui.utils.gson.RecurringActionDetailsDto;
import com.suse.manager.webui.utils.gson.RecurringActionScheduleJson;
import com.suse.manager.webui.utils.gson.ResultJson;
import com.suse.manager.webui.utils.gson.SimpleMinionJson;
import com.suse.manager.webui.utils.gson.StateConfigJson;

import com.google.gson.Gson;
Expand Down Expand Up @@ -104,6 +105,7 @@ public static void initRoutes(JadeTemplateEngine jade) {
jade);

get("/manager/api/recurringactions", asJson(withUser(RecurringActionController::listAll)));
get("/manager/api/recurringactions/targets/:type/:id", asJson(withUser(RecurringActionController::getTargets)));
get("/manager/api/recurringactions/:id/details", asJson(withUser(RecurringActionController::getDetails)));
get("/manager/api/recurringactions/:type/:id", asJson(withUser(RecurringActionController::listByEntity)));
get("/manager/api/recurringactions/states", asJson(withUser(RecurringActionController::getStatesConfig)));
Expand Down Expand Up @@ -142,6 +144,35 @@ public static String listAll(Request request, Response response, User user) {
return json(response, new PagedDataResultJson<>(schedules, schedules.getTotalSize(), Collections.emptySet()));
}

/**
* Processes a GET request to get a list of all the members of an entity
*
* @param request the request object
* @param response the response object
* @param user the authorized user
* @return the result JSON object
*/
public static String getTargets(Request request, Response response, User user) {
TargetType type = TargetType.valueOf(request.params("type"));
Long id = Long.parseLong(request.params("id"));

PageControlHelper pageHelper = new PageControlHelper(request, "name");
PageControl pc = pageHelper.getPageControl();
DataResult<SimpleMinionJson> members =
RecurringActionManager.listEntityMembers(type, id, user, pc, PagedSqlQueryBuilder::parseFilterAsText);

if ("id".equals(pageHelper.getFunction())) {
pc.setStart(1);
pc.setPageSize(0);

return json(response, members.stream()
.map(SimpleMinionJson::getId)
.collect(Collectors.toList()));
}

return json(response, new PagedDataResultJson<>(members, members.getTotalSize(), Collections.emptySet()));
}

/**
* Processes a GET request to get the details of a recurring action based on its id.
* @param request the request object
Expand Down Expand Up @@ -309,29 +340,22 @@ public static String save(Request request, Response response, User user) {
*/
public static String executeCustom(Request request, Response response, User user) {
RecurringActionScheduleJson json = GSON.fromJson(request.body(), RecurringActionScheduleJson.class);
RecurringAction action = createOrGetAction(user, json);
if (!action.getActionType().equals(RecurringActionType.ActionType.CUSTOMSTATE)) {
LOG.error("Invalid action type");
Spark.halt(HttpStatus.SC_BAD_REQUEST, GSON.toJson(ResultJson.error(
LocalizationService.getInstance().getMessage("recurring_action_invalid_action_type"))));
}
mapJsonToAction(json, action);
Set<RecurringStateConfig> configs = getStateConfigFromJson(json.getDetails().getStates(), user);
List<Long> minionIds = json.getMemberIds();

List<Long> minionIds = new MaintenanceManager().systemIdsMaintenanceMode(action.computeMinions());
Set<RecurringStateConfig> configs = ((RecurringState) action.getRecurringActionType()).getStateConfig();
List<String> mods = configs.stream()
.sorted(Comparator.comparingLong(RecurringStateConfig::getPosition))
.map(RecurringStateConfig::getStateName)
.collect(Collectors.toList());
Action a = ActionManager.scheduleApplyStates(action.getCreator(),
minionIds, mods,
Optional.empty(),
new Date(),
Optional.of(((RecurringState) action.getRecurringActionType()).isTestMode()),
true);
ActionFactory.save(a);

try {
Action a = ActionManager.scheduleApplyStates(user,
minionIds, mods,
Optional.empty(),
new Date(),
Optional.of(json.getDetails().isTest()),
true);
ActionFactory.save(a);
new TaskomaticApi().scheduleActionExecution(a);
}
catch (TaskomaticApiException e) {
Expand All @@ -340,7 +364,10 @@ public static String executeCustom(Request request, Response response, User user
String errMsg = LocalizationService.getInstance().getMessage("recurring_action.taskomatic_error");
Spark.halt(HttpStatus.SC_SERVICE_UNAVAILABLE, GSON.toJson(ResultJson.error(errMsg)));
}

catch (NotInMaintenanceModeException e) {
String errMsg = LocalizationService.getInstance().getMessage("recurring_action.not_in_maint_mode");
Spark.halt(HttpStatus.SC_BAD_REQUEST, GSON.toJson(ResultJson.error(errMsg)));
}
return json(response, ResultJson.success());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.redhat.rhn.domain.recurringactions.type.RecurringActionType;
import com.redhat.rhn.frontend.dto.BaseTupleDto;

import java.util.List;
import java.util.Objects;

import javax.persistence.Tuple;
Expand Down Expand Up @@ -73,6 +74,9 @@ public RecurringActionScheduleJson(Tuple tuple) {
/** Target ID */
private Long targetId;

/** Ids of the entities members */
private List<Long> memberIds;

/** Name of the schedule */
private String scheduleName;

Expand Down Expand Up @@ -109,6 +113,15 @@ public Long getId() {
return getRecurringActionId();
}

/**
* Gets the List of member ids
*
* @return the memer ids
*/
public List<Long> getMemberIds() {
return memberIds;
}

/**
* Gets the recurringActionId.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,29 @@
package com.suse.manager.webui.utils.gson;

import com.redhat.rhn.domain.server.MinionServer;
import com.redhat.rhn.frontend.dto.BaseTupleDto;

import javax.persistence.Tuple;

/**
* Simple JSON representation of a Salt Minion.
*/
public class SimpleMinionJson {
public class SimpleMinionJson extends BaseTupleDto {

/**
* Default constructor
*/
public SimpleMinionJson() { }

/**
* Constructor used to populate using DTO projection from the data of query that list simple minions
*
* @param tuple JPA tuple
*/
public SimpleMinionJson(Tuple tuple) {
setId(getTupleValue(tuple, "id", Number.class).map(Number::longValue).orElse(null));
setName(getTupleValue(tuple, "name", String.class).orElse("-"));
}

private Long id;
private String name;
Expand Down Expand Up @@ -54,6 +72,24 @@ public String getName() {
return name;
}

/**
* Sets the minion id
*
* @param idIn the minion id
*/
public void setId(Long idIn) {
id = idIn;
}

/**
* Set the minion name
*
* @param nameIn the minion name
*/
public void setName(String nameIn) {
name = nameIn;
}

/**
* Instantiates a new minion json from a {@link MinionServer}
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add one-shot action execution to recurring custom state create/edit
Loading

0 comments on commit 0be4803

Please sign in to comment.