Integrated Maintenance Window fields in Management API and UI (#677)
* Added Maintenance Window properties to API and UI * extended Management API with Maintenance Window schedule, duration, timezone and nextAt properties * extended integration tests for the above properties * extended Management UI with Maintenance Window column in Action History grid, added tooltip for next execution * general refactoring Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch-si.com> * fixed Sonar issues Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch-si.com> * changed the documentation help link for maintenance window Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch-si.com> * added licence header, first refactoring after partial PR review Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch-si.com> * changes related to PR review findings Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch-si.com> * last PR review findings Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch-si.com>
This commit is contained in:
committed by
Dominic Schabel
parent
1deb47a4db
commit
b5114081be
@@ -8,88 +8,32 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.json.model;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* JSON model for Management API to define the maintenance window based on a
|
||||
* schedule defined as cron expression, duration in HH:mm:ss format and time
|
||||
* zone as offset from UTC.
|
||||
* JSON model for Management API to define the maintenance window.
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class MgmtMaintenanceWindow {
|
||||
|
||||
private String maintenanceSchedule;
|
||||
private String maintenanceWindowDuration;
|
||||
private String maintenanceWindowTimeZone;
|
||||
public class MgmtMaintenanceWindow extends MgmtMaintenanceWindowRequestBody {
|
||||
|
||||
/**
|
||||
* Sets the maintenance schedule.
|
||||
*
|
||||
* @param maintenanceSchedule
|
||||
* is the cron expression to be used for scheduling maintenance
|
||||
* window(s). Expression has 6 mandatory fields and a last
|
||||
* optional field: "second minute hour dayofmonth month weekday
|
||||
* year".
|
||||
* Time in {@link TimeUnit#MILLISECONDS} of the next maintenance window
|
||||
* start
|
||||
*/
|
||||
@JsonSetter("schedule")
|
||||
public void setMaintenanceSchedule(final String maintenanceSchedule) {
|
||||
this.maintenanceSchedule = maintenanceSchedule;
|
||||
@JsonProperty
|
||||
private long nextStartAt;
|
||||
|
||||
public long getNextStartAt() {
|
||||
return nextStartAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maintenance window duration.
|
||||
*
|
||||
* @param maintenanceWindowDuration
|
||||
* in HH:mm:ss format specifying the duration of a maintenance
|
||||
* window, for example 00:30:00 for 30 minutes.
|
||||
*/
|
||||
@JsonSetter("duration")
|
||||
public void setMaintenanceWindowDuration(final String maintenanceWindowDuration) {
|
||||
this.maintenanceWindowDuration = maintenanceWindowDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maintenance window timezone.
|
||||
*
|
||||
* @param maintenanceWindowTimeZone
|
||||
* is the time zone specified as +/-hh:mm offset from UTC. For
|
||||
* example +02:00 for CET summer time and +00:00 for UTC. The
|
||||
* start time of a maintenance window calculated based on the
|
||||
* cron expression is relative to this time zone.
|
||||
*/
|
||||
@JsonSetter("timezone")
|
||||
public void setMaintenanceWindowTimeZone(final String maintenanceWindowTimeZone) {
|
||||
this.maintenanceWindowTimeZone = maintenanceWindowTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maintenance schedule for the {@link Action}.
|
||||
*
|
||||
* @return cron expression as {@link String}.
|
||||
*/
|
||||
public String getMaintenanceSchedule() {
|
||||
return maintenanceSchedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of maintenance window for the {@link Action}.
|
||||
*
|
||||
* @return duration in HH:mm:ss format as {@link String}.
|
||||
*/
|
||||
public String getMaintenanceWindowDuration() {
|
||||
return maintenanceWindowDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timezone of maintenance window for the {@link Action}.
|
||||
*
|
||||
* @return the timezone offset from UTC in +/-hh:mm as {@link String}.
|
||||
*/
|
||||
public String getMaintenanceWindowTimeZone() {
|
||||
return maintenanceWindowTimeZone;
|
||||
public void setNextStartAt(final long nextStartAt) {
|
||||
this.nextStartAt = nextStartAt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.json.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Request body for maintenance window PUT/POST commands, based on a schedule
|
||||
* defined as cron expression, duration in HH:mm:ss format and time zone as
|
||||
* offset from UTC.
|
||||
*
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class MgmtMaintenanceWindowRequestBody {
|
||||
@JsonProperty
|
||||
private String schedule;
|
||||
|
||||
@JsonProperty
|
||||
private String duration;
|
||||
|
||||
@JsonProperty
|
||||
private String timezone;
|
||||
|
||||
public String getSchedule() {
|
||||
return schedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param schedule
|
||||
* is the cron expression to be used for scheduling maintenance
|
||||
* window(s). Expression has 6 mandatory fields and a last
|
||||
* optional field: "second minute hour dayofmonth month weekday
|
||||
* year".
|
||||
*/
|
||||
public void setSchedule(final String schedule) {
|
||||
this.schedule = schedule;
|
||||
}
|
||||
|
||||
public String getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param duration
|
||||
* in HH:mm:ss format specifying the duration of a maintenance
|
||||
* window, for example 00:30:00 for 30 minutes.
|
||||
*/
|
||||
public void setDuration(final String duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public String getTimezone() {
|
||||
return timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timezone
|
||||
* is the time zone specified as +/-hh:mm offset from UTC. For
|
||||
* example +02:00 for CET summer time and +00:00 for UTC. The
|
||||
* start time of a maintenance window calculated based on the
|
||||
* cron expression is relative to this time zone.
|
||||
*/
|
||||
public void setTimezone(final String timezone) {
|
||||
this.timezone = timezone;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
package org.eclipse.hawkbit.mgmt.json.model.action;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtBaseEntity;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
@@ -59,6 +60,17 @@ public class MgmtAction extends MgmtBaseEntity {
|
||||
@JsonProperty
|
||||
private MgmtActionType forceType;
|
||||
|
||||
@JsonProperty
|
||||
private MgmtMaintenanceWindow maintenanceWindow;
|
||||
|
||||
public MgmtMaintenanceWindow getMaintenanceWindow() {
|
||||
return maintenanceWindow;
|
||||
}
|
||||
|
||||
public void setMaintenanceWindow(final MgmtMaintenanceWindow maintenanceWindow) {
|
||||
this.maintenanceWindow = maintenanceWindow;
|
||||
}
|
||||
|
||||
public Long getForceTime() {
|
||||
return forceTime;
|
||||
}
|
||||
@@ -75,47 +87,26 @@ public class MgmtAction extends MgmtBaseEntity {
|
||||
this.forceType = forceType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the status
|
||||
*/
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param status
|
||||
* the status to set
|
||||
*/
|
||||
public void setStatus(final String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionId
|
||||
*/
|
||||
public Long getActionId() {
|
||||
return actionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param actionId
|
||||
* the actionId to set
|
||||
*/
|
||||
public void setActionId(final Long actionId) {
|
||||
this.actionId = actionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* the type to set
|
||||
*/
|
||||
public void setType(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.json.model.distributionset;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindowRequestBody;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -28,10 +28,10 @@ public class MgmtTargetAssignmentRequestBody {
|
||||
private MgmtActionType type;
|
||||
|
||||
/**
|
||||
* {@link MgmtMaintenanceWindow} object containing schedule, duration and
|
||||
* timezone.
|
||||
* {@link MgmtMaintenanceWindowRequestBody} object containing schedule,
|
||||
* duration and timezone.
|
||||
*/
|
||||
private MgmtMaintenanceWindow maintenanceWindow;
|
||||
private MgmtMaintenanceWindowRequestBody maintenanceWindow;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@@ -57,11 +57,11 @@ public class MgmtTargetAssignmentRequestBody {
|
||||
this.forcetime = forcetime;
|
||||
}
|
||||
|
||||
public MgmtMaintenanceWindow getMaintenanceWindow() {
|
||||
public MgmtMaintenanceWindowRequestBody getMaintenanceWindow() {
|
||||
return maintenanceWindow;
|
||||
}
|
||||
|
||||
public void setMaintenanceWindow(final MgmtMaintenanceWindow maintenanceWindow) {
|
||||
public void setMaintenanceWindow(final MgmtMaintenanceWindowRequestBody maintenanceWindow) {
|
||||
this.maintenanceWindow = maintenanceWindow;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package org.eclipse.hawkbit.mgmt.json.model.target;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindowRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
|
||||
/**
|
||||
@@ -16,10 +16,10 @@ public class MgmtDistributionSetAssignment extends MgmtId {
|
||||
private MgmtActionType type;
|
||||
|
||||
/**
|
||||
* {@link MgmtMaintenanceWindow} object defining a schedule, duration and
|
||||
* timezone.
|
||||
* {@link MgmtMaintenanceWindowRequestBody} object defining a schedule,
|
||||
* duration and timezone.
|
||||
*/
|
||||
private MgmtMaintenanceWindow maintenanceWindow;
|
||||
private MgmtMaintenanceWindowRequestBody maintenanceWindow;
|
||||
|
||||
public MgmtActionType getType() {
|
||||
return type;
|
||||
@@ -38,21 +38,23 @@ public class MgmtDistributionSetAssignment extends MgmtId {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link MgmtMaintenanceWindow} for distribution set assignment.
|
||||
* Returns {@link MgmtMaintenanceWindowRequestBody} for distribution set
|
||||
* assignment.
|
||||
*
|
||||
* @return {@link MgmtMaintenanceWindow}.
|
||||
* @return {@link MgmtMaintenanceWindowRequestBody}.
|
||||
*/
|
||||
public MgmtMaintenanceWindow getMaintenanceWindow() {
|
||||
public MgmtMaintenanceWindowRequestBody getMaintenanceWindow() {
|
||||
return maintenanceWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link MgmtMaintenanceWindow} for distribution set assignment.
|
||||
* Sets {@link MgmtMaintenanceWindowRequestBody} for distribution set
|
||||
* assignment.
|
||||
*
|
||||
* @param maintenanceWindow
|
||||
* as {@link MgmtMaintenanceWindow}.
|
||||
* as {@link MgmtMaintenanceWindowRequestBody}.
|
||||
*/
|
||||
public void setMaintenanceWindow(final MgmtMaintenanceWindow maintenanceWindow) {
|
||||
public void setMaintenanceWindow(final MgmtMaintenanceWindowRequestBody maintenanceWindow) {
|
||||
this.maintenanceWindow = maintenanceWindow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindowRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
@@ -252,14 +253,16 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
|
||||
|
||||
final DistributionSetAssignmentResult assignDistributionSet = this.deployManagament
|
||||
.assignDistributionSet(distributionSetId, assignments.stream().map(t -> {
|
||||
if (t.getMaintenanceWindow() == null) {
|
||||
final MgmtMaintenanceWindowRequestBody maintenanceWindow = t.getMaintenanceWindow();
|
||||
|
||||
if (maintenanceWindow == null) {
|
||||
return new TargetWithActionType(t.getId(), MgmtRestModelMapper.convertActionType(t.getType()),
|
||||
t.getForcetime());
|
||||
}
|
||||
|
||||
final String cronSchedule = t.getMaintenanceWindow().getMaintenanceSchedule();
|
||||
final String duration = t.getMaintenanceWindow().getMaintenanceWindowDuration();
|
||||
final String timezone = t.getMaintenanceWindow().getMaintenanceWindowTimeZone();
|
||||
final String cronSchedule = maintenanceWindow.getSchedule();
|
||||
final String duration = maintenanceWindow.getDuration();
|
||||
final String timezone = maintenanceWindow.getTimezone();
|
||||
|
||||
MaintenanceScheduleHelper.validateMaintenanceSchedule(cronSchedule, duration, timezone);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtPollStatus;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionStatus;
|
||||
@@ -194,6 +195,16 @@ public final class MgmtTargetMapper {
|
||||
result.setStatus(MgmtAction.ACTION_FINISHED);
|
||||
}
|
||||
|
||||
if (action.hasMaintenanceSchedule()) {
|
||||
final MgmtMaintenanceWindow maintenanceWindow = new MgmtMaintenanceWindow();
|
||||
maintenanceWindow.setSchedule(action.getMaintenanceWindowSchedule());
|
||||
maintenanceWindow.setDuration(action.getMaintenanceWindowDuration());
|
||||
maintenanceWindow.setTimezone(action.getMaintenanceWindowTimeZone());
|
||||
action.getMaintenanceWindowStartTime()
|
||||
.ifPresent(nextStart -> maintenanceWindow.setNextStartAt(nextStart.toInstant().toEpochMilli()));
|
||||
result.setMaintenanceWindow(maintenanceWindow);
|
||||
}
|
||||
|
||||
MgmtRestModelMapper.mapBaseToBase(result, action);
|
||||
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getAction(targetId, action.getId())).withSelfRel());
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.util.Map;
|
||||
|
||||
import javax.validation.ValidationException;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindowRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionRequestBodyPut;
|
||||
@@ -276,7 +276,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
|
||||
}
|
||||
|
||||
findTargetWithExceptionIfNotFound(controllerId);
|
||||
final MgmtMaintenanceWindow maintenanceWindow = dsId.getMaintenanceWindow();
|
||||
final MgmtMaintenanceWindowRequestBody maintenanceWindow = dsId.getMaintenanceWindow();
|
||||
|
||||
if (maintenanceWindow == null) {
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponse(this.deploymentManagement
|
||||
@@ -284,9 +284,9 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
|
||||
MgmtRestModelMapper.convertActionType(dsId.getType()), dsId.getForcetime())))));
|
||||
}
|
||||
|
||||
final String cronSchedule = maintenanceWindow.getMaintenanceSchedule();
|
||||
final String duration = maintenanceWindow.getMaintenanceWindowDuration();
|
||||
final String timezone = maintenanceWindow.getMaintenanceWindowTimeZone();
|
||||
final String cronSchedule = maintenanceWindow.getSchedule();
|
||||
final String duration = maintenanceWindow.getDuration();
|
||||
final String timezone = maintenanceWindow.getTimezone();
|
||||
|
||||
MaintenanceScheduleHelper.validateMaintenanceSchedule(cronSchedule, duration, timezone);
|
||||
|
||||
|
||||
@@ -853,17 +853,97 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the expected response is return when update was cancelled.")
|
||||
@Description("Ensures that the expected response is returned for update action.")
|
||||
public void getUpdateAction() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actions.get(1).getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("id", equalTo(actions.get(1).getId().intValue())))
|
||||
.andExpect(jsonPath("type", equalTo("update"))).andExpect(jsonPath("status", equalTo("pending")))
|
||||
.andExpect(jsonPath("forceType", equalTo("forced")))
|
||||
.andExpect(jsonPath("maintenanceWindow").doesNotExist())
|
||||
.andExpect(jsonPath("_links.self.href",
|
||||
equalTo(generateActionSelfLink(knownTargetId, actions.get(1).getId()))))
|
||||
.andExpect(jsonPath("_links.distributionset.href",
|
||||
equalTo(generateActionDsLink(actions.get(1).getDistributionSet().getId()))))
|
||||
.andExpect(jsonPath("_links.status.href",
|
||||
equalTo(generateStatusreferenceLink(knownTargetId, actions.get(1).getId()))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the expected response is returned for update action with maintenance window.")
|
||||
public void getUpdateActionWithMaintenanceWindow() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
final String schedule = getTestSchedule(10);
|
||||
final String duration = getTestDuration(10);
|
||||
final String timezone = getTestTimeZone();
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverrideWithMaintenanceWindow(knownTargetId,
|
||||
schedule, duration, timezone);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actions.get(1).getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("id", equalTo(actions.get(1).getId().intValue())))
|
||||
.andExpect(jsonPath("type", equalTo("update"))).andExpect(jsonPath("status", equalTo("pending")))
|
||||
.andExpect(jsonPath("forceType", equalTo("forced")))
|
||||
.andExpect(jsonPath("maintenanceWindow.schedule", equalTo(schedule)))
|
||||
.andExpect(jsonPath("maintenanceWindow.duration", equalTo(duration)))
|
||||
.andExpect(jsonPath("maintenanceWindow.timezone", equalTo(timezone)))
|
||||
.andExpect(jsonPath("maintenanceWindow.nextStartAt",
|
||||
equalTo(actions.get(1).getMaintenanceWindowStartTime().get().toInstant().toEpochMilli())))
|
||||
.andExpect(jsonPath("_links.self.href",
|
||||
equalTo(generateActionSelfLink(knownTargetId, actions.get(1).getId()))))
|
||||
.andExpect(jsonPath("_links.distributionset.href",
|
||||
equalTo(generateActionDsLink(actions.get(1).getDistributionSet().getId()))))
|
||||
.andExpect(jsonPath("_links.status.href",
|
||||
equalTo(generateStatusreferenceLink(knownTargetId, actions.get(1).getId()))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the expected response is returned when update action was cancelled.")
|
||||
public void getCancelAction() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("id", equalTo(actions.get(0).getId().intValue())))
|
||||
.andExpect(jsonPath("type", equalTo("cancel"))).andExpect(jsonPath("status", equalTo("pending")))
|
||||
.andExpect(jsonPath("forceType", equalTo("forced")))
|
||||
.andExpect(jsonPath("maintenanceWindow").doesNotExist())
|
||||
.andExpect(jsonPath("_links.self.href",
|
||||
equalTo(generateActionSelfLink(knownTargetId, actions.get(0).getId()))))
|
||||
.andExpect(jsonPath("_links.canceledaction.href",
|
||||
equalTo(generateCanceledactionreferenceLink(knownTargetId, actions.get(0)))))
|
||||
.andExpect(jsonPath("_links.status.href",
|
||||
equalTo(generateStatusreferenceLink(knownTargetId, actions.get(0).getId()))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the expected response is returned when update action with maintenance window was cancelled.")
|
||||
public void getCancelActionWithMaintenanceWindow() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
final String schedule = getTestSchedule(10);
|
||||
final String duration = getTestDuration(10);
|
||||
final String timezone = getTestTimeZone();
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverrideWithMaintenanceWindow(knownTargetId,
|
||||
schedule, duration, timezone);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("id", equalTo(actions.get(0).getId().intValue())))
|
||||
.andExpect(jsonPath("forceType", equalTo("forced"))).andExpect(jsonPath("type", equalTo("cancel")))
|
||||
.andExpect(jsonPath("status", equalTo("pending")))
|
||||
.andExpect(jsonPath("maintenanceWindow.schedule", equalTo(schedule)))
|
||||
.andExpect(jsonPath("maintenanceWindow.duration", equalTo(duration)))
|
||||
.andExpect(jsonPath("maintenanceWindow.timezone", equalTo(timezone)))
|
||||
.andExpect(jsonPath("maintenanceWindow.nextStartAt",
|
||||
equalTo(actions.get(0).getMaintenanceWindowStartTime().get().toInstant().toEpochMilli())))
|
||||
.andExpect(jsonPath("_links.self.href",
|
||||
equalTo(generateActionSelfLink(knownTargetId, actions.get(0).getId()))))
|
||||
.andExpect(jsonPath("_links.canceledaction.href",
|
||||
@@ -896,6 +976,44 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the expected response of getting actions with maintenance window of a target is returned.")
|
||||
public void getMultipleActionsWithMaintenanceWindow() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
final String schedule = getTestSchedule(10);
|
||||
final String duration = getTestDuration(10);
|
||||
final String timezone = getTestTimeZone();
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverrideWithMaintenanceWindow(knownTargetId,
|
||||
schedule, duration, timezone);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS).param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("content.[1].id", equalTo(actions.get(1).getId().intValue())))
|
||||
.andExpect(jsonPath("content.[1].type", equalTo("update")))
|
||||
.andExpect(jsonPath("content.[1].status", equalTo("pending")))
|
||||
.andExpect(jsonPath("content.[1].maintenanceWindow.schedule", equalTo(schedule)))
|
||||
.andExpect(jsonPath("content.[1].maintenanceWindow.duration", equalTo(duration)))
|
||||
.andExpect(jsonPath("content.[1].maintenanceWindow.timezone", equalTo(timezone)))
|
||||
.andExpect(jsonPath("content.[1].maintenanceWindow.nextStartAt",
|
||||
equalTo(actions.get(1).getMaintenanceWindowStartTime().get().toInstant().toEpochMilli())))
|
||||
.andExpect(jsonPath("content.[1]._links.self.href",
|
||||
equalTo(generateActionSelfLink(knownTargetId, actions.get(1).getId()))))
|
||||
.andExpect(jsonPath("content.[0].id", equalTo(actions.get(0).getId().intValue())))
|
||||
.andExpect(jsonPath("content.[0].type", equalTo("cancel")))
|
||||
.andExpect(jsonPath("content.[0].status", equalTo("pending")))
|
||||
.andExpect(jsonPath("content.[0].maintenanceWindow.schedule", equalTo(schedule)))
|
||||
.andExpect(jsonPath("content.[0].maintenanceWindow.duration", equalTo(duration)))
|
||||
.andExpect(jsonPath("content.[0].maintenanceWindow.timezone", equalTo(timezone)))
|
||||
.andExpect(jsonPath("content.[0].maintenanceWindow.nextStartAt",
|
||||
equalTo(actions.get(0).getMaintenanceWindowStartTime().get().toInstant().toEpochMilli())))
|
||||
.andExpect(jsonPath("content.[0]._links.self.href",
|
||||
equalTo(generateActionSelfLink(knownTargetId, actions.get(0).getId()))))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the API returns the status list with expected content.")
|
||||
public void getMultipleActionStatus() throws Exception {
|
||||
@@ -1054,6 +1172,10 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId;
|
||||
}
|
||||
|
||||
private String generateActionDsLink(final Long dsId) {
|
||||
return "http://localhost" + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + dsId;
|
||||
}
|
||||
|
||||
private String generateCanceledactionreferenceLink(final String knownTargetId, final Action action) {
|
||||
return "http://localhost" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId();
|
||||
@@ -1067,20 +1189,33 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
||||
|
||||
private List<Action> generateTargetWithTwoUpdatesWithOneOverride(final String knownTargetId)
|
||||
throws InterruptedException {
|
||||
return generateTargetWithTwoUpdatesWithOneOverrideWithMaintenanceWindow(knownTargetId, null, null, null);
|
||||
}
|
||||
|
||||
private List<Action> generateTargetWithTwoUpdatesWithOneOverrideWithMaintenanceWindow(final String knownTargetId,
|
||||
final String schedule, final String duration, final String timezone) throws InterruptedException {
|
||||
final Target target = testdataFactory.createTarget(knownTargetId);
|
||||
final List<Target> targets = Arrays.asList(target);
|
||||
|
||||
final Iterator<DistributionSet> sets = testdataFactory.createDistributionSets(2).iterator();
|
||||
final DistributionSet one = sets.next();
|
||||
final DistributionSet two = sets.next();
|
||||
|
||||
// Update
|
||||
final List<Target> updatedTargets = assignDistributionSet(one, targets).getAssignedEntity();
|
||||
// 2nd update
|
||||
// sleep 10ms to ensure that we can sort by reportedAt
|
||||
Thread.sleep(10);
|
||||
assignDistributionSet(two, updatedTargets);
|
||||
if (schedule == null) {
|
||||
final List<Target> updatedTargets = assignDistributionSet(one, Arrays.asList(target)).getAssignedEntity();
|
||||
// 2nd update
|
||||
// sleep 10ms to ensure that we can sort by reportedAt
|
||||
Thread.sleep(10);
|
||||
assignDistributionSet(two, updatedTargets);
|
||||
} else {
|
||||
final List<Target> updatedTargets = assignDistributionSetWithMaintenanceWindow(one.getId(),
|
||||
target.getControllerId(), schedule, duration, timezone).getAssignedEntity();
|
||||
// 2nd update
|
||||
// sleep 10ms to ensure that we can sort by reportedAt
|
||||
Thread.sleep(10);
|
||||
assignDistributionSetWithMaintenanceWindow(two.getId(), updatedTargets.get(0).getControllerId(), schedule,
|
||||
duration, timezone);
|
||||
}
|
||||
|
||||
// two updates, one cancellation
|
||||
final List<Action> actions = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE)
|
||||
@@ -1090,26 +1225,6 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUpdateAction() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actions.get(1).getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("id", equalTo(actions.get(1).getId().intValue())))
|
||||
.andExpect(jsonPath("type", equalTo("update"))).andExpect(jsonPath("status", equalTo("pending")))
|
||||
.andExpect(jsonPath("forceType", equalTo("forced")))
|
||||
.andExpect(jsonPath("_links.self.href",
|
||||
equalTo(generateActionSelfLink(knownTargetId, actions.get(1).getId()))))
|
||||
.andExpect(jsonPath("_links.distributionset.href",
|
||||
equalTo("http://localhost/rest/v1/distributionsets/"
|
||||
+ actions.get(1).getDistributionSet().getId())))
|
||||
.andExpect(jsonPath("_links.status.href",
|
||||
equalTo(generateStatusreferenceLink(knownTargetId, actions.get(1).getId()))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that an action is switched from soft to forced if requested by management API")
|
||||
public void updateAction() throws Exception {
|
||||
@@ -1266,6 +1381,28 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Assigns distribution set to target with maintenance window next execution start (should be ignored, calculated automaticaly based on schedule, duration and timezone)")
|
||||
public void assignDistributionSetToTargetWithMaintenanceWindowNextExecutionStart() throws Exception {
|
||||
|
||||
final Target target = testdataFactory.createTarget("fsdfsd");
|
||||
final DistributionSet set = testdataFactory.createDistributionSet("one");
|
||||
final long nextExecutionStart = System.currentTimeMillis();
|
||||
|
||||
final String body = new JSONObject().put("id", set.getId())
|
||||
.put("maintenanceWindow", getMaintenanceWindowWithNextStart(getTestSchedule(10), getTestDuration(10),
|
||||
getTestTimeZone(), nextExecutionStart))
|
||||
.toString();
|
||||
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + target.getControllerId() + "/assignedDS")
|
||||
.content(body).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + target.getControllerId() + "/"
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS)).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(jsonPath("content.[0].maintenanceWindow.nextStartAt", not(nextExecutionStart)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Assigns distribution set to target with last maintenance window scheduled before current time.")
|
||||
public void assignDistributionSetToTargetWithMaintenanceWindowEndTimeBeforeStartTime() throws Exception {
|
||||
|
||||
@@ -55,7 +55,7 @@ public final class MaintenanceScheduleHelper {
|
||||
* start time of a maintenance window calculated based on the
|
||||
* cron expression is relative to this time zone.
|
||||
*
|
||||
* @return {@link Optional<ZonedDateTime>} of the next available window. In
|
||||
* @return { @link Optional<ZonedDateTime>} of the next available window. In
|
||||
* case there is none, or there are maintenance window validation
|
||||
* errors, returns empty value.
|
||||
*
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.model;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -18,7 +20,7 @@ public interface Action extends TenantAwareBaseEntity {
|
||||
/**
|
||||
* Maximum length of controllerId.
|
||||
*/
|
||||
int MAINTENANCE_SCHEDULE_CRON_LENGTH = 128;
|
||||
int MAINTENANCE_WINDOW_SCHEDULE_LENGTH = 128;
|
||||
|
||||
/**
|
||||
* Maximum length of controllerId.
|
||||
@@ -81,6 +83,21 @@ public interface Action extends TenantAwareBaseEntity {
|
||||
*/
|
||||
Rollout getRollout();
|
||||
|
||||
/**
|
||||
* @return maintenance window schedule related to this {@link Action}.
|
||||
*/
|
||||
String getMaintenanceWindowSchedule();
|
||||
|
||||
/**
|
||||
* @return maintenance window duration related to this {@link Action}.
|
||||
*/
|
||||
String getMaintenanceWindowDuration();
|
||||
|
||||
/**
|
||||
* @return maintenance window time zone related to this {@link Action}.
|
||||
*/
|
||||
String getMaintenanceWindowTimeZone();
|
||||
|
||||
/**
|
||||
* checks if the {@link #getForcedTime()} is hit by the given
|
||||
* {@code hitTimeMillis}, by means if the given milliseconds are greater
|
||||
@@ -215,6 +232,15 @@ public interface Action extends TenantAwareBaseEntity {
|
||||
TIMEFORCED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start time of next available maintenance window for the
|
||||
* {@link Action} as {@link ZonedDateTime}. If a maintenance window is
|
||||
* already active, the start time of currently active window is returned.
|
||||
*
|
||||
* @return the start time as { @link Optional<ZonedDateTime>}.
|
||||
*/
|
||||
Optional<ZonedDateTime> getMaintenanceWindowStartTime();
|
||||
|
||||
/**
|
||||
* The method checks whether the action has a maintenance schedule defined
|
||||
* for it. A maintenance schedule defines a set of maintenance windows
|
||||
|
||||
@@ -229,7 +229,7 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
actionForTarget.setActive(true);
|
||||
actionForTarget.setTarget(target);
|
||||
actionForTarget.setDistributionSet(set);
|
||||
actionForTarget.setMaintenanceSchedule(targetWithActionType.getMaintenanceSchedule());
|
||||
actionForTarget.setMaintenanceWindowSchedule(targetWithActionType.getMaintenanceSchedule());
|
||||
actionForTarget.setMaintenanceWindowDuration(targetWithActionType.getMaintenanceWindowDuration());
|
||||
actionForTarget.setMaintenanceWindowTimeZone(targetWithActionType.getMaintenanceWindowTimeZone());
|
||||
return actionForTarget;
|
||||
|
||||
@@ -117,8 +117,8 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
@JoinColumn(name = "rollout", updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout"))
|
||||
private JpaRollout rollout;
|
||||
|
||||
@Column(name = "maintenance_cron_schedule", updatable = false, length = Action.MAINTENANCE_SCHEDULE_CRON_LENGTH)
|
||||
private String maintenanceSchedule;
|
||||
@Column(name = "maintenance_cron_schedule", updatable = false, length = Action.MAINTENANCE_WINDOW_SCHEDULE_LENGTH)
|
||||
private String maintenanceWindowSchedule;
|
||||
|
||||
@Column(name = "maintenance_duration", updatable = false, length = Action.MAINTENANCE_WINDOW_DURATION_LENGTH)
|
||||
private String maintenanceWindowDuration;
|
||||
@@ -231,14 +231,24 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
// there is no action deletion
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaintenanceWindowSchedule() {
|
||||
return maintenanceWindowSchedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maintenance schedule.
|
||||
*
|
||||
* @param maintenanceSchedule
|
||||
* @param maintenanceWindowSchedule
|
||||
* is a cron expression to be used for scheduling.
|
||||
*/
|
||||
public void setMaintenanceSchedule(final String maintenanceSchedule) {
|
||||
this.maintenanceSchedule = maintenanceSchedule;
|
||||
public void setMaintenanceWindowSchedule(final String maintenanceWindowSchedule) {
|
||||
this.maintenanceWindowSchedule = maintenanceWindowSchedule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaintenanceWindowDuration() {
|
||||
return maintenanceWindowDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -252,6 +262,11 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
this.maintenanceWindowDuration = maintenanceWindowDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaintenanceWindowTimeZone() {
|
||||
return maintenanceWindowTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time zone to be used for maintenance window.
|
||||
*
|
||||
@@ -265,15 +280,9 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
this.maintenanceWindowTimeZone = maintenanceWindowTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start time of next available maintenance window for the
|
||||
* {@link Action} as {@link ZonedDateTime}. If a maintenance window is
|
||||
* already active, the start time of currently active window is returned.
|
||||
*
|
||||
* @return the start time as {@link Optional<ZonedDateTime>}.
|
||||
*/
|
||||
@Override
|
||||
public Optional<ZonedDateTime> getMaintenanceWindowStartTime() {
|
||||
return MaintenanceScheduleHelper.getNextMaintenanceWindow(maintenanceSchedule, maintenanceWindowDuration,
|
||||
return MaintenanceScheduleHelper.getNextMaintenanceWindow(maintenanceWindowSchedule, maintenanceWindowDuration,
|
||||
maintenanceWindowTimeZone);
|
||||
}
|
||||
|
||||
@@ -282,7 +291,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
* the {@link Action} as {@link ZonedDateTime}. If a maintenance window is
|
||||
* already active, the end time of currently active window is returned.
|
||||
*
|
||||
* @return the end time of window as {@link Optional<ZonedDateTime>}.
|
||||
* @return the end time of window as { @link Optional<ZonedDateTime>}.
|
||||
*/
|
||||
private Optional<ZonedDateTime> getMaintenanceWindowEndTime() {
|
||||
return getMaintenanceWindowStartTime()
|
||||
@@ -291,7 +300,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
|
||||
@Override
|
||||
public boolean hasMaintenanceSchedule() {
|
||||
return this.maintenanceSchedule != null;
|
||||
return this.maintenanceWindowSchedule != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -225,7 +225,7 @@ public abstract class AbstractIntegrationTest {
|
||||
}
|
||||
};
|
||||
|
||||
protected DistributionSetAssignmentResult assignDistributionSet(final Long dsID, final String controllerId) {
|
||||
protected DistributionSetAssignmentResult assignDistributionSet(final long dsID, final String controllerId) {
|
||||
return deploymentManagement.assignDistributionSet(dsID, Arrays.asList(
|
||||
new TargetWithActionType(controllerId, ActionType.FORCED, RepositoryModelConstants.NO_FORCE_TIME)));
|
||||
}
|
||||
@@ -253,18 +253,26 @@ public abstract class AbstractIntegrationTest {
|
||||
* start time of a maintenance window calculated based on the
|
||||
* cron expression is relative to this time zone
|
||||
*
|
||||
* @return result of the assignment as
|
||||
* {@link DistributionSetAssignmentResult}.
|
||||
* @return result of the assignment as { @link
|
||||
* DistributionSetAssignmentResult}.
|
||||
*/
|
||||
protected DistributionSetAssignmentResult assignDistributionSetWithMaintenanceWindow(final Long dsID,
|
||||
final String controllerId, final String maintenanceSchedule, final String maintenanceWindowDuration,
|
||||
protected DistributionSetAssignmentResult assignDistributionSetWithMaintenanceWindow(final long dsID,
|
||||
final String controllerId, final String maintenanceWindowSchedule, final String maintenanceWindowDuration,
|
||||
final String maintenanceWindowTimeZone) {
|
||||
return deploymentManagement.assignDistributionSet(dsID,
|
||||
Arrays.asList(new TargetWithActionType(controllerId, ActionType.FORCED,
|
||||
RepositoryModelConstants.NO_FORCE_TIME, maintenanceSchedule, maintenanceWindowDuration,
|
||||
RepositoryModelConstants.NO_FORCE_TIME, maintenanceWindowSchedule, maintenanceWindowDuration,
|
||||
maintenanceWindowTimeZone)));
|
||||
}
|
||||
|
||||
protected DistributionSetAssignmentResult assignDistributionSetWithMaintenanceWindowTimeForced(final long dsID,
|
||||
final String controllerId, final String maintenanceWindowSchedule, final String maintenanceWindowDuration,
|
||||
final String maintenanceWindowTimeZone) {
|
||||
return deploymentManagement.assignDistributionSet(dsID,
|
||||
Arrays.asList(new TargetWithActionType(controllerId, ActionType.TIMEFORCED, System.currentTimeMillis(),
|
||||
maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone)));
|
||||
}
|
||||
|
||||
protected DistributionSetAssignmentResult assignDistributionSet(final DistributionSet pset,
|
||||
final List<Target> targets) {
|
||||
return deploymentManagement.assignDistributionSet(pset.getId(),
|
||||
@@ -275,11 +283,17 @@ public abstract class AbstractIntegrationTest {
|
||||
return assignDistributionSet(pset, Arrays.asList(target));
|
||||
}
|
||||
|
||||
protected DistributionSetMetadata createDistributionSetMetadata(final Long dsId, final MetaData md) {
|
||||
protected DistributionSetAssignmentResult assignDistributionSetTimeForced(final DistributionSet pset,
|
||||
final Target target) {
|
||||
return deploymentManagement.assignDistributionSet(pset.getId(), Arrays.asList(
|
||||
new TargetWithActionType(target.getControllerId(), ActionType.TIMEFORCED, System.currentTimeMillis())));
|
||||
}
|
||||
|
||||
protected DistributionSetMetadata createDistributionSetMetadata(final long dsId, final MetaData md) {
|
||||
return createDistributionSetMetadata(dsId, Collections.singletonList(md)).get(0);
|
||||
}
|
||||
|
||||
protected List<DistributionSetMetadata> createDistributionSetMetadata(final Long dsId, final List<MetaData> md) {
|
||||
protected List<DistributionSetMetadata> createDistributionSetMetadata(final long dsId, final List<MetaData> md) {
|
||||
return distributionSetManagement.createMetaData(dsId, md);
|
||||
}
|
||||
|
||||
@@ -378,23 +392,23 @@ public abstract class AbstractIntegrationTest {
|
||||
*
|
||||
* @return {@link String} containing a valid cron expression.
|
||||
*/
|
||||
public static String getTestSchedule(final int minutesToAdd) {
|
||||
protected static String getTestSchedule(final int minutesToAdd) {
|
||||
ZonedDateTime currentTime = ZonedDateTime.now();
|
||||
currentTime = currentTime.plusMinutes(minutesToAdd);
|
||||
return String.format("0 %d %d %d %d ? %d", currentTime.getMinute(), currentTime.getHour(),
|
||||
currentTime.getDayOfMonth(), currentTime.getMonthValue(), currentTime.getYear());
|
||||
}
|
||||
|
||||
public static String getTestDuration(final int duration) {
|
||||
protected static String getTestDuration(final int duration) {
|
||||
return String.format("%02d:%02d:00", duration / 60, duration % 60);
|
||||
}
|
||||
|
||||
public static String getTestTimeZone() {
|
||||
protected static String getTestTimeZone() {
|
||||
final ZonedDateTime currentTime = ZonedDateTime.now();
|
||||
return currentTime.getOffset().getId().replace("Z", "+00:00");
|
||||
}
|
||||
|
||||
public static Map<String, String> getMaintenanceWindow(final String schedule, final String duration,
|
||||
protected static Map<String, String> getMaintenanceWindow(final String schedule, final String duration,
|
||||
final String timezone) {
|
||||
final Map<String, String> maintenanceWindowMap = new HashMap<>();
|
||||
maintenanceWindowMap.put("schedule", schedule);
|
||||
@@ -402,4 +416,11 @@ public abstract class AbstractIntegrationTest {
|
||||
maintenanceWindowMap.put("timezone", timezone);
|
||||
return maintenanceWindowMap;
|
||||
}
|
||||
|
||||
protected static Map<String, String> getMaintenanceWindowWithNextStart(final String schedule, final String duration,
|
||||
final String timezone, final long nextStartAt) {
|
||||
final Map<String, String> maintenanceWindowMap = getMaintenanceWindow(schedule, duration, timezone);
|
||||
maintenanceWindowMap.put("nextStartAt", String.valueOf(nextStartAt));
|
||||
return maintenanceWindowMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,16 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.grid;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.components.RefreshableContainer;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ProxyAction;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ProxyActionStatus;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
@@ -284,8 +288,8 @@ public abstract class AbstractGrid<T extends Indexed> extends Grid implements Re
|
||||
|
||||
/**
|
||||
* Template method invoked by {@link this#addNewContainerDS()} for adding
|
||||
* properties to the container (usually by invoing
|
||||
* {@link Container#addContainerProperty(Object, Class, Object))})
|
||||
* properties to the container (usually by invoking { @link
|
||||
* Container#addContainerProperty(Object, Class, Object))})
|
||||
*/
|
||||
protected abstract void addContainerProperties();
|
||||
|
||||
@@ -581,7 +585,7 @@ public abstract class AbstractGrid<T extends Indexed> extends Grid implements Re
|
||||
* CellStyleGenerator that concerns about alignment in the grid cells.
|
||||
*/
|
||||
protected static class AlignCellStyleGenerator implements CellStyleGenerator {
|
||||
private static final long serialVersionUID = 5573570647129792429L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String[] left;
|
||||
private final String[] center;
|
||||
@@ -621,29 +625,40 @@ public abstract class AbstractGrid<T extends Indexed> extends Grid implements Re
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tooltip to the 'Date and time' column in detailed format.
|
||||
* Adds a tooltip to the 'Date and time' and 'Maintenance Window' columns in
|
||||
* detailed format.
|
||||
*/
|
||||
public static class ModifiedTimeTooltipGenerator implements CellDescriptionGenerator {
|
||||
private static final long serialVersionUID = -6617911967167729195L;
|
||||
protected static class TooltipGenerator implements CellDescriptionGenerator {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String datePropertyId;
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param datePropertyId
|
||||
*/
|
||||
public ModifiedTimeTooltipGenerator(final String datePropertyId) {
|
||||
this.datePropertyId = datePropertyId;
|
||||
public TooltipGenerator(final VaadinMessageSource i18n) {
|
||||
this.i18n = i18n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(final CellReference cell) {
|
||||
if (!datePropertyId.equals(cell.getPropertyId())) {
|
||||
final String propertyId = (String) cell.getPropertyId();
|
||||
switch (propertyId) {
|
||||
case ProxyAction.PXY_ACTION_LAST_MODIFIED_AT:
|
||||
case ProxyActionStatus.PXY_AS_CREATED_AT:
|
||||
final Long timestamp = (Long) cell.getItem().getItemProperty(propertyId).getValue();
|
||||
return SPDateTimeUtil.getFormattedDate(timestamp);
|
||||
|
||||
case ProxyAction.PXY_ACTION_MAINTENANCE_WINDOW:
|
||||
final Action action = (Action) cell.getItem().getItemProperty(ProxyAction.PXY_ACTION).getValue();
|
||||
return action.getMaintenanceWindowStartTime().map(this::getFormattedNextMaintenanceWindow).orElse(null);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
final Long timestamp = (Long) cell.getItem().getItemProperty(datePropertyId).getValue();
|
||||
return SPDateTimeUtil.getFormattedDate(timestamp);
|
||||
}
|
||||
|
||||
private String getFormattedNextMaintenanceWindow(final ZonedDateTime nextAt) {
|
||||
final long nextAtMilli = nextAt.toInstant().toEpochMilli();
|
||||
return i18n.getMessage("tooltip.next.maintenancewindow",
|
||||
SPDateTimeUtil.getFormattedDate(nextAtMilli, SPUIDefinitions.LAST_QUERY_DATE_FORMAT_SHORT));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,12 +115,19 @@ public class ActionBeanQuery extends AbstractBeanQuery<ProxyAction> {
|
||||
proxyAction.setLastModifiedAt(action.getLastModifiedAt());
|
||||
proxyAction.setRolloutName(action.getRollout() != null ? action.getRollout().getName() : "");
|
||||
proxyAction.setStatus(action.getStatus());
|
||||
proxyAction.setMaintenanceWindow(
|
||||
action.hasMaintenanceSchedule() ? buildMaintenanceWindowDisplayText(action) : "");
|
||||
|
||||
proxyActions.add(proxyAction);
|
||||
}
|
||||
return proxyActions;
|
||||
}
|
||||
|
||||
private static String buildMaintenanceWindowDisplayText(final Action action) {
|
||||
return action.getMaintenanceWindowSchedule() + "/" + action.getMaintenanceWindowDuration() + "/"
|
||||
+ action.getMaintenanceWindowTimeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a virtual IsActiveDecoration for the presentation layer that is
|
||||
* calculated from {@link Action#isActive()} and
|
||||
|
||||
@@ -78,13 +78,14 @@ public class ActionHistoryGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
|
||||
private static final Object[] maxColumnOrder = new Object[] { ProxyAction.PXY_ACTION_IS_ACTIVE_DECO,
|
||||
ProxyAction.PXY_ACTION_ID, ProxyAction.PXY_ACTION_DS_NAME_VERSION, ProxyAction.PXY_ACTION_LAST_MODIFIED_AT,
|
||||
ProxyAction.PXY_ACTION_STATUS, ProxyAction.PXY_ACTION_ROLLOUT_NAME, VIRT_PROP_FORCED, VIRT_PROP_TIMEFORCED,
|
||||
VIRT_PROP_ACTION_CANCEL, VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT };
|
||||
ProxyAction.PXY_ACTION_STATUS, ProxyAction.PXY_ACTION_MAINTENANCE_WINDOW,
|
||||
ProxyAction.PXY_ACTION_ROLLOUT_NAME, VIRT_PROP_FORCED, VIRT_PROP_TIMEFORCED, VIRT_PROP_ACTION_CANCEL,
|
||||
VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT };
|
||||
|
||||
private static final Object[] minColumnOrder = new Object[] { ProxyAction.PXY_ACTION_IS_ACTIVE_DECO,
|
||||
ProxyAction.PXY_ACTION_DS_NAME_VERSION, ProxyAction.PXY_ACTION_LAST_MODIFIED_AT,
|
||||
ProxyAction.PXY_ACTION_STATUS, VIRT_PROP_FORCED, VIRT_PROP_TIMEFORCED, VIRT_PROP_ACTION_CANCEL,
|
||||
VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT };
|
||||
ProxyAction.PXY_ACTION_STATUS, ProxyAction.PXY_ACTION_MAINTENANCE_WINDOW, VIRT_PROP_FORCED,
|
||||
VIRT_PROP_TIMEFORCED, VIRT_PROP_ACTION_CANCEL, VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT };
|
||||
|
||||
private static final String[] leftAlignedColumns = new String[] { VIRT_PROP_TIMEFORCED };
|
||||
|
||||
@@ -99,7 +100,7 @@ public class ActionHistoryGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
|
||||
private Target selectedTarget;
|
||||
private final AlignCellStyleGenerator alignGenerator;
|
||||
private final ModifiedTimeTooltipGenerator modTimetooltipGenerator;
|
||||
private final TooltipGenerator tooltipGenerator;
|
||||
|
||||
private final Map<Action.Status, StatusFontIcon> states;
|
||||
private final Map<IsActiveDecoration, StatusFontIcon> activeStates;
|
||||
@@ -139,7 +140,7 @@ public class ActionHistoryGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
activeStates = conf
|
||||
.createActiveStatusLabelConfig(UIComponentIdProvider.ACTION_HISTORY_TABLE_ACTIVESTATE_LABEL_ID);
|
||||
alignGenerator = new AlignCellStyleGenerator(leftAlignedColumns, centerAlignedColumns, rightAlignedColumns);
|
||||
modTimetooltipGenerator = new ModifiedTimeTooltipGenerator(ProxyAction.PXY_ACTION_LAST_MODIFIED_AT);
|
||||
tooltipGenerator = new TooltipGenerator(i18n);
|
||||
|
||||
init();
|
||||
}
|
||||
@@ -208,6 +209,7 @@ public class ActionHistoryGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION_ID, String.class, null, true, true);
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION_ROLLOUT_NAME, String.class, null, true, true);
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION_MAINTENANCE_WINDOW, String.class, null, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -436,11 +438,14 @@ public class ActionHistoryGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
getColumn(VIRT_PROP_ACTION_CANCEL).setHidable(false);
|
||||
getColumn(VIRT_PROP_ACTION_FORCE).setHidable(false);
|
||||
getColumn(VIRT_PROP_ACTION_FORCE_QUIT).setHidable(false);
|
||||
|
||||
getColumn(ProxyAction.PXY_ACTION_MAINTENANCE_WINDOW).setHidden(true);
|
||||
getColumn(ProxyAction.PXY_ACTION_MAINTENANCE_WINDOW).setHidable(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CellDescriptionGenerator getDescriptionGenerator() {
|
||||
return modTimetooltipGenerator;
|
||||
return tooltipGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -451,6 +456,8 @@ public class ActionHistoryGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
getColumn(ProxyAction.PXY_ACTION_DS_NAME_VERSION).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_DIST);
|
||||
getColumn(ProxyAction.PXY_ACTION_LAST_MODIFIED_AT).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_DATETIME);
|
||||
getColumn(ProxyAction.PXY_ACTION_STATUS).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_STATUS);
|
||||
getColumn(ProxyAction.PXY_ACTION_MAINTENANCE_WINDOW)
|
||||
.setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_MAINTENANCE_WINDOW);
|
||||
getColumn(VIRT_PROP_FORCED).setHeaderCaption(String.valueOf(forceClientRefreshToggle));
|
||||
forceClientRefreshToggle = !forceClientRefreshToggle;
|
||||
|
||||
@@ -463,8 +470,9 @@ public class ActionHistoryGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
protected void setColumnExpandRatio() {
|
||||
setColumnsSize(50.0, 50.0, ProxyAction.PXY_ACTION_IS_ACTIVE_DECO);
|
||||
setColumnsSize(107.0, 500.0, ProxyAction.PXY_ACTION_DS_NAME_VERSION);
|
||||
setColumnsSize(100.0, 120.0, ProxyAction.PXY_ACTION_LAST_MODIFIED_AT);
|
||||
setColumnsSize(100.0, 130.0, ProxyAction.PXY_ACTION_LAST_MODIFIED_AT);
|
||||
setColumnsSize(53.0, 55.0, ProxyAction.PXY_ACTION_STATUS);
|
||||
setColumnsSize(150.0, 200.0, ProxyAction.PXY_ACTION_MAINTENANCE_WINDOW);
|
||||
setColumnsSize(FIXED_PIX_MIN, FIXED_PIX_MIN, VIRT_PROP_FORCED, VIRT_PROP_TIMEFORCED, VIRT_PROP_ACTION_CANCEL,
|
||||
VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ActionStatusGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
private static final String[] centerAlignedColumns = new String[] { ProxyActionStatus.PXY_AS_STATUS };
|
||||
|
||||
private final AlignCellStyleGenerator alignGenerator;
|
||||
private final ModifiedTimeTooltipGenerator modTimetooltipGenerator;
|
||||
private final TooltipGenerator tooltipGenerator;
|
||||
|
||||
private final Map<Action.Status, StatusFontIcon> states;
|
||||
|
||||
@@ -58,7 +58,7 @@ public class ActionStatusGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
final LabelConfig conf = new ActionHistoryGrid.LabelConfig();
|
||||
states = conf.createStatusLabelConfig(i18n, UIComponentIdProvider.ACTION_STATUS_GRID_STATUS_LABEL_ID);
|
||||
alignGenerator = new AlignCellStyleGenerator(leftAlignedColumns, centerAlignedColumns, null);
|
||||
modTimetooltipGenerator = new ModifiedTimeTooltipGenerator(ProxyActionStatus.PXY_AS_CREATED_AT);
|
||||
tooltipGenerator = new TooltipGenerator(i18n);
|
||||
|
||||
init();
|
||||
}
|
||||
@@ -153,7 +153,7 @@ public class ActionStatusGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
|
||||
@Override
|
||||
protected CellDescriptionGenerator getDescriptionGenerator() {
|
||||
return modTimetooltipGenerator;
|
||||
return tooltipGenerator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public class ProxyAction implements Serializable {
|
||||
public static final String PXY_ACTION = "action";
|
||||
public static final String PXY_ACTION_LAST_MODIFIED_AT = "lastModifiedAt";
|
||||
public static final String PXY_ACTION_ROLLOUT_NAME = "rolloutName";
|
||||
public static final String PXY_ACTION_MAINTENANCE_WINDOW = "maintenanceWindow";
|
||||
|
||||
private Action.Status status;
|
||||
private boolean isActive;
|
||||
@@ -35,6 +36,15 @@ public class ProxyAction implements Serializable {
|
||||
private Action action;
|
||||
private Long lastModifiedAt;
|
||||
private String rolloutName;
|
||||
private String maintenanceWindow;
|
||||
|
||||
public String getMaintenanceWindow() {
|
||||
return maintenanceWindow;
|
||||
}
|
||||
|
||||
public void setMaintenanceWindow(final String maintenanceWindow) {
|
||||
this.maintenanceWindow = maintenanceWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id for the entry.
|
||||
@@ -51,7 +61,7 @@ public class ProxyAction implements Serializable {
|
||||
* @param id
|
||||
* of the action entry.
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@@ -70,7 +80,7 @@ public class ProxyAction implements Serializable {
|
||||
* @param status
|
||||
* literal
|
||||
*/
|
||||
public void setStatus(Action.Status status) {
|
||||
public void setStatus(final Action.Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@@ -91,7 +101,7 @@ public class ProxyAction implements Serializable {
|
||||
* <code>true</code> if the action is active, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public void setActive(boolean isActive) {
|
||||
public void setActive(final boolean isActive) {
|
||||
this.isActive = isActive;
|
||||
}
|
||||
|
||||
@@ -113,7 +123,7 @@ public class ProxyAction implements Serializable {
|
||||
* @param isActiveDecoration
|
||||
* pre-calculated literal
|
||||
*/
|
||||
public void setIsActiveDecoration(IsActiveDecoration isActiveDecoration) {
|
||||
public void setIsActiveDecoration(final IsActiveDecoration isActiveDecoration) {
|
||||
this.isActiveDecoration = isActiveDecoration;
|
||||
}
|
||||
|
||||
@@ -133,7 +143,7 @@ public class ProxyAction implements Serializable {
|
||||
* @param dsNameVersion
|
||||
* combined value
|
||||
*/
|
||||
public void setDsNameVersion(String dsNameVersion) {
|
||||
public void setDsNameVersion(final String dsNameVersion) {
|
||||
this.dsNameVersion = dsNameVersion;
|
||||
}
|
||||
|
||||
@@ -151,7 +161,7 @@ public class ProxyAction implements Serializable {
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
public void setAction(Action action) {
|
||||
public void setAction(final Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@@ -170,7 +180,7 @@ public class ProxyAction implements Serializable {
|
||||
* @param lastModifiedAt
|
||||
* raw long-value for lastModifiedAt-date
|
||||
*/
|
||||
public void setLastModifiedAt(Long lastModifiedAt) {
|
||||
public void setLastModifiedAt(final Long lastModifiedAt) {
|
||||
this.lastModifiedAt = lastModifiedAt;
|
||||
}
|
||||
|
||||
@@ -188,7 +198,7 @@ public class ProxyAction implements Serializable {
|
||||
*
|
||||
* @param rolloutName
|
||||
*/
|
||||
public void setRolloutName(String rolloutName) {
|
||||
public void setRolloutName(final String rolloutName) {
|
||||
this.rolloutName = rolloutName;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ public class MaintenanceWindowLayout extends VerticalLayout {
|
||||
* Text field to specify the schedule.
|
||||
*/
|
||||
private void createMaintenanceScheduleControl() {
|
||||
schedule = new TextFieldBuilder(Action.MAINTENANCE_SCHEDULE_CRON_LENGTH)
|
||||
schedule = new TextFieldBuilder(Action.MAINTENANCE_WINDOW_SCHEDULE_LENGTH)
|
||||
.id(UIComponentIdProvider.MAINTENANCE_WINDOW_SCHEDULE_ID)
|
||||
.caption(i18n.getMessage("caption.maintenancewindow.schedule")).validator(new CronValidator())
|
||||
.prompt("0 0 3 ? * 6").required(true, i18n).buildTextComponent();
|
||||
@@ -259,6 +259,7 @@ public class MaintenanceWindowLayout extends VerticalLayout {
|
||||
schedule.setValue("");
|
||||
duration.setValue("");
|
||||
timeZone.setValue(getClientTimeZone());
|
||||
scheduleTranslator.setValue(i18n.getMessage(CRON_VALIDATION_ERROR));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -561,6 +561,8 @@ public final class SPUIDefinitions {
|
||||
*/
|
||||
public static final String SP_BUTTON_STATUS_STYLE = "targetStatusBtn";
|
||||
|
||||
public static final String ACTION_HIS_TBL_MAINTENANCE_WINDOW = "Maintenance Window";
|
||||
|
||||
/**
|
||||
* /** Constructor.
|
||||
*/
|
||||
|
||||
@@ -251,6 +251,7 @@ tooltip.check.for.mandatory=Check to make Mandatory
|
||||
tooltip.artifact.icon=Show Artifact Details
|
||||
tooltip.click.to.edit = Click to edit
|
||||
tooltip.metadata.icon = Manage Metadata
|
||||
tooltip.next.maintenancewindow = next on {0}
|
||||
#rollout action
|
||||
tooltip.rollout.run = Run
|
||||
tooltip.rollout.pause = Pause
|
||||
|
||||
Reference in New Issue
Block a user