aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extra/sql/bulkload/create-tables.sql1
-rw-r--r--src/main/java/org/onap/clamp/clds/service/CldsDictionaryService.java58
-rw-r--r--src/main/java/org/onap/clamp/loop/Loop.java39
-rw-r--r--src/main/java/org/onap/clamp/loop/LoopCsarInstaller.java68
-rw-r--r--src/main/java/org/onap/clamp/policy/operational/LegacyOperationalPolicy.java37
-rw-r--r--src/main/java/org/onap/clamp/policy/operational/OperationalPolicy.java37
-rw-r--r--src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java146
-rw-r--r--src/main/resources/clds/json-schema/operational_policies/operational_policy.json362
-rw-r--r--src/test/java/org/onap/clamp/clds/it/CldsDictionaryServiceItCase.java72
-rw-r--r--src/test/java/org/onap/clamp/policy/microservice/OperationalPolicyPayloadTest.java20
-rw-r--r--src/test/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilderTest.java52
-rw-r--r--src/test/resources/clds/OperationalPolicyRepresentationBuilderTest.java52
-rw-r--r--src/test/resources/tosca/guard1-policy-payload.json19
-rw-r--r--src/test/resources/tosca/guard2-policy-payload.json20
-rw-r--r--src/test/resources/tosca/operational-policy-json-schema.json574
-rw-r--r--src/test/resources/tosca/operational-policy-payload-legacy.yaml52
-rw-r--r--src/test/resources/tosca/operational-policy-payload.json2
-rw-r--r--src/test/resources/tosca/operational-policy-payload.yaml60
-rw-r--r--src/test/resources/tosca/operational-policy-properties.json149
-rw-r--r--src/test/resources/tosca/pdp-group-policy-payload.json4
-rw-r--r--ui-react/package.json2
-rw-r--r--ui-react/src/LoopUI.js32
-rw-r--r--ui-react/src/api/LoopActionService.js74
-rw-r--r--ui-react/src/api/LoopCache.js4
-rw-r--r--ui-react/src/api/LoopService.js24
-rw-r--r--ui-react/src/components/dialogs/ConfigurationPolicy/ConfigurationPolicyModal.js2
-rw-r--r--ui-react/src/components/dialogs/DeployLoop.js128
-rw-r--r--ui-react/src/components/dialogs/LoopProperties.js7
-rw-r--r--ui-react/src/components/dialogs/OperationalPolicy/OperationalPolicyModal.js533
-rw-r--r--ui-react/src/components/dialogs/PerformActions.js85
-rw-r--r--ui-react/src/components/dialogs/RefreshStatus.js66
-rw-r--r--ui-react/src/components/loop_viewer/svg/LoopSvg.js17
-rw-r--r--ui-react/src/components/menu/MenuBar.js71
-rw-r--r--ui-react/src/index.js2
-rw-r--r--ui-react/src/theme/globalStyle.js13
35 files changed, 2067 insertions, 817 deletions
diff --git a/extra/sql/bulkload/create-tables.sql b/extra/sql/bulkload/create-tables.sql
index 121c5e689..aef3a7e7d 100644
--- a/extra/sql/bulkload/create-tables.sql
+++ b/extra/sql/bulkload/create-tables.sql
@@ -24,6 +24,7 @@
global_properties_json json,
last_computed_state varchar(255) not null,
model_properties_json json,
+ operational_policy_schema json not null,
svg_representation MEDIUMTEXT,
primary key (name)
) engine=InnoDB;
diff --git a/src/main/java/org/onap/clamp/clds/service/CldsDictionaryService.java b/src/main/java/org/onap/clamp/clds/service/CldsDictionaryService.java
index c228e171a..454056cd3 100644
--- a/src/main/java/org/onap/clamp/clds/service/CldsDictionaryService.java
+++ b/src/main/java/org/onap/clamp/clds/service/CldsDictionaryService.java
@@ -60,47 +60,73 @@ public class CldsDictionaryService extends SecureServiceBase {
@PostConstruct
- private final void initConstruct() {
+ private void initConstruct() {
permissionReadTosca = SecureServicePermission.create(cldsPermissionTypeTosca, cldsPermissionInstance, "read");
permissionUpdateTosca = SecureServicePermission.create(cldsPermissionTypeTosca, cldsPermissionInstance,
"update");
}
/**
- * REST Service that creates or Updates a Dictionary.
- *
+ * REST Service that creates a Dictionary.
+ *
* @param dictionaryName dictionary name
- * @param cldsDictionary clds dictionary
* @return CldsDictionary that was created in DB.
*/
+ public CldsDictionary createDictionary(String dictionaryName) {
+ CldsDictionary cldsDictionary = new CldsDictionary();
+ cldsDictionary.setDictionaryName(dictionaryName);
+ cldsDictionary.save(cldsDictionary.getDictionaryName(), cldsDao, getUserId());
+ return cldsDictionary;
+ }
+
+ /**
+ * REST Service that creates or Updates a Dictionary.
+ * Used in clds-services.xml
+ *
+ * @param cldsDictionary clds dictionary
+ * @return ResponseEntity with CldsDictionary that was created in DB.
+ */
public ResponseEntity<CldsDictionary> createOrUpdateDictionary(String dictionaryName,
- CldsDictionary cldsDictionary) {
- final Date startTime = new Date();
+ CldsDictionary cldsDictionary) {
+
+ Date startTime = new Date();
LoggingUtils.setRequestContext("CldsDictionaryService: createOrUpdateDictionary", getPrincipalName());
// TODO revisit based on new permissions
isAuthorized(permissionUpdateTosca);
+
if (cldsDictionary == null) {
- cldsDictionary = new CldsDictionary();
- cldsDictionary.setDictionaryName(dictionaryName);
+
+ cldsDictionary = createDictionary(dictionaryName);
+ } else {
+
+ if (cldsDictionary.getDictionaryName() == null) {
+ cldsDictionary.setDictionaryName(dictionaryName);
+ }
+
+ cldsDictionary.save(cldsDictionary.getDictionaryName(), cldsDao, getUserId());
}
- cldsDictionary.save(dictionaryName, cldsDao, getUserId());
- auditLogInfo("createOrUpdateDictionary", startTime);
+
+ LoggingUtils.setTimeContext(startTime, new Date());
+ LoggingUtils.setResponseContext("0", "createOrUpdateDictionary success", this.getClass().getName());
+ auditLogger.info("createOrUpdateDictionary completed");
+
return new ResponseEntity<>(cldsDictionary, HttpStatus.OK);
}
/**
* REST Service that creates or Updates a Dictionary Elements for dictionary
* in DB.
- *
+ *
* @param dictionaryName dictionary name
* @param dictionaryItem dictionary item
* @return CldsDictionaryItem A dictionary items that was created or updated
* in DB
*/
public ResponseEntity<CldsDictionaryItem> createOrUpdateDictionaryElements(String dictionaryName,
- CldsDictionaryItem dictionaryItem) {
+ CldsDictionaryItem dictionaryItem) {
final Date startTime = new Date();
- LoggingUtils.setRequestContext("CldsDictionaryService: createOrUpdateDictionaryElements", getPrincipalName());
+ LoggingUtils.setRequestContext("CldsDictionaryService: createOrUpdateDictionaryElements",
+ getPrincipalName());
// TODO revisit based on new permissions
isAuthorized(permissionUpdateTosca);
dictionaryItem.save(dictionaryName, cldsDao, getUserId());
@@ -110,7 +136,7 @@ public class CldsDictionaryService extends SecureServiceBase {
/**
* Rest Service that retrieves all CLDS dictionary in DB.
- *
+ *
* @return CldsDictionary List List of CldsDictionary available in DB
*/
public ResponseEntity<List<CldsDictionary>> getAllDictionaryNames() {
@@ -126,7 +152,7 @@ public class CldsDictionaryService extends SecureServiceBase {
/**
* Rest Service that retrieves all CLDS dictionary items in DB for a give
* dictionary name.
- *
+ *
* @param dictionaryName dictionary name
* @return CldsDictionaryItem list List of CLDS Dictionary items for a given
* dictionary name
@@ -150,4 +176,4 @@ public class CldsDictionaryService extends SecureServiceBase {
util = utilP;
}
-}
+} \ No newline at end of file
diff --git a/src/main/java/org/onap/clamp/loop/Loop.java b/src/main/java/org/onap/clamp/loop/Loop.java
index 2393f2498..37d597eeb 100644
--- a/src/main/java/org/onap/clamp/loop/Loop.java
+++ b/src/main/java/org/onap/clamp/loop/Loop.java
@@ -23,9 +23,13 @@
package org.onap.clamp.loop;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.Expose;
+import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
@@ -59,6 +63,7 @@ import org.onap.clamp.loop.components.external.PolicyComponent;
import org.onap.clamp.loop.log.LoopLog;
import org.onap.clamp.policy.microservice.MicroServicePolicy;
import org.onap.clamp.policy.operational.OperationalPolicy;
+import org.onap.clamp.policy.operational.OperationalPolicyRepresentationBuilder;
@Entity
@Table(name = "loops")
@@ -70,6 +75,9 @@ public class Loop implements Serializable {
*/
private static final long serialVersionUID = -286522707701388642L;
+ @Transient
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(Loop.class);
+
@Id
@Expose
@Column(nullable = false, name = "name", unique = true)
@@ -92,6 +100,11 @@ public class Loop implements Serializable {
@Expose
@Type(type = "json")
+ @Column(columnDefinition = "json", name = "operational_policy_schema")
+ private JsonObject operationalPolicySchema;
+
+ @Expose
+ @Type(type = "json")
@Column(columnDefinition = "json", name = "global_properties_json")
private JsonObject globalPropertiesJson;
@@ -131,6 +144,9 @@ public class Loop implements Serializable {
this.addComponent(new DcaeComponent());
}
+ /**
+ * Public constructor.
+ */
public Loop() {
initializeExternalComponents();
}
@@ -256,6 +272,13 @@ public class Loop implements Serializable {
void setModelPropertiesJson(JsonObject modelPropertiesJson) {
this.modelPropertiesJson = modelPropertiesJson;
+ try {
+ this.operationalPolicySchema = OperationalPolicyRepresentationBuilder
+ .generateOperationalPolicySchema(this.getModelPropertiesJson());
+ } catch (JsonSyntaxException | IOException | NullPointerException e) {
+ logger.error("Unable to generate the operational policy Schema ... ", e);
+ this.operationalPolicySchema = new JsonObject();
+ }
}
public Map<String, ExternalComponent> getComponents() {
@@ -273,20 +296,16 @@ public class Loop implements Serializable {
/**
* Generate the loop name.
*
- * @param serviceName
- * The service name
- * @param serviceVersion
- * The service version
- * @param resourceName
- * The resource name
- * @param blueprintFileName
- * The blueprint file name
+ * @param serviceName The service name
+ * @param serviceVersion The service version
+ * @param resourceName The resource name
+ * @param blueprintFileName The blueprint file name
* @return The generated loop name
*/
static String generateLoopName(String serviceName, String serviceVersion, String resourceName,
- String blueprintFilename) {
+ String blueprintFilename) {
StringBuilder buffer = new StringBuilder("LOOP_").append(serviceName).append("_v").append(serviceVersion)
- .append("_").append(resourceName).append("_").append(blueprintFilename.replaceAll(".yaml", ""));
+ .append("_").append(resourceName).append("_").append(blueprintFilename.replaceAll(".yaml", ""));
return buffer.toString().replace('.', '_').replaceAll(" ", "");
}
diff --git a/src/main/java/org/onap/clamp/loop/LoopCsarInstaller.java b/src/main/java/org/onap/clamp/loop/LoopCsarInstaller.java
index ad13ad34d..41d34a224 100644
--- a/src/main/java/org/onap/clamp/loop/LoopCsarInstaller.java
+++ b/src/main/java/org/onap/clamp/loop/LoopCsarInstaller.java
@@ -99,10 +99,10 @@ public class LoopCsarInstaller implements CsarInstaller {
boolean alreadyInstalled = true;
for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) {
alreadyInstalled = alreadyInstalled
- && loopRepository.existsById(Loop.generateLoopName(csar.getSdcNotification().getServiceName(),
- csar.getSdcNotification().getServiceVersion(),
- blueprint.getValue().getResourceAttached().getResourceInstanceName(),
- blueprint.getValue().getBlueprintArtifactName()));
+ && loopRepository.existsById(Loop.generateLoopName(csar.getSdcNotification().getServiceName(),
+ csar.getSdcNotification().getServiceVersion(),
+ blueprint.getValue().getResourceAttached().getResourceInstanceName(),
+ blueprint.getValue().getBlueprintArtifactName()));
}
return alreadyInstalled;
}
@@ -110,7 +110,7 @@ public class LoopCsarInstaller implements CsarInstaller {
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void installTheCsar(CsarHandler csar)
- throws SdcArtifactInstallerException, InterruptedException, PolicyModelException {
+ throws SdcArtifactInstallerException, InterruptedException, PolicyModelException {
try {
logger.info("Installing the CSAR " + csar.getFilePath());
for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) {
@@ -126,53 +126,53 @@ public class LoopCsarInstaller implements CsarInstaller {
}
private Loop createLoopFromBlueprint(CsarHandler csar, BlueprintArtifact blueprintArtifact)
- throws IOException, ParseException, InterruptedException {
+ throws IOException, ParseException, InterruptedException {
Loop newLoop = new Loop();
newLoop.setBlueprint(blueprintArtifact.getDcaeBlueprint());
newLoop.setName(Loop.generateLoopName(csar.getSdcNotification().getServiceName(),
- csar.getSdcNotification().getServiceVersion(),
- blueprintArtifact.getResourceAttached().getResourceInstanceName(),
- blueprintArtifact.getBlueprintArtifactName()));
+ csar.getSdcNotification().getServiceVersion(),
+ blueprintArtifact.getResourceAttached().getResourceInstanceName(),
+ blueprintArtifact.getBlueprintArtifactName()));
newLoop.setLastComputedState(LoopState.DESIGN);
List<MicroService> microServicesChain = chainGenerator
- .getChainOfMicroServices(blueprintParser.getMicroServices(blueprintArtifact.getDcaeBlueprint()));
+ .getChainOfMicroServices(blueprintParser.getMicroServices(blueprintArtifact.getDcaeBlueprint()));
if (microServicesChain.isEmpty()) {
microServicesChain = blueprintParser.fallbackToOneMicroService(blueprintArtifact.getDcaeBlueprint());
}
-
- newLoop
- .setMicroServicePolicies(createMicroServicePolicies(microServicesChain, csar, blueprintArtifact, newLoop));
+ newLoop.setModelPropertiesJson(createModelPropertiesJson(csar));
+ newLoop.setMicroServicePolicies(
+ createMicroServicePolicies(microServicesChain, csar, blueprintArtifact, newLoop));
newLoop.setOperationalPolicies(createOperationalPolicies(csar, blueprintArtifact, newLoop));
newLoop.setSvgRepresentation(svgFacade.getSvgImage(microServicesChain));
newLoop.setGlobalPropertiesJson(createGlobalPropertiesJson(blueprintArtifact, newLoop));
- newLoop.setModelPropertiesJson(createModelPropertiesJson(csar));
+
DcaeInventoryResponse dcaeResponse = queryDcaeToGetServiceTypeId(blueprintArtifact);
newLoop.setDcaeBlueprintId(dcaeResponse.getTypeId());
return newLoop;
}
private HashSet<OperationalPolicy> createOperationalPolicies(CsarHandler csar, BlueprintArtifact blueprintArtifact,
- Loop newLoop) {
+ Loop newLoop) {
return new HashSet<>(Arrays.asList(new OperationalPolicy(Policy.generatePolicyName("OPERATIONAL",
- csar.getSdcNotification().getServiceName(), csar.getSdcNotification().getServiceVersion(),
- blueprintArtifact.getResourceAttached().getResourceInstanceName(),
- blueprintArtifact.getBlueprintArtifactName()), newLoop, new JsonObject())));
+ csar.getSdcNotification().getServiceName(), csar.getSdcNotification().getServiceVersion(),
+ blueprintArtifact.getResourceAttached().getResourceInstanceName(),
+ blueprintArtifact.getBlueprintArtifactName()), newLoop, new JsonObject())));
}
private HashSet<MicroServicePolicy> createMicroServicePolicies(List<MicroService> microServicesChain,
- CsarHandler csar, BlueprintArtifact blueprintArtifact, Loop newLoop) throws IOException {
+ CsarHandler csar, BlueprintArtifact blueprintArtifact, Loop newLoop) throws IOException {
HashSet<MicroServicePolicy> newSet = new HashSet<>();
for (MicroService microService : microServicesChain) {
MicroServicePolicy microServicePolicy = new MicroServicePolicy(
- Policy.generatePolicyName(microService.getName(), csar.getSdcNotification().getServiceName(),
- csar.getSdcNotification().getServiceVersion(),
- blueprintArtifact.getResourceAttached().getResourceInstanceName(),
- blueprintArtifact.getBlueprintArtifactName()),
- microService.getModelType(), csar.getPolicyModelYaml().orElse(""), false,
- new HashSet<>(Arrays.asList(newLoop)));
+ Policy.generatePolicyName(microService.getName(), csar.getSdcNotification().getServiceName(),
+ csar.getSdcNotification().getServiceVersion(),
+ blueprintArtifact.getResourceAttached().getResourceInstanceName(),
+ blueprintArtifact.getBlueprintArtifactName()),
+ microService.getModelType(), csar.getPolicyModelYaml().orElse(""), false,
+ new HashSet<>(Arrays.asList(newLoop)));
newSet.add(microServicePolicy);
microService.setMappedNameJpa(microServicePolicy.getName());
@@ -191,8 +191,8 @@ public class LoopCsarInstaller implements CsarInstaller {
// Loop on all Groups defined in the service (VFModule entries type:
// org.openecomp.groups.VfModule)
for (IEntityDetails entity : csar.getSdcCsarHelper().getEntity(
- EntityQuery.newBuilder(EntityTemplateType.GROUP).build(),
- TopologyTemplateQuery.newBuilder(SdcTypes.SERVICE).build(), false)) {
+ EntityQuery.newBuilder(EntityTemplateType.GROUP).build(),
+ TopologyTemplateQuery.newBuilder(SdcTypes.SERVICE).build(), false)) {
// Get all metadata info
JsonObject allVfProps = (JsonObject) JsonUtils.GSON.toJsonTree(entity.getMetadata().getAllProperties());
vfModuleProps.add(entity.getMetadata().getAllProperties().get("vfModuleModelName"), allVfProps);
@@ -200,7 +200,7 @@ public class LoopCsarInstaller implements CsarInstaller {
// volume_group, etc ... fields under the VFmodule name
for (Entry<String, Property> additionalProp : entity.getProperties().entrySet()) {
allVfProps.add(additionalProp.getValue().getName(),
- JsonUtils.GSON.toJsonTree(additionalProp.getValue().getValue()));
+ JsonUtils.GSON.toJsonTree(additionalProp.getValue().getValue()));
}
}
return vfModuleProps;
@@ -214,7 +214,7 @@ public class LoopCsarInstaller implements CsarInstaller {
// For each type, get the metadata of each nodetemplate
for (NodeTemplate nodeTemplate : csar.getSdcCsarHelper().getServiceNodeTemplateBySdcType(type)) {
resourcesPropByType.add(nodeTemplate.getName(),
- JsonUtils.GSON.toJsonTree(nodeTemplate.getMetaData().getAllProperties()));
+ JsonUtils.GSON.toJsonTree(nodeTemplate.getMetaData().getAllProperties()));
}
resourcesProp.add(type.getValue(), resourcesPropByType);
}
@@ -225,7 +225,7 @@ public class LoopCsarInstaller implements CsarInstaller {
JsonObject modelProperties = new JsonObject();
// Add service details
modelProperties.add("serviceDetails", JsonUtils.GSON.fromJson(
- JsonUtils.GSON.toJson(csar.getSdcCsarHelper().getServiceMetadataAllProperties()), JsonObject.class));
+ JsonUtils.GSON.toJson(csar.getSdcCsarHelper().getServiceMetadataAllProperties()), JsonObject.class));
// Add properties details for each type, VfModule, VF, VFC, ....
JsonObject resourcesProp = createServicePropertiesByType(csar);
resourcesProp.add("VFModule", createVfModuleProperties(csar));
@@ -237,7 +237,7 @@ public class LoopCsarInstaller implements CsarInstaller {
JsonObject node = new JsonObject();
Yaml yaml = new Yaml();
Map<String, Object> inputsNodes = ((Map<String, Object>) ((Map<String, Object>) yaml
- .load(blueprintArtifact.getDcaeBlueprint())).get("inputs"));
+ .load(blueprintArtifact.getDcaeBlueprint())).get("inputs"));
inputsNodes.entrySet().stream().filter(e -> !e.getKey().contains("policy_id")).forEach(elem -> {
Object defaultValue = ((Map<String, Object>) elem.getValue()).get("default");
if (defaultValue != null) {
@@ -258,10 +258,10 @@ public class LoopCsarInstaller implements CsarInstaller {
* @return The DcaeInventoryResponse object containing the dcae values
*/
private DcaeInventoryResponse queryDcaeToGetServiceTypeId(BlueprintArtifact blueprintArtifact)
- throws IOException, ParseException, InterruptedException {
+ throws IOException, ParseException, InterruptedException {
return dcaeInventoryService.getDcaeInformation(blueprintArtifact.getBlueprintArtifactName(),
- blueprintArtifact.getBlueprintInvariantServiceUuid(),
- blueprintArtifact.getResourceAttached().getResourceInvariantUUID());
+ blueprintArtifact.getBlueprintInvariantServiceUuid(),
+ blueprintArtifact.getResourceAttached().getResourceInvariantUUID());
}
private void addPropertyToNode(JsonObject node, String key, Object value) {
diff --git a/src/main/java/org/onap/clamp/policy/operational/LegacyOperationalPolicy.java b/src/main/java/org/onap/clamp/policy/operational/LegacyOperationalPolicy.java
index 33148f0b6..dd156d8f3 100644
--- a/src/main/java/org/onap/clamp/policy/operational/LegacyOperationalPolicy.java
+++ b/src/main/java/org/onap/clamp/policy/operational/LegacyOperationalPolicy.java
@@ -25,6 +25,7 @@ package org.onap.clamp.policy.operational;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.List;
@@ -33,16 +34,15 @@ import java.util.Map.Entry;
import java.util.TreeMap;
import org.apache.commons.lang3.math.NumberUtils;
+import org.onap.clamp.loop.Loop;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
import org.yaml.snakeyaml.Yaml;
/**
- *
* This class contains the code required to support the sending of Legacy
* operational payload to policy engine. This will probably disappear in El
* Alto.
- *
*/
public class LegacyOperationalPolicy {
@@ -76,6 +76,13 @@ public class LegacyOperationalPolicy {
return jsonElement;
}
+ /**
+ * This method rework the payload attribute (yaml) that is normally wrapped in a
+ * string when coming from the UI.
+ *
+ * @param policyJson The operational policy json config
+ * @return The same object reference but modified
+ */
public static JsonElement reworkPayloadAttributes(JsonElement policyJson) {
for (JsonElement policy : policyJson.getAsJsonObject().get("policies").getAsJsonArray()) {
JsonElement payloadElem = policy.getAsJsonObject().get("payload");
@@ -135,9 +142,15 @@ public class LegacyOperationalPolicy {
return mapResult;
}
+ /**
+ * This method transforms the configuration json to a Yaml format.
+ *
+ * @param operationalPolicyJsonElement The operational policy json config
+ * @return The Yaml as string
+ */
public static String createPolicyPayloadYamlLegacy(JsonElement operationalPolicyJsonElement) {
JsonElement opPolicy = fulfillPoliciesTreeField(
- removeAllQuotes(reworkPayloadAttributes(operationalPolicyJsonElement.getAsJsonObject().deepCopy())));
+ removeAllQuotes(reworkPayloadAttributes(operationalPolicyJsonElement.getAsJsonObject().deepCopy())));
Map<?, ?> jsonMap = createMap(opPolicy);
DumperOptions options = new DumperOptions();
options.setDefaultScalarStyle(ScalarStyle.PLAIN);
@@ -147,4 +160,22 @@ public class LegacyOperationalPolicy {
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
return (new Yaml(options)).dump(jsonMap);
}
+
+ /**
+ * This method load mandatory field in the operational policy configuration
+ * JSON.
+ *
+ * @param configurationsJson The operational policy JSON
+ * @param loop The parent loop object
+ */
+ public static void preloadConfiguration(JsonObject configurationsJson, Loop loop) {
+ if (configurationsJson.entrySet().isEmpty()) {
+ JsonObject controlLoopName = new JsonObject();
+ controlLoopName.addProperty("controlLoopName",
+ loop != null ? loop.getName() : "Empty (NO loop loaded yet)");
+ JsonObject controlLoop = new JsonObject();
+ controlLoop.add("controlLoop", controlLoopName);
+ configurationsJson.add("operational_policy", controlLoop);
+ }
+ }
}
diff --git a/src/main/java/org/onap/clamp/policy/operational/OperationalPolicy.java b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicy.java
index 62c5a1e9f..86f8ac391 100644
--- a/src/main/java/org/onap/clamp/policy/operational/OperationalPolicy.java
+++ b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicy.java
@@ -38,7 +38,6 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
-import java.util.Map.Entry;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -91,17 +90,16 @@ public class OperationalPolicy implements Serializable, Policy {
/**
* The constructor.
*
- * @param name
- * The name of the operational policy
- * @param loop
- * The loop that uses this operational policy
- * @param configurationsJson
- * The operational policy property in the format of json
+ * @param name The name of the operational policy
+ * @param loop The loop that uses this operational policy
+ * @param configurationsJson The operational policy property in the format of
+ * json
*/
public OperationalPolicy(String name, Loop loop, JsonObject configurationsJson) {
this.name = name;
this.loop = loop;
this.configurationsJson = configurationsJson;
+ LegacyOperationalPolicy.preloadConfiguration(this.configurationsJson, loop);
}
@Override
@@ -117,11 +115,6 @@ public class OperationalPolicy implements Serializable, Policy {
return loop;
}
- @Override
- public JsonObject getJsonRepresentation() {
- return configurationsJson;
- }
-
public JsonObject getConfigurationsJson() {
return configurationsJson;
}
@@ -131,6 +124,11 @@ public class OperationalPolicy implements Serializable, Policy {
}
@Override
+ public JsonObject getJsonRepresentation() {
+ return null;
+ }
+
+ @Override
public int hashCode() {
final int prime = 31;
int result = 1;
@@ -184,7 +182,7 @@ public class OperationalPolicy implements Serializable, Policy {
metadata.addProperty("policy-id", this.name);
operationalPolicyDetails.add("properties", LegacyOperationalPolicy
- .reworkPayloadAttributes(this.configurationsJson.get("operational_policy").deepCopy()));
+ .reworkPayloadAttributes(this.configurationsJson.get("operational_policy").deepCopy()));
Gson gson = new GsonBuilder().create();
@@ -204,9 +202,8 @@ public class OperationalPolicy implements Serializable, Policy {
// Now using the legacy payload fo Dublin
JsonObject payload = new JsonObject();
payload.addProperty("policy-id", this.getName());
- payload.addProperty("content", URLEncoder.encode(
- LegacyOperationalPolicy.createPolicyPayloadYamlLegacy(this.configurationsJson.get("operational_policy")),
- StandardCharsets.UTF_8.toString()));
+ payload.addProperty("content", URLEncoder.encode(LegacyOperationalPolicy.createPolicyPayloadYamlLegacy(
+ this.configurationsJson.get("operational_policy")), StandardCharsets.UTF_8.toString()));
String opPayload = new GsonBuilder().setPrettyPrinting().create().toJson(payload);
logger.info("Operational policy payload: " + opPayload);
return opPayload;
@@ -222,11 +219,9 @@ public class OperationalPolicy implements Serializable, Policy {
JsonElement guardsList = this.getConfigurationsJson().get("guard_policies");
if (guardsList != null) {
- for (Entry<String, JsonElement> guardElem : guardsList.getAsJsonObject().entrySet()) {
- JsonObject guard = new JsonObject();
- guard.addProperty("policy-id", guardElem.getKey());
- guard.add("content", guardElem.getValue());
- result.put(guardElem.getKey(), new GsonBuilder().create().toJson(guard));
+ for (JsonElement guardElem : guardsList.getAsJsonArray()) {
+ result.put(guardElem.getAsJsonObject().get("policy-id").getAsString(),
+ new GsonBuilder().create().toJson(guardElem));
}
}
logger.info("Guard policy payload: " + result);
diff --git a/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java
new file mode 100644
index 000000000..f6f3f498d
--- /dev/null
+++ b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java
@@ -0,0 +1,146 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.clamp.policy.operational;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+
+import java.io.IOException;
+import java.util.Map.Entry;
+
+import org.onap.clamp.clds.util.JsonUtils;
+import org.onap.clamp.clds.util.ResourceFileUtil;
+
+public class OperationalPolicyRepresentationBuilder {
+
+ /**
+ * This method generates the operational policy json representation that will be
+ * used by ui for rendering. It uses the model (VF and VFModule) defined in the
+ * loop object to do so, so it's dynamic. It also uses the operational policy
+ * schema template defined in the resource folder.
+ *
+ * @param modelJson The loop model json
+ * @return The json representation
+ * @throws JsonSyntaxException If the schema template cannot be parsed
+ * @throws IOException In case of issue when opening the schema template
+ */
+ public static JsonObject generateOperationalPolicySchema(JsonObject modelJson)
+ throws JsonSyntaxException, IOException {
+ JsonObject jsonSchema = JsonUtils.GSON.fromJson(
+ ResourceFileUtil.getResourceAsString("clds/json-schema/operational_policies/operational_policy.json"),
+ JsonObject.class);
+ jsonSchema.get("schema").getAsJsonObject().get("items").getAsJsonObject().get("properties").getAsJsonObject()
+ .get("configurationsJson").getAsJsonObject().get("properties").getAsJsonObject()
+ .get("operational_policy").getAsJsonObject().get("properties").getAsJsonObject().get("policies")
+ .getAsJsonObject().get("items").getAsJsonObject().get("properties").getAsJsonObject().get("target")
+ .getAsJsonObject().get("anyOf").getAsJsonArray().addAll(createAnyOfArray(modelJson));
+ return jsonSchema;
+ }
+
+ private static JsonObject createSchemaProperty(String title, String type, String defaultValue, String readOnlyFlag,
+ String[] enumArray) {
+ JsonObject property = new JsonObject();
+ property.addProperty("title", title);
+ property.addProperty("type", type);
+ property.addProperty("default", defaultValue);
+ property.addProperty("readOnly", readOnlyFlag);
+
+ if (enumArray != null) {
+ JsonArray jsonArray = new JsonArray();
+ property.add("enum", jsonArray);
+ for (String val : enumArray) {
+ jsonArray.add(val);
+ }
+ }
+ return property;
+ }
+
+ private static JsonArray createVnfSchema(JsonObject modelJson) {
+ JsonArray vnfSchemaArray = new JsonArray();
+ JsonObject modelVnfs = modelJson.get("resourceDetails").getAsJsonObject().get("VF").getAsJsonObject();
+
+ for (Entry<String, JsonElement> entry : modelVnfs.entrySet()) {
+ JsonObject vnfOneOfSchema = new JsonObject();
+ vnfOneOfSchema.addProperty("title", "VNF" + "-" + entry.getKey());
+ JsonObject properties = new JsonObject();
+ properties.add("type", createSchemaProperty("Type", "string", "VNF", "True", null));
+ properties.add("resourceID", createSchemaProperty("Resource ID", "string",
+ modelVnfs.get(entry.getKey()).getAsJsonObject().get("name").getAsString(), "True", null));
+
+ vnfOneOfSchema.add("properties", properties);
+ vnfSchemaArray.add(vnfOneOfSchema);
+ }
+ return vnfSchemaArray;
+ }
+
+ private static JsonArray createVfModuleSchema(JsonObject modelJson) {
+ JsonArray vfModuleOneOfSchemaArray = new JsonArray();
+ JsonObject modelVfModules = modelJson.get("resourceDetails").getAsJsonObject().get("VFModule")
+ .getAsJsonObject();
+
+ for (Entry<String, JsonElement> entry : modelVfModules.entrySet()) {
+ JsonObject vfModuleOneOfSchema = new JsonObject();
+ vfModuleOneOfSchema.addProperty("title", "VFMODULE" + "-" + entry.getKey());
+ JsonObject properties = new JsonObject();
+ properties.add("type", createSchemaProperty("Type", "string", "VFMODULE", "True", null));
+ properties.add("resourceID",
+ createSchemaProperty("Resource ID", "string",
+ modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelName").getAsString(),
+ "True", null));
+ properties.add("modelInvariantId",
+ createSchemaProperty("Model Invariant Id (ModelInvariantUUID)", "string", modelVfModules
+ .get(entry.getKey()).getAsJsonObject().get("vfModuleModelInvariantUUID").getAsString(),
+ "True", null));
+ properties.add("modelVersionId",
+ createSchemaProperty("Model Version Id (ModelUUID)", "string",
+ modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelUUID").getAsString(),
+ "True", null));
+ properties.add("modelName",
+ createSchemaProperty("Model Name", "string",
+ modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelName").getAsString(),
+ "True", null));
+ properties.add("modelVersion", createSchemaProperty("Model Version", "string",
+ modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelVersion").getAsString(),
+ "True", null));
+ properties
+ .add("modelCustomizationId",
+ createSchemaProperty("Customization ID", "string", modelVfModules.get(entry.getKey())
+ .getAsJsonObject().get("vfModuleModelCustomizationUUID").getAsString(), "True",
+ null));
+
+ vfModuleOneOfSchema.add("properties", properties);
+ vfModuleOneOfSchemaArray.add(vfModuleOneOfSchema);
+ }
+ return vfModuleOneOfSchemaArray;
+ }
+
+ private static JsonArray createAnyOfArray(JsonObject modelJson) {
+ JsonArray targetOneOfStructure = new JsonArray();
+ targetOneOfStructure.addAll(createVnfSchema(modelJson));
+ targetOneOfStructure.addAll(createVfModuleSchema(modelJson));
+ return targetOneOfStructure;
+ }
+}
diff --git a/src/main/resources/clds/json-schema/operational_policies/operational_policy.json b/src/main/resources/clds/json-schema/operational_policies/operational_policy.json
new file mode 100644
index 000000000..93738c809
--- /dev/null
+++ b/src/main/resources/clds/json-schema/operational_policies/operational_policy.json
@@ -0,0 +1,362 @@
+{
+ "schema": {
+ "uniqueItems": "true",
+ "format": "tabs",
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 1,
+ "title": "Operational policies",
+ "items": {
+ "type": "object",
+ "title": "Operational Policy Item",
+ "id": "operational_policy_item",
+ "headerTemplate": "{{self.name}}",
+ "required": [
+ "name",
+ "configurationsJson"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Operational policy name",
+ "readOnly": "True"
+ },
+ "configurationsJson": {
+ "type": "object",
+ "title": "Configuration",
+ "required": [
+ "operational_policy",
+ "guard_policies"
+ ],
+ "properties": {
+ "operational_policy": {
+ "type": "object",
+ "title": "Related Parameters",
+ "required": [
+ "controlLoop",
+ "policies"
+ ],
+ "properties": {
+ "controlLoop": {
+ "type": "object",
+ "title": "Control Loop details",
+ "required": [
+ "timeout",
+ "abatement",
+ "trigger_policy",
+ "controlLoopName"
+ ],
+ "properties": {
+ "timeout": {
+ "type": "string",
+ "title": "Overall Time Limit",
+ "default": "0",
+ "format": "number"
+ },
+ "abatement": {
+ "type": "string",
+ "title": "Abatement",
+ "enum": [
+ "True",
+ "False"
+ ]
+ },
+ "trigger_policy": {
+ "type": "string",
+ "title": "Policy Decision Entry"
+ },
+ "controlLoopName": {
+ "type": "string",
+ "title": "Control loop name",
+ "readOnly": "True"
+ }
+ }
+ },
+ "policies": {
+ "uniqueItems": "true",
+ "id": "policies_array",
+ "type": "array",
+ "title": "Policy Decision Tree",
+ "format": "tabs-top",
+ "items": {
+ "title": "Policy Decision",
+ "type": "object",
+ "id": "policy_item",
+ "headerTemplate": "{{self.id}} - {{self.recipe}}",
+ "format": "categories",
+ "basicCategoryTitle": "recipe",
+ "required": [
+ "id",
+ "recipe",
+ "retry",
+ "timeout",
+ "actor",
+ "success",
+ "failure",
+ "failure_timeout",
+ "failure_retries",
+ "failure_exception",
+ "failure_guard",
+ "target"
+ ],
+ "properties": {
+ "id": {
+ "default": "Policy 1",
+ "title": "Policy ID",
+ "type": "string"
+ },
+ "recipe": {
+ "title": "Recipe",
+ "type": "string",
+ "enum": [
+ "Restart",
+ "Rebuild",
+ "Migrate",
+ "Health-Check",
+ "ModifyConfig",
+ "VF Module Create",
+ "VF Module Delete",
+ "Reroute"
+ ]
+ },
+ "retry": {
+ "default": "0",
+ "title": "Number of Retry",
+ "type": "string",
+ "format": "number"
+ },
+ "timeout": {
+ "default": "0",
+ "title": "Timeout",
+ "type": "string",
+ "format": "number"
+ },
+ "actor": {
+ "title": "Actor",
+ "type": "string",
+ "enum": [
+ "APPC",
+ "SO",
+ "VFC",
+ "SDNC",
+ "SDNR"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ },
+ "success": {
+ "default": "final_success",
+ "title": "When Success",
+ "type": "string"
+ },
+ "failure": {
+ "default": "final_failure",
+ "title": "When Failure",
+ "type": "string"
+ },
+ "failure_timeout": {
+ "default": "final_failure_timeout",
+ "title": "When Failure Timeout",
+ "type": "string"
+ },
+ "failure_retries": {
+ "default": "final_failure_retries",
+ "title": "When Failure Retries",
+ "type": "string"
+ },
+ "failure_exception": {
+ "default": "final_failure_exception",
+ "title": "When Failure Exception",
+ "type": "string"
+ },
+ "failure_guard": {
+ "default": "final_failure_guard",
+ "title": "When Failure Guard",
+ "type": "string"
+ },
+ "target": {
+ "type": "object",
+ "required": [
+ "type",
+ "resourceID"
+ ],
+ "anyOf": [
+ {
+ "title": "User Defined",
+ "additionalProperties":"True",
+ "properties": {
+ "type": {
+ "title": "Target type",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "VNF",
+ "VFMODULE",
+ "VM"
+ ]
+ },
+ "resourceID": {
+ "title": "Target type",
+ "type": "string",
+ "default": ""
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "guard_policies": {
+ "type": "array",
+ "format": "tabs-top",
+ "title": "Associated Guard policies",
+ "items": {
+ "headerTemplate": "{{self.policy-id}} - {{self.content.recipe}}",
+ "anyOf": [
+ {
+ "title": "Guard MinMax",
+ "type": "object",
+ "properties": {
+ "policy-id": {
+ "type": "string",
+ "default": "guard.minmax.new",
+ "pattern": "^(guard.minmax\\..*)$"
+ },
+ "content": {
+ "properties": {
+ "actor": {
+ "type": "string",
+ "enum": [
+ "APPC",
+ "SO",
+ "VFC",
+ "SDNC",
+ "SDNR"
+ ]
+ },
+ "recipe": {
+ "type": "string",
+ "enum": [
+ "Restart",
+ "Rebuild",
+ "Migrate",
+ "Health-Check",
+ "ModifyConfig",
+ "VF Module Create",
+ "VF Module Delete",
+ "Reroute"
+ ]
+ },
+ "targets": {
+ "type": "string",
+ "default": ".*"
+ },
+ "clname": {
+ "type": "string",
+ "template": "{{loopName}}",
+ "watch": {
+ "loopName": "operational_policy_item.configurationsJson.operational_policy.controlLoop.controlLoopName"
+ }
+ },
+ "guardActiveStart": {
+ "type": "string",
+ "default": "00:00:00Z"
+ },
+ "guardActiveEnd": {
+ "type": "string",
+ "default": "10:00:00Z"
+ },
+ "min": {
+ "type": "string",
+ "default": "0"
+ },
+ "max": {
+ "type": "string",
+ "default": "1"
+ }
+ }
+ }
+ }
+ },
+ {
+ "title": "Guard Frequency",
+ "type": "object",
+ "properties": {
+ "policy-id": {
+ "type": "string",
+ "default": "guard.frequency.new",
+ "pattern": "^(guard.frequency\\..*)$"
+ },
+ "content": {
+ "properties": {
+ "actor": {
+ "type": "string",
+ "enum": [
+ "APPC",
+ "SO",
+ "VFC",
+ "SDNC",
+ "SDNR"
+ ]
+ },
+ "recipe": {
+ "type": "string",
+ "enum": [
+ "Restart",
+ "Rebuild",
+ "Migrate",
+ "Health-Check",
+ "ModifyConfig",
+ "VF Module Create",
+ "VF Module Delete",
+ "Reroute"
+ ]
+ },
+ "targets": {
+ "type": "string",
+ "default": ".*"
+ },
+ "clname": {
+ "type": "string",
+ "template": "{{loopName}}",
+ "watch": {
+ "loopName": "operational_policy_item.configurationsJson.operational_policy.controlLoop.controlLoopName"
+ }
+ },
+ "guardActiveStart": {
+ "type": "string",
+ "default": "00:00:00Z"
+ },
+ "guardActiveEnd": {
+ "type": "string",
+ "default": "10:00:00Z"
+ },
+ "limit": {
+ "type": "string"
+ },
+ "timeWindow": {
+ "type": "string"
+ },
+ "timeUnits": {
+ "type": "string",
+ "enum":["minute","hour","day","week","month","year"]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/onap/clamp/clds/it/CldsDictionaryServiceItCase.java b/src/test/java/org/onap/clamp/clds/it/CldsDictionaryServiceItCase.java
index d31d5a01e..5218c9255 100644
--- a/src/test/java/org/onap/clamp/clds/it/CldsDictionaryServiceItCase.java
+++ b/src/test/java/org/onap/clamp/clds/it/CldsDictionaryServiceItCase.java
@@ -5,6 +5,8 @@
* Copyright (C) 2018 AT&T Intellectual Property. All rights
* reserved.
* ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -29,7 +31,6 @@ import static org.junit.Assert.assertNotNull;
import com.att.eelf.configuration.EELFLogger;
import com.att.eelf.configuration.EELFManager;
-import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
@@ -63,23 +64,21 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class CldsDictionaryServiceItCase {
- protected static final EELFLogger logger = EELFManager.getInstance().getLogger(CldsDictionaryServiceItCase.class);
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(CldsDictionaryServiceItCase.class);
@Autowired
private CldsDictionaryService cldsDictionaryService;
- private Authentication authentication;
private CldsDictionary cldsDictionary;
private CldsDictionaryItem cldsDictionaryItem;
- private List<GrantedAuthority> authList = new LinkedList<GrantedAuthority>();
- private LoggingUtils util;
+ private List<GrantedAuthority> authList = new LinkedList<>();
+
+ private static final String DICTIONARY_NAME = "TestDictionary";
/**
* Setup the variable before the tests execution.
*
- * @throws IOException
- * In case of issues when opening the files
*/
@Before
- public void setupBefore() throws IOException {
+ public void setupBefore() {
authList.add(new SimpleGrantedAuthority("permission-type-cl|dev|read"));
authList.add(new SimpleGrantedAuthority("permission-type-cl|dev|update"));
authList.add(new SimpleGrantedAuthority("permission-type-template|dev|read"));
@@ -87,22 +86,19 @@ public class CldsDictionaryServiceItCase {
authList.add(new SimpleGrantedAuthority("permission-type-filter-vf|dev|*"));
authList.add(new SimpleGrantedAuthority("permission-type-tosca|dev|read"));
authList.add(new SimpleGrantedAuthority("permission-type-tosca|dev|update"));
- authentication = new UsernamePasswordAuthenticationToken(new User("admin", "", authList), "", authList);
+ Authentication authentication =
+ new UsernamePasswordAuthenticationToken(new User("admin", "", authList), "", authList);
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
- util = Mockito.mock(LoggingUtils.class);
+ LoggingUtils util = Mockito.mock(LoggingUtils.class);
Mockito.doNothing().when(util).entering(Matchers.any(HttpServletRequest.class), Matchers.any(String.class));
cldsDictionaryService.setLoggingUtil(util);
cldsDictionaryService.setSecurityContext(securityContext);
- cldsDictionary = new CldsDictionary();
-
- cldsDictionary.setDictionaryName("TestDictionary");
- ResponseEntity entity = cldsDictionaryService.createOrUpdateDictionary("TestDictionary", cldsDictionary);
- cldsDictionary = (CldsDictionary) entity.getBody();
+ cldsDictionary = cldsDictionaryService.createDictionary(DICTIONARY_NAME);
cldsDictionaryItem = new CldsDictionaryItem();
cldsDictionaryItem.setDictElementShortName("TestDictionaryItemShortName");
@@ -110,23 +106,43 @@ public class CldsDictionaryServiceItCase {
cldsDictionaryItem.setDictElementType("string");
cldsDictionaryItem.setDictionaryId(cldsDictionary.getDictionaryId());
cldsDictionaryItem.setDictElementDesc("TestDictionaryItemDesc");
- cldsDictionaryService.createOrUpdateDictionaryElements("TestDictionary", cldsDictionaryItem);
+ cldsDictionaryService.createOrUpdateDictionaryElements(DICTIONARY_NAME, cldsDictionaryItem);
logger.info("Initial Clds Dictionary uploaded in DB:" + cldsDictionaryItem);
}
@Test
- public void testCreateOrUpdateDictionary() throws Exception {
- ResponseEntity<CldsDictionary> responseEntity = cldsDictionaryService.createOrUpdateDictionary("TestDictionary",
- cldsDictionary);
- CldsDictionary dictionary = responseEntity.getBody();
+ public void testCreateDictionaryFromString() {
+ String dictionaryName = "TestDefaultDictionary";
+ CldsDictionary dictionary = cldsDictionaryService.createDictionary(dictionaryName);
assertNotNull(dictionary);
- logger.info("CLDS Dictionary is:" + dictionary);
- assertEquals("TestDictionary", dictionary.getDictionaryName());
+ logger.info("CLDS Default Dictionary is:" + dictionary);
+ assertEquals(dictionaryName, dictionary.getDictionaryName());
+ }
+
+ @Test
+ public void testCreateOrUpdateDictionaryUsedByFrontend() {
+ ResponseEntity<CldsDictionary> responseEntity =
+ cldsDictionaryService.createOrUpdateDictionary(DICTIONARY_NAME, null);
+ CldsDictionary dictionary1 = responseEntity.getBody();
+
+ responseEntity = cldsDictionaryService.createOrUpdateDictionary(DICTIONARY_NAME, cldsDictionary);
+ CldsDictionary dictionary2 = responseEntity.getBody();
+
+ responseEntity = cldsDictionaryService.createOrUpdateDictionary(DICTIONARY_NAME, new CldsDictionary());
+ CldsDictionary dictionary3 = responseEntity.getBody();
+
+ assertNotNull(dictionary1);
+ assertNotNull(dictionary2);
+ assertNotNull(dictionary3);
+ assertEquals(DICTIONARY_NAME, dictionary1.getDictionaryName());
+ assertEquals(DICTIONARY_NAME, dictionary2.getDictionaryName());
+ assertNotNull(dictionary3.getDictionaryName());
+ assertEquals(DICTIONARY_NAME, dictionary3.getDictionaryName());
}
@Test
- public void testCreateOrUpdateDictionaryElements() throws Exception {
+ public void testCreateOrUpdateDictionaryElements() {
cldsDictionaryItem = new CldsDictionaryItem();
cldsDictionaryItem.setDictElementShortName("TestDictionaryItemShortName1");
cldsDictionaryItem.setDictElementName("TestDictionaryItemName1");
@@ -135,7 +151,7 @@ public class CldsDictionaryServiceItCase {
cldsDictionaryItem.setDictElementDesc("TestDictionaryItemDesc1");
ResponseEntity<CldsDictionaryItem> responseEntity = cldsDictionaryService
- .createOrUpdateDictionaryElements("TestDictionary", cldsDictionaryItem);
+ .createOrUpdateDictionaryElements(DICTIONARY_NAME, cldsDictionaryItem);
CldsDictionaryItem dictionaryItem = responseEntity.getBody();
assertNotNull(dictionaryItem);
logger.info("CLDS Dictionary Item is:" + dictionaryItem);
@@ -143,7 +159,7 @@ public class CldsDictionaryServiceItCase {
}
@Test
- public void testGetAllDictionaryNames() throws Exception {
+ public void testGetAllDictionaryNames() {
ResponseEntity<List<CldsDictionary>> responseEntity = cldsDictionaryService.getAllDictionaryNames();
List<CldsDictionary> dictionaries = responseEntity.getBody();
assertNotNull(dictionaries);
@@ -151,11 +167,11 @@ public class CldsDictionaryServiceItCase {
}
@Test
- public void testGetDictionaryElementsByName() throws Exception {
+ public void testGetDictionaryElementsByName() {
ResponseEntity<List<CldsDictionaryItem>> responseEntity = cldsDictionaryService
- .getDictionaryElementsByName("TestDictionary");
+ .getDictionaryElementsByName(DICTIONARY_NAME);
List<CldsDictionaryItem> dictionaryItems = responseEntity.getBody();
assertNotNull(dictionaryItems);
logger.info("CLDS Dictionary Item LIst is:" + dictionaryItems);
}
-}
+} \ No newline at end of file
diff --git a/src/test/java/org/onap/clamp/policy/microservice/OperationalPolicyPayloadTest.java b/src/test/java/org/onap/clamp/policy/microservice/OperationalPolicyPayloadTest.java
index 8972e5117..728b61cc9 100644
--- a/src/test/java/org/onap/clamp/policy/microservice/OperationalPolicyPayloadTest.java
+++ b/src/test/java/org/onap/clamp/policy/microservice/OperationalPolicyPayloadTest.java
@@ -42,29 +42,29 @@ public class OperationalPolicyPayloadTest {
@Test
public void testOperationalPolicyPayloadConstruction() throws IOException {
JsonObject jsonConfig = new GsonBuilder().create().fromJson(
- ResourceFileUtil.getResourceAsString("tosca/operational-policy-properties.json"), JsonObject.class);
+ ResourceFileUtil.getResourceAsString("tosca/operational-policy-properties.json"), JsonObject.class);
OperationalPolicy policy = new OperationalPolicy("testPolicy", null, jsonConfig);
assertThat(policy.createPolicyPayloadYaml())
- .isEqualTo(ResourceFileUtil.getResourceAsString("tosca/operational-policy-payload.yaml"));
+ .isEqualTo(ResourceFileUtil.getResourceAsString("tosca/operational-policy-payload.yaml"));
assertThat(policy.createPolicyPayload())
- .isEqualTo(ResourceFileUtil.getResourceAsString("tosca/operational-policy-payload.json"));
+ .isEqualTo(ResourceFileUtil.getResourceAsString("tosca/operational-policy-payload.json"));
}
@Test
public void testLegacyOperationalPolicyPayloadConstruction() throws IOException {
JsonObject jsonConfig = new GsonBuilder().create().fromJson(
- ResourceFileUtil.getResourceAsString("tosca/operational-policy-properties.json"), JsonObject.class);
+ ResourceFileUtil.getResourceAsString("tosca/operational-policy-properties.json"), JsonObject.class);
assertThat(LegacyOperationalPolicy.createPolicyPayloadYamlLegacy(jsonConfig.get("operational_policy")))
- .isEqualTo(ResourceFileUtil.getResourceAsString("tosca/operational-policy-payload-legacy.yaml"));
+ .isEqualTo(ResourceFileUtil.getResourceAsString("tosca/operational-policy-payload-legacy.yaml"));
}
@Test
public void testGuardPolicyEmptyPayloadConstruction() throws IOException {
JsonObject jsonConfig = new GsonBuilder().create().fromJson(
- ResourceFileUtil.getResourceAsString("tosca/operational-policy-no-guard-properties.json"),
- JsonObject.class);
+ ResourceFileUtil.getResourceAsString("tosca/operational-policy-no-guard-properties.json"),
+ JsonObject.class);
OperationalPolicy policy = new OperationalPolicy("testPolicy", null, jsonConfig);
Map<String, String> guardsMap = policy.createGuardPolicyPayloads();
assertThat(guardsMap).isEmpty();
@@ -74,15 +74,15 @@ public class OperationalPolicyPayloadTest {
@Test
public void testGuardPolicyPayloadConstruction() throws IOException {
JsonObject jsonConfig = new GsonBuilder().create().fromJson(
- ResourceFileUtil.getResourceAsString("tosca/operational-policy-properties.json"), JsonObject.class);
+ ResourceFileUtil.getResourceAsString("tosca/operational-policy-properties.json"), JsonObject.class);
OperationalPolicy policy = new OperationalPolicy("testPolicy", null, jsonConfig);
Map<String, String> guardsMap = policy.createGuardPolicyPayloads();
JSONAssert.assertEquals(ResourceFileUtil.getResourceAsString("tosca/guard1-policy-payload.json"),
- guardsMap.get("guard1"), false);
+ guardsMap.get("guard.minmax.new"), false);
JSONAssert.assertEquals(ResourceFileUtil.getResourceAsString("tosca/guard2-policy-payload.json"),
- guardsMap.get("guard2"), false);
+ guardsMap.get("guard.frequency.new"), false);
}
}
diff --git a/src/test/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilderTest.java b/src/test/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilderTest.java
new file mode 100644
index 000000000..904525bea
--- /dev/null
+++ b/src/test/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilderTest.java
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.clamp.policy.operational;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.onap.clamp.clds.util.ResourceFileUtil;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+public class OperationalPolicyRepresentationBuilderTest {
+
+ @Test
+ public void testOperationalPolicyPayloadConstruction() throws IOException {
+ JsonObject jsonModel = new GsonBuilder().create()
+ .fromJson(ResourceFileUtil.getResourceAsString("tosca/model-properties.json"), JsonObject.class);
+
+ JsonObject jsonSchema = OperationalPolicyRepresentationBuilder.generateOperationalPolicySchema(jsonModel);
+
+ assertThat(jsonSchema).isNotNull();
+
+ JSONAssert.assertEquals(ResourceFileUtil.getResourceAsString("tosca/operational-policy-json-schema.json"),
+ new GsonBuilder().create().toJson(jsonSchema), false);
+ }
+
+}
diff --git a/src/test/resources/clds/OperationalPolicyRepresentationBuilderTest.java b/src/test/resources/clds/OperationalPolicyRepresentationBuilderTest.java
new file mode 100644
index 000000000..904525bea
--- /dev/null
+++ b/src/test/resources/clds/OperationalPolicyRepresentationBuilderTest.java
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.clamp.policy.operational;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.onap.clamp.clds.util.ResourceFileUtil;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+public class OperationalPolicyRepresentationBuilderTest {
+
+ @Test
+ public void testOperationalPolicyPayloadConstruction() throws IOException {
+ JsonObject jsonModel = new GsonBuilder().create()
+ .fromJson(ResourceFileUtil.getResourceAsString("tosca/model-properties.json"), JsonObject.class);
+
+ JsonObject jsonSchema = OperationalPolicyRepresentationBuilder.generateOperationalPolicySchema(jsonModel);
+
+ assertThat(jsonSchema).isNotNull();
+
+ JSONAssert.assertEquals(ResourceFileUtil.getResourceAsString("tosca/operational-policy-json-schema.json"),
+ new GsonBuilder().create().toJson(jsonSchema), false);
+ }
+
+}
diff --git a/src/test/resources/tosca/guard1-policy-payload.json b/src/test/resources/tosca/guard1-policy-payload.json
index b4e0809c9..1c03df306 100644
--- a/src/test/resources/tosca/guard1-policy-payload.json
+++ b/src/test/resources/tosca/guard1-policy-payload.json
@@ -1,16 +1,13 @@
{
- "policy-id": "guard1",
+ "policy-id": "guard.minmax.new",
"content": {
- "recipe": "Rebuild",
- "actor": "SO",
- "clname": "testloop",
+ "actor": "APPC",
+ "recipe": "Restart",
"targets": ".*",
- "min": "3",
- "max": "7",
- "limit": "",
- "timeUnits": "",
- "timeWindow": "",
- "guardActiveStart": "00:00:01-05:00",
- "guardActiveEnd": "23:59:01-05:00"
+ "clname": "LOOP_ASJOy_v1_0_ResourceInstanceName1_tca",
+ "guardActiveStart": "00:00:00Z",
+ "guardActiveEnd": "10:00:00Z",
+ "min": "0",
+ "max": "1"
}
} \ No newline at end of file
diff --git a/src/test/resources/tosca/guard2-policy-payload.json b/src/test/resources/tosca/guard2-policy-payload.json
index 29beb6b98..559a56840 100644
--- a/src/test/resources/tosca/guard2-policy-payload.json
+++ b/src/test/resources/tosca/guard2-policy-payload.json
@@ -1,16 +1,14 @@
{
- "policy-id": "guard2",
+ "policy-id": "guard.frequency.new",
"content": {
- "recipe": "Migrate",
- "actor": "SO",
- "clname": "testloop",
+ "actor": "APPC",
+ "recipe": "Rebuild",
"targets": ".*",
- "min": "1",
- "max": "2",
- "limit": "",
- "timeUnits": "",
- "timeWindow": "",
- "guardActiveStart": "00:00:01-05:00",
- "guardActiveEnd": "23:59:01-05:00"
+ "clname": "LOOP_ASJOy_v1_0_ResourceInstanceName1_tca",
+ "guardActiveStart": "00:00:00Z",
+ "guardActiveEnd": "10:00:00Z",
+ "limit": "1",
+ "timeWindow": "2",
+ "timeUnits": "minute"
}
} \ No newline at end of file
diff --git a/src/test/resources/tosca/operational-policy-json-schema.json b/src/test/resources/tosca/operational-policy-json-schema.json
new file mode 100644
index 000000000..d6870dc9d
--- /dev/null
+++ b/src/test/resources/tosca/operational-policy-json-schema.json
@@ -0,0 +1,574 @@
+{
+ "schema": {
+ "uniqueItems": "true",
+ "format": "tabs",
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 1,
+ "title": "Operational policies",
+ "items": {
+ "type": "object",
+ "title": "Operational Policy Item",
+ "id": "operational_policy_item",
+ "headerTemplate": "{{self.name}}",
+ "required": [
+ "name",
+ "configurationsJson"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Operational policy name",
+ "readOnly": "True"
+ },
+ "configurationsJson": {
+ "type": "object",
+ "title": "Configuration",
+ "required": [
+ "operational_policy",
+ "guard_policies"
+ ],
+ "properties": {
+ "operational_policy": {
+ "type": "object",
+ "title": "Related Parameters",
+ "required": [
+ "controlLoop",
+ "policies"
+ ],
+ "properties": {
+ "controlLoop": {
+ "type": "object",
+ "title": "Control Loop details",
+ "required": [
+ "timeout",
+ "abatement",
+ "trigger_policy",
+ "controlLoopName"
+ ],
+ "properties": {
+ "timeout": {
+ "type": "string",
+ "title": "Overall Time Limit",
+ "default": "0",
+ "format": "number"
+ },
+ "abatement": {
+ "type": "string",
+ "title": "Abatement",
+ "enum": [
+ "True",
+ "False"
+ ]
+ },
+ "trigger_policy": {
+ "type": "string",
+ "title": "Policy Decision Entry"
+ },
+ "controlLoopName": {
+ "type": "string",
+ "title": "Control loop name",
+ "readOnly": "True"
+ }
+ }
+ },
+ "policies": {
+ "uniqueItems": "true",
+ "id": "policies_array",
+ "type": "array",
+ "title": "Policy Decision Tree",
+ "format": "tabs-top",
+ "items": {
+ "title": "Policy Decision",
+ "type": "object",
+ "id": "policy_item",
+ "headerTemplate": "{{self.id}} - {{self.recipe}}",
+ "format": "categories",
+ "basicCategoryTitle": "recipe",
+ "required": [
+ "id",
+ "recipe",
+ "retry",
+ "timeout",
+ "actor",
+ "success",
+ "failure",
+ "failure_timeout",
+ "failure_retries",
+ "failure_exception",
+ "failure_guard",
+ "target"
+ ],
+ "properties": {
+ "id": {
+ "default": "Policy 1",
+ "title": "Policy ID",
+ "type": "string"
+ },
+ "recipe": {
+ "title": "Recipe",
+ "type": "string",
+ "enum": [
+ "Restart",
+ "Rebuild",
+ "Migrate",
+ "Health-Check",
+ "ModifyConfig",
+ "VF Module Create",
+ "VF Module Delete",
+ "Reroute"
+ ]
+ },
+ "retry": {
+ "default": "0",
+ "title": "Number of Retry",
+ "type": "string",
+ "format": "number"
+ },
+ "timeout": {
+ "default": "0",
+ "title": "Timeout",
+ "type": "string",
+ "format": "number"
+ },
+ "actor": {
+ "title": "Actor",
+ "type": "string",
+ "enum": [
+ "APPC",
+ "SO",
+ "VFC",
+ "SDNC",
+ "SDNR"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ },
+ "success": {
+ "default": "final_success",
+ "title": "When Success",
+ "type": "string"
+ },
+ "failure": {
+ "default": "final_failure",
+ "title": "When Failure",
+ "type": "string"
+ },
+ "failure_timeout": {
+ "default": "final_failure_timeout",
+ "title": "When Failure Timeout",
+ "type": "string"
+ },
+ "failure_retries": {
+ "default": "final_failure_retries",
+ "title": "When Failure Retries",
+ "type": "string"
+ },
+ "failure_exception": {
+ "default": "final_failure_exception",
+ "title": "When Failure Exception",
+ "type": "string"
+ },
+ "failure_guard": {
+ "default": "final_failure_guard",
+ "title": "When Failure Guard",
+ "type": "string"
+ },
+ "target": {
+ "type": "object",
+ "required": [
+ "type",
+ "resourceID"
+ ],
+ "anyOf": [
+ {
+ "title": "User Defined",
+ "additionalProperties": "True",
+ "properties": {
+ "type": {
+ "title": "Target type",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "VNF",
+ "VFMODULE",
+ "VM"
+ ]
+ },
+ "resourceID": {
+ "title": "Target type",
+ "type": "string",
+ "default": ""
+ }
+ }
+ },
+ {
+ "title": "VNF-vLoadBalancerMS 0",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VNF",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "vLoadBalancerMS",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vpkg..module-1",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vpkg..module-1",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vpkg..module-1",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vdns..module-3",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vdns..module-3",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vdns..module-3",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "bafcdab0-801d-4d81-9ead-f464640a38b1",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..base_template..module-0",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..base_template..module-0",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "921f7c96-ebdd-42e6-81b9-1cfc0c9796f3",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "63734409-f745-4e4d-a38b-131638a0edce",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..base_template..module-0",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "86baddea-c730-4fb8-9410-cd2e17fd7f27",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vlb..module-2",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vlb..module-2",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "a772a1f4-0064-412c-833d-4749b15828dd",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "0f5c3f6a-650a-4303-abb6-fff3e573a07a",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vlb..module-2",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "96a78aad-4ffb-4ef0-9c4f-deb03bf1d806",
+ "readOnly": "True"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "guard_policies": {
+ "type": "array",
+ "format": "tabs-top",
+ "title": "Associated Guard policies",
+ "items": {
+ "headerTemplate": "{{self.policy-id}} - {{self.content.recipe}}",
+ "anyOf": [
+ {
+ "title": "Guard MinMax",
+ "type": "object",
+ "properties": {
+ "policy-id": {
+ "type": "string",
+ "default": "guard.minmax.new",
+ "pattern": "^(guard.minmax\\..*)$"
+ },
+ "content": {
+ "properties": {
+ "actor": {
+ "type": "string",
+ "enum": [
+ "APPC",
+ "SO",
+ "VFC",
+ "SDNC",
+ "SDNR"
+ ]
+ },
+ "recipe": {
+ "type": "string",
+ "enum": [
+ "Restart",
+ "Rebuild",
+ "Migrate",
+ "Health-Check",
+ "ModifyConfig",
+ "VF Module Create",
+ "VF Module Delete",
+ "Reroute"
+ ]
+ },
+ "targets": {
+ "type": "string",
+ "default": ".*"
+ },
+ "clname": {
+ "type": "string",
+ "template": "{{loopName}}",
+ "watch": {
+ "loopName": "operational_policy_item.configurationsJson.operational_policy.controlLoop.controlLoopName"
+ }
+ },
+ "guardActiveStart": {
+ "type": "string",
+ "default": "00:00:00Z"
+ },
+ "guardActiveEnd": {
+ "type": "string",
+ "default": "10:00:00Z"
+ },
+ "min": {
+ "type": "string",
+ "default": "0"
+ },
+ "max": {
+ "type": "string",
+ "default": "1"
+ }
+ }
+ }
+ }
+ },
+ {
+ "title": "Guard Frequency",
+ "type": "object",
+ "properties": {
+ "policy-id": {
+ "type": "string",
+ "default": "guard.frequency.new",
+ "pattern": "^(guard.frequency\\..*)$"
+ },
+ "content": {
+ "properties": {
+ "actor": {
+ "type": "string",
+ "enum": [
+ "APPC",
+ "SO",
+ "VFC",
+ "SDNC",
+ "SDNR"
+ ]
+ },
+ "recipe": {
+ "type": "string",
+ "enum": [
+ "Restart",
+ "Rebuild",
+ "Migrate",
+ "Health-Check",
+ "ModifyConfig",
+ "VF Module Create",
+ "VF Module Delete",
+ "Reroute"
+ ]
+ },
+ "targets": {
+ "type": "string",
+ "default": ".*"
+ },
+ "clname": {
+ "type": "string",
+ "template": "{{loopName}}",
+ "watch": {
+ "loopName": "operational_policy_item.configurationsJson.operational_policy.controlLoop.controlLoopName"
+ }
+ },
+ "guardActiveStart": {
+ "type": "string",
+ "default": "00:00:00Z"
+ },
+ "guardActiveEnd": {
+ "type": "string",
+ "default": "10:00:00Z"
+ },
+ "limit": {
+ "type": "string"
+ },
+ "timeWindow": {
+ "type": "string"
+ },
+ "timeUnits": {
+ "type": "string",
+ "enum": [
+ "minute",
+ "hour",
+ "day",
+ "week",
+ "month",
+ "year"
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/test/resources/tosca/operational-policy-payload-legacy.yaml b/src/test/resources/tosca/operational-policy-payload-legacy.yaml
index 41184c9c9..4d2b9f361 100644
--- a/src/test/resources/tosca/operational-policy-payload-legacy.yaml
+++ b/src/test/resources/tosca/operational-policy-payload-legacy.yaml
@@ -1,39 +1,43 @@
controlLoop:
abatement: true
- controlLoopName: control loop
- timeout: 30
- trigger_policy: new1
- version: 2.0.0
+ controlLoopName: LOOP_ASJOy_v1_0_ResourceInstanceName1_tca
+ timeout: 0
+ trigger_policy: policy1
policies:
-- actor: SO
- failure: new2
- failure_exception: new2
- failure_guard: new2
- failure_retries: new2
- failure_timeout: new2
- id: new1
+- actor: APPC
+ failure: policy2
+ failure_exception: final_failure_exception
+ failure_guard: final_failure_guard
+ failure_retries: final_failure_retries
+ failure_timeout: final_failure_timeout
+ id: policy1
payload:
configurationParameters: '[{"ip-addr":"$.vf-module-topology.vf-module-parameters.param[10].value","oam-ip-addr":"$.vf-module-topology.vf-module-parameters.param[15].value","enabled":"$.vf-module-topology.vf-module-parameters.param[22].value"}]'
requestParameters: '{"usePreload":true,"userParams":[]}'
- recipe: Rebuild
- retry: 10
- success: new2
+ recipe: Restart
+ retry: 0
+ success: final_success
target:
- resourceTargetId: test
- type: VFC
- timeout: 20
-- actor: SDNC
+ resourceID: vLoadBalancerMS
+ type: VNF
+ timeout: 0
+- actor: SO
failure: final_failure
failure_exception: final_failure_exception
failure_guard: final_failure_guard
failure_retries: final_failure_retries
failure_timeout: final_failure_timeout
- id: new2
+ id: policy2
payload: ''
- recipe: Migrate
- retry: 30
+ recipe: VF Module Create
+ retry: 0
success: final_success
target:
- resourceTargetId: test
- type: VFC
- timeout: 40
+ modelCustomizationId: 1bffdc31-a37d-4dee-b65c-dde623a76e52
+ modelInvariantId: ca052563-eb92-4b5b-ad41-9111768ce043
+ modelName: Vloadbalancerms..vpkg..module-1
+ modelVersion: 1
+ modelVersionId: 1e725ccc-b823-4f67-82b9-4f4367070dbc
+ resourceID: Vloadbalancerms..vpkg..module-1
+ type: VFMODULE
+ timeout: 0
diff --git a/src/test/resources/tosca/operational-policy-payload.json b/src/test/resources/tosca/operational-policy-payload.json
index 5097654da..ed0197606 100644
--- a/src/test/resources/tosca/operational-policy-payload.json
+++ b/src/test/resources/tosca/operational-policy-payload.json
@@ -1,4 +1,4 @@
{
"policy-id": "testPolicy",
- "content": "controlLoop%3A%0A++abatement%3A+true%0A++controlLoopName%3A+control+loop%0A++timeout%3A+30%0A++trigger_policy%3A+new1%0A++version%3A+2.0.0%0Apolicies%3A%0A-+actor%3A+SO%0A++failure%3A+new2%0A++failure_exception%3A+new2%0A++failure_guard%3A+new2%0A++failure_retries%3A+new2%0A++failure_timeout%3A+new2%0A++id%3A+new1%0A++payload%3A%0A++++configurationParameters%3A+%27%5B%7B%22ip-addr%22%3A%22%24.vf-module-topology.vf-module-parameters.param%5B10%5D.value%22%2C%22oam-ip-addr%22%3A%22%24.vf-module-topology.vf-module-parameters.param%5B15%5D.value%22%2C%22enabled%22%3A%22%24.vf-module-topology.vf-module-parameters.param%5B22%5D.value%22%7D%5D%27%0A++++requestParameters%3A+%27%7B%22usePreload%22%3Atrue%2C%22userParams%22%3A%5B%5D%7D%27%0A++recipe%3A+Rebuild%0A++retry%3A+10%0A++success%3A+new2%0A++target%3A%0A++++resourceTargetId%3A+test%0A++++type%3A+VFC%0A++timeout%3A+20%0A-+actor%3A+SDNC%0A++failure%3A+final_failure%0A++failure_exception%3A+final_failure_exception%0A++failure_guard%3A+final_failure_guard%0A++failure_retries%3A+final_failure_retries%0A++failure_timeout%3A+final_failure_timeout%0A++id%3A+new2%0A++payload%3A+%27%27%0A++recipe%3A+Migrate%0A++retry%3A+30%0A++success%3A+final_success%0A++target%3A%0A++++resourceTargetId%3A+test%0A++++type%3A+VFC%0A++timeout%3A+40%0A"
+ "content": "controlLoop%3A%0A++abatement%3A+true%0A++controlLoopName%3A+LOOP_ASJOy_v1_0_ResourceInstanceName1_tca%0A++timeout%3A+0%0A++trigger_policy%3A+policy1%0Apolicies%3A%0A-+actor%3A+APPC%0A++failure%3A+policy2%0A++failure_exception%3A+final_failure_exception%0A++failure_guard%3A+final_failure_guard%0A++failure_retries%3A+final_failure_retries%0A++failure_timeout%3A+final_failure_timeout%0A++id%3A+policy1%0A++payload%3A%0A++++configurationParameters%3A+%27%5B%7B%22ip-addr%22%3A%22%24.vf-module-topology.vf-module-parameters.param%5B10%5D.value%22%2C%22oam-ip-addr%22%3A%22%24.vf-module-topology.vf-module-parameters.param%5B15%5D.value%22%2C%22enabled%22%3A%22%24.vf-module-topology.vf-module-parameters.param%5B22%5D.value%22%7D%5D%27%0A++++requestParameters%3A+%27%7B%22usePreload%22%3Atrue%2C%22userParams%22%3A%5B%5D%7D%27%0A++recipe%3A+Restart%0A++retry%3A+0%0A++success%3A+final_success%0A++target%3A%0A++++resourceID%3A+vLoadBalancerMS%0A++++type%3A+VNF%0A++timeout%3A+0%0A-+actor%3A+SO%0A++failure%3A+final_failure%0A++failure_exception%3A+final_failure_exception%0A++failure_guard%3A+final_failure_guard%0A++failure_retries%3A+final_failure_retries%0A++failure_timeout%3A+final_failure_timeout%0A++id%3A+policy2%0A++payload%3A+%27%27%0A++recipe%3A+VF+Module+Create%0A++retry%3A+0%0A++success%3A+final_success%0A++target%3A%0A++++modelCustomizationId%3A+1bffdc31-a37d-4dee-b65c-dde623a76e52%0A++++modelInvariantId%3A+ca052563-eb92-4b5b-ad41-9111768ce043%0A++++modelName%3A+Vloadbalancerms..vpkg..module-1%0A++++modelVersion%3A+1%0A++++modelVersionId%3A+1e725ccc-b823-4f67-82b9-4f4367070dbc%0A++++resourceID%3A+Vloadbalancerms..vpkg..module-1%0A++++type%3A+VFMODULE%0A++timeout%3A+0%0A"
} \ No newline at end of file
diff --git a/src/test/resources/tosca/operational-policy-payload.yaml b/src/test/resources/tosca/operational-policy-payload.yaml
index c3a6b5c23..ed03842f5 100644
--- a/src/test/resources/tosca/operational-policy-payload.yaml
+++ b/src/test/resources/tosca/operational-policy-payload.yaml
@@ -8,35 +8,45 @@ topology_template:
policy-id: testPolicy
properties:
controlLoop:
- controlLoopName: control loop
- version: 2.0.0
- trigger_policy: new1
- timeout: '30'
- abatement: 'true'
+ timeout: '0'
+ abatement: 'True'
+ trigger_policy: policy1
+ controlLoopName: LOOP_ASJOy_v1_0_ResourceInstanceName1_tca
policies:
- - id: new1
- recipe: Rebuild
- retry: '10'
- timeout: '20'
- actor: SO
+ - id: policy1
+ recipe: Restart
+ retry: '0'
+ timeout: '0'
+ actor: APPC
payload:
requestParameters: '{"usePreload":true,"userParams":[]}'
configurationParameters: '[{"ip-addr":"$.vf-module-topology.vf-module-parameters.param[10].value","oam-ip-addr":"$.vf-module-topology.vf-module-parameters.param[15].value","enabled":"$.vf-module-topology.vf-module-parameters.param[22].value"}]'
- success: new2
- failure: new2
- failure_timeout: new2
- failure_retries: new2
- failure_exception: new2
- failure_guard: new2
+ success: final_success
+ failure: policy2
+ failure_timeout: final_failure_timeout
+ failure_retries: final_failure_retries
+ failure_exception: final_failure_exception
+ failure_guard: final_failure_guard
target:
- type: VFC
- resourceTargetId: test
- - id: new2
- recipe: Migrate
- retry: '30'
- timeout: '40'
- actor: SDNC
+ type: VNF
+ resourceID: vLoadBalancerMS
+ - id: policy2
+ recipe: VF Module Create
+ retry: '0'
+ timeout: '0'
+ actor: SO
payload: ''
+ success: final_success
+ failure: final_failure
+ failure_timeout: final_failure_timeout
+ failure_retries: final_failure_retries
+ failure_exception: final_failure_exception
+ failure_guard: final_failure_guard
target:
- type: VFC
- resourceTargetId: test
+ type: VFMODULE
+ resourceID: Vloadbalancerms..vpkg..module-1
+ modelInvariantId: ca052563-eb92-4b5b-ad41-9111768ce043
+ modelVersionId: 1e725ccc-b823-4f67-82b9-4f4367070dbc
+ modelName: Vloadbalancerms..vpkg..module-1
+ modelVersion: '1'
+ modelCustomizationId: 1bffdc31-a37d-4dee-b65c-dde623a76e52
diff --git a/src/test/resources/tosca/operational-policy-properties.json b/src/test/resources/tosca/operational-policy-properties.json
index bfce6b331..ac1314ecb 100644
--- a/src/test/resources/tosca/operational-policy-properties.json
+++ b/src/test/resources/tosca/operational-policy-properties.json
@@ -1,71 +1,82 @@
{
- "guard_policies": {
- "guard1":{
- "recipe": "Rebuild",
- "actor": "SO",
- "clname": "testloop",
- "targets": ".*",
- "min": "3",
- "max": "7",
- "limit": "",
- "timeUnits": "",
- "timeWindow": "",
- "guardActiveStart": "00:00:01-05:00",
- "guardActiveEnd": "23:59:01-05:00"
- },
- "guard2":{
- "recipe": "Migrate",
- "actor": "SO",
- "clname": "testloop",
- "targets": ".*",
- "min": "1",
- "max": "2",
- "limit": "",
- "timeUnits": "",
- "timeWindow": "",
- "guardActiveStart": "00:00:01-05:00",
- "guardActiveEnd": "23:59:01-05:00"
- }
- },
- "operational_policy": {
- "controlLoop": {
- "controlLoopName": "control loop",
- "version": "2.0.0",
- "trigger_policy": "new1",
- "timeout": "30",
- "abatement": "true"
- },
- "policies": [
- {
- "id": "new1",
- "recipe": "Rebuild",
- "retry": "10",
- "timeout": "20",
- "actor": "SO",
- "payload": "requestParameters: '{\"usePreload\":true,\"userParams\":[]}'\r\nconfigurationParameters: '[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[10].value\",\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[15].value\",\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[22].value\"}]'",
- "success": "new2",
- "failure": "new2",
- "failure_timeout": "new2",
- "failure_retries": "new2",
- "failure_exception": "new2",
- "failure_guard": "new2",
- "target": {
- "type": "VFC",
- "resourceTargetId": "test"
- }
- },
- {
- "id": "new2",
- "recipe": "Migrate",
- "retry": "30",
- "timeout": "40",
- "actor": "SDNC",
- "payload": "",
- "target": {
- "type": "VFC",
- "resourceTargetId": "test"
- }
- }
- ]
- }
+ "operational_policy": {
+ "controlLoop": {
+ "timeout": "0",
+ "abatement": "True",
+ "trigger_policy": "policy1",
+ "controlLoopName": "LOOP_ASJOy_v1_0_ResourceInstanceName1_tca"
+ },
+ "policies": [
+ {
+ "id": "policy1",
+ "recipe": "Restart",
+ "retry": "0",
+ "timeout": "0",
+ "actor": "APPC",
+ "payload": "requestParameters: '{\"usePreload\":true,\"userParams\":[]}'\r\nconfigurationParameters: '[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[10].value\",\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[15].value\",\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[22].value\"}]'",
+ "success": "final_success",
+ "failure": "policy2",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard",
+ "target": {
+ "type": "VNF",
+ "resourceID": "vLoadBalancerMS"
+ }
+ },
+ {
+ "id": "policy2",
+ "recipe": "VF Module Create",
+ "retry": "0",
+ "timeout": "0",
+ "actor": "SO",
+ "payload": "",
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard",
+ "target": {
+ "type": "VFMODULE",
+ "resourceID": "Vloadbalancerms..vpkg..module-1",
+ "modelInvariantId": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "modelVersionId": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "modelName": "Vloadbalancerms..vpkg..module-1",
+ "modelVersion": "1",
+ "modelCustomizationId": "1bffdc31-a37d-4dee-b65c-dde623a76e52"
+ }
+ }
+ ]
+ },
+ "guard_policies": [
+ {
+ "policy-id": "guard.minmax.new",
+ "content": {
+ "actor": "APPC",
+ "recipe": "Restart",
+ "targets": ".*",
+ "clname": "LOOP_ASJOy_v1_0_ResourceInstanceName1_tca",
+ "guardActiveStart": "00:00:00Z",
+ "guardActiveEnd": "10:00:00Z",
+ "min": "0",
+ "max": "1"
+ }
+ },
+ {
+ "policy-id": "guard.frequency.new",
+ "content": {
+ "actor": "APPC",
+ "recipe": "Rebuild",
+ "targets": ".*",
+ "clname": "LOOP_ASJOy_v1_0_ResourceInstanceName1_tca",
+ "guardActiveStart": "00:00:00Z",
+ "guardActiveEnd": "10:00:00Z",
+ "limit": "1",
+ "timeWindow": "2",
+ "timeUnits": "minute"
+ }
+ }
+ ]
}
diff --git a/src/test/resources/tosca/pdp-group-policy-payload.json b/src/test/resources/tosca/pdp-group-policy-payload.json
index bf941e516..ad3a5b4c3 100644
--- a/src/test/resources/tosca/pdp-group-policy-payload.json
+++ b/src/test/resources/tosca/pdp-group-policy-payload.json
@@ -4,10 +4,10 @@
"policy-id": "GuardOpPolicyTest"
},
{
- "policy-id": "guard2"
+ "policy-id": "guard.minmax.new"
},
{
- "policy-id": "guard1"
+ "policy-id": "guard.frequency.new"
},
{
"policy-id": "configPolicyTest"
diff --git a/ui-react/package.json b/ui-react/package.json
index a51812271..9770d44c6 100644
--- a/ui-react/package.json
+++ b/ui-react/package.json
@@ -25,7 +25,7 @@
"src/theme"
],
"dependencies": {
- "@json-editor/json-editor": "1.3.5",
+ "@json-editor/json-editor": "1.4.0-beta.0",
"react": "16.8.0",
"react-dom": "16.8.0",
"react-scripts": "3.0.1",
diff --git a/ui-react/src/LoopUI.js b/ui-react/src/LoopUI.js
index 643b32d14..b64cfbaa3 100644
--- a/ui-react/src/LoopUI.js
+++ b/ui-react/src/LoopUI.js
@@ -34,13 +34,16 @@ import LoopStatus from './components/loop_viewer/status/LoopStatus';
import UserService from './api/UserService';
import LoopCache from './api/LoopCache';
-import { Route, Redirect } from 'react-router-dom'
+import { Route } from 'react-router-dom'
import OpenLoopModal from './components/dialogs/OpenLoop/OpenLoopModal';
import OperationalPolicyModal from './components/dialogs/OperationalPolicy/OperationalPolicyModal';
import ConfigurationPolicyModal from './components/dialogs/ConfigurationPolicy/ConfigurationPolicyModal';
import LoopProperties from './components/dialogs/LoopProperties';
import UserInfo from './components/dialogs/UserInfo';
import LoopService from './api/LoopService';
+import PerformAction from './components/dialogs/PerformActions';
+import RefreshStatus from './components/dialogs/RefreshStatus';
+import DeployLoop from './components/dialogs/DeployLoop';
const ProjectNameStyled = styled.a`
vertical-align: middle;
@@ -80,7 +83,7 @@ export default class LoopUI extends React.Component {
state = {
userName: null,
loopName: LoopUI.defaultLoopName,
- loopCache: new LoopCache({}),
+ loopCache: new LoopCache({})
};
constructor() {
@@ -88,6 +91,7 @@ export default class LoopUI extends React.Component {
this.getUser = this.getUser.bind(this);
this.updateLoopCache = this.updateLoopCache.bind(this);
this.loadLoop = this.loadLoop.bind(this);
+ this.closeLoop = this.closeLoop.bind(this);
}
componentWillMount() {
@@ -102,7 +106,7 @@ export default class LoopUI extends React.Component {
renderMenuNavBar() {
return (
- <MenuBar loopCache={this.state.loopCache}/>
+ <MenuBar loopName={this.state.loopName}/>
);
}
@@ -155,6 +159,7 @@ export default class LoopUI extends React.Component {
return this.state.loopCache;
}
+
renderLoopViewer() {
return (
<LoopViewDivStyled>
@@ -165,11 +170,10 @@ export default class LoopUI extends React.Component {
}
updateLoopCache(loopJson) {
- this.setState({ loopCache: new LoopCache(loopJson) });
- this.setState({ loopName: this.state.loopCache.getLoopName() });
+ this.setState({ loopCache: new LoopCache(loopJson), loopName: this.state.loopCache.getLoopName() });
console.info(this.state.loopName+" loop loaded successfully");
}
-
+
loadLoop(loopName) {
LoopService.getLoop(loopName).then(loop => {
console.debug("Updating loopCache");
@@ -177,7 +181,12 @@ export default class LoopUI extends React.Component {
});
}
- render() {
+ closeLoop() {
+ this.setState({ loopCache: new LoopCache({}), loopName: LoopUI.defaultLoopName });
+ this.props.history.push('/');
+ }
+
+ render() {
return (
<div id="main_div">
<Route path="/operationalPolicyModal"
@@ -186,7 +195,14 @@ export default class LoopUI extends React.Component {
<Route path="/openLoop" render={(routeProps) => (<OpenLoopModal {...routeProps} loadLoopFunction={this.loadLoop} />)} />
<Route path="/loopProperties" render={(routeProps) => (<LoopProperties {...routeProps} loopCache={this.getLoopCache()} loadLoopFunction={this.loadLoop}/>)} />
<Route path="/userInfo" render={(routeProps) => (<UserInfo {...routeProps} />)} />
- <Route path="/closeLoop" render={(routeProps) => (<Redirect to='/'/>)} />
+ <Route path="/closeLoop" render={this.closeLoop} />
+ <Route path="/submit" render={(routeProps) => (<PerformAction {...routeProps} loopAction="submit" loopCache={this.getLoopCache()} updateLoopFunction={this.updateLoopCache}/>)} />
+ <Route path="/stop" render={(routeProps) => (<PerformAction {...routeProps} loopAction="stop" loopCache={this.getLoopCache()} updateLoopFunction={this.updateLoopCache}/>)} />
+ <Route path="/restart" render={(routeProps) => (<PerformAction {...routeProps} loopAction="restart" loopCache={this.getLoopCache()} updateLoopFunction={this.updateLoopCache}/>)} />
+ <Route path="/delete" render={(routeProps) => (<PerformAction {...routeProps} loopAction="delete" loopCache={this.getLoopCache()} updateLoopFunction={this.updateLoopCache}/>)} />
+ <Route path="/undeploy" render={(routeProps) => (<PerformAction {...routeProps} loopAction="undeploy" loopCache={this.getLoopCache()} updateLoopFunction={this.updateLoopCache}/>)} />
+ <Route path="/deploy" render={(routeProps) => (<DeployLoop {...routeProps} loopCache={this.getLoopCache()} updateLoopFunction={this.updateLoopCache}/>)} />
+ <Route path="/refreshStatus" render={(routeProps) => (<RefreshStatus {...routeProps} loopCache={this.getLoopCache()} updateLoopFunction={this.updateLoopCache}/>)} />
<GlobalClampStyle />
{this.renderNavBar()}
{this.renderLoopViewer()}
diff --git a/ui-react/src/api/LoopActionService.js b/ui-react/src/api/LoopActionService.js
index 9ce8ff0a9..6e45ce4b9 100644
--- a/ui-react/src/api/LoopActionService.js
+++ b/ui-react/src/api/LoopActionService.js
@@ -20,35 +20,55 @@
* ===================================================================
*
*/
-const loopActionService = {
- submit
-};
+export default class LoopActionService{
-function submit(uiAction) {
- const cl_name = "";
- console.log("clActionServices perform action: " + uiAction + " closedloopName="
- + cl_name);
- const svcAction = uiAction.toLowerCase();
- const svcUrl = "/restservices/clds/v2/loop/" + svcAction + "/" + cl_name;
+ static performAction(cl_name, uiAction) {
+ console.log("LoopActionService perform action: " + uiAction + " closedloopName=" + cl_name);
+ const svcAction = uiAction.toLowerCase();
+ return fetch("/restservices/clds/v2/loop/" + svcAction + "/" + cl_name, {
+ method: 'PUT',
+ credentials: 'same-origin',
+ })
+ .then(function (response) {
+ if (response.ok) {
+ return response.json();
+ } else {
+ return Promise.reject("Perform action failed with code:" + response.status);
+ }
+ })
+ .then(function (data) {
+ alert("Action Successful: " + uiAction);
+ return data;
+ })
+ .catch(function(error) {
+ console.log("Action Failure: " + uiAction);
+ return Promise.reject(error);
+ });
+ }
- let options = {
- method: 'GET'
- };
- return sendRequest(svcUrl, svcAction, options);
-}
-
-function sendRequest(svcUrl, svcAction) {
- fetch(svcUrl, options)
- .then(
- response => {
- alertService.alertMessage("Action Successful: " + svcAction, 1)
- }).error(error => {
- alertService.alertMessage("Action Failure: " + svcAction, 2);
- return Promise.reject(error);
- });
- return response.json();
-};
+ static refreshStatus(cl_name) {
+ console.log("Refresh the status for closedloopName=" + cl_name);
-export default loopActionService; \ No newline at end of file
+ return fetch("/restservices/clds/v2/loop/getstatus/" + cl_name, {
+ method: 'GET',
+ credentials: 'same-origin',
+ })
+ .then(function (response) {
+ if (response.ok) {
+ return response.json();
+ } else {
+ return Promise.reject("Refresh status failed with code:" + response.status);
+ }
+ })
+ .then(function (data) {
+ console.info ("Refresh status Successful");
+ return data;
+ })
+ .catch(function(error) {
+ console.info ("Refresh status failed:", error);
+ return Promise.reject(error);
+ });
+ }
+}
diff --git a/ui-react/src/api/LoopCache.js b/ui-react/src/api/LoopCache.js
index 3ee5acc68..d83e3ce9d 100644
--- a/ui-react/src/api/LoopCache.js
+++ b/ui-react/src/api/LoopCache.js
@@ -51,6 +51,10 @@ export default class LoopCache {
getOperationalPolicyConfigurationJson() {
return this.loopJsonCache["operationalPolicies"]["0"]["configurationsJson"];
}
+
+ getOperationalPolicyJsonSchema() {
+ return this.loopJsonCache["operationalPolicySchema"];
+ }
getOperationalPolicies() {
return this.loopJsonCache["operationalPolicies"];
diff --git a/ui-react/src/api/LoopService.js b/ui-react/src/api/LoopService.js
index 031ec638f..eece20c96 100644
--- a/ui-react/src/api/LoopService.js
+++ b/ui-react/src/api/LoopService.js
@@ -104,6 +104,30 @@ export default class LoopService {
return "";
});
}
+
+ static setOperationalPolicyProperties(loopName, jsonData) {
+ return fetch('/restservices/clds/v2/loop/updateOperationalPolicies/' + loopName, {
+ method: 'POST',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(jsonData),
+ })
+ .then(function (response) {
+ console.debug("updateOperationalPolicies response received: ", response.status);
+ if (response.ok) {
+ return response.text();
+ } else {
+ console.error("updateOperationalPolicies query failed");
+ return "";
+ }
+ })
+ .catch(function (error) {
+ console.error("updateOperationalPolicies error received", error);
+ return "";
+ });
+ }
static updateGlobalProperties(loopName, jsonData) {
return fetch('/restservices/clds/v2/loop/updateGlobalProperties/' + loopName, {
diff --git a/ui-react/src/components/dialogs/ConfigurationPolicy/ConfigurationPolicyModal.js b/ui-react/src/components/dialogs/ConfigurationPolicy/ConfigurationPolicyModal.js
index 4fbb7832c..9863ef721 100644
--- a/ui-react/src/components/dialogs/ConfigurationPolicy/ConfigurationPolicyModal.js
+++ b/ui-react/src/components/dialogs/ConfigurationPolicy/ConfigurationPolicyModal.js
@@ -103,7 +103,7 @@ export default class ConfigurationPolicyModal extends React.Component {
render() {
return (
- <ModalStyled size="lg" show={this.state.show} onHide={this.handleClose}>
+ <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Configuration policies</Modal.Title>
</Modal.Header>
diff --git a/ui-react/src/components/dialogs/DeployLoop.js b/ui-react/src/components/dialogs/DeployLoop.js
new file mode 100644
index 000000000..2ec395d23
--- /dev/null
+++ b/ui-react/src/components/dialogs/DeployLoop.js
@@ -0,0 +1,128 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import LoopActionService from '../../api/LoopActionService';
+import LoopService from '../../api/LoopService';
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import Form from 'react-bootstrap/Form';
+import styled from 'styled-components';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+const FormStyled = styled(Form.Group)`
+ padding: .25rem 1.5rem;
+`
+export default class DeployLoop extends React.Component {
+ state = {
+ loopCache: this.props.loopCache,
+ temporaryPropertiesJson: JSON.parse(JSON.stringify(this.props.loopCache.getGlobalProperties())),
+ show: true
+ };
+ constructor(props, context) {
+ super(props, context);
+
+ this.handleSave = this.handleSave.bind(this);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ this.refreshStatus = this.refreshStatus.bind(this);
+ this.renderDeployParam = this.renderDeployParam.bind(this);
+ }
+ componentWillReceiveProps(newProps) {
+ this.setState({
+ loopName: newProps.loopCache.getLoopName(),
+ show: true
+ });
+ }
+ handleClose(){
+ this.props.history.push('/');
+ }
+ handleSave(e) {
+ const loopName = this.props.loopCache.getLoopName();
+ // save the global propserties
+ LoopService.updateGlobalProperties(loopName, this.state.temporaryPropertiesJson).then(resp => {
+ this.setState({ show: false });
+
+ console.log("Perform action: deploy");
+ LoopActionService.performAction(loopName, "deploy").then(pars => {
+ alert("Action deploy successfully performed");
+ // refresh status and update loop logs
+ this.refreshStatus(loopName);
+ })
+ .catch(error => {
+ alert("Action deploy failed");
+ // refresh status and update loop logs
+ this.refreshStatus(loopName);
+ });
+ });
+ }
+
+ refreshStatus(loopName) {
+ LoopActionService.refreshStatus(loopName).then(data => {
+ this.props.updateLoopFunction(data);
+ this.props.history.push('/');
+ })
+ .catch(error => {
+ alert("Refresh status failed");
+ this.props.history.push('/');
+ });
+ }
+ handleChange(event) {
+ let deploymentParam = this.state.temporaryPropertiesJson["dcaeDeployParameters"];
+ deploymentParam[event.target.name] = event.target.value;
+
+ this.setState({temporaryPropertiesJson:{dcaeDeployParameters: deploymentParam}});
+ }
+ renderDeployParam() {
+ if (typeof (this.state.temporaryPropertiesJson) === "undefined") {
+ return "";
+ }
+
+ const deployJson = this.state.temporaryPropertiesJson["dcaeDeployParameters"];
+ var indents = [];
+ Object.keys(deployJson).map((item,key) =>
+ indents.push(<FormStyled>
+ <Form.Label>{item}</Form.Label>
+ <Form.Control type="text" name={item} onChange={this.handleChange} defaultValue={deployJson[item]}></Form.Control>
+ </FormStyled>));
+
+ return indents;
+ }
+
+
+ render() {
+ return (
+ <ModalStyled size="lg" show={this.state.show} onHide={this.handleClose} >
+ <Modal.Header closeButton>
+ <Modal.Title>Deployment parameters</Modal.Title>
+ </Modal.Header>
+ {this.renderDeployParam()}
+ <Modal.Footer>
+ <Button variant="secondary" type="null" onClick={this.handleClose}>Cancel</Button>
+ <Button variant="primary" type="submit" onClick={this.handleSave}>Deploy</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
+}
diff --git a/ui-react/src/components/dialogs/LoopProperties.js b/ui-react/src/components/dialogs/LoopProperties.js
index dac77655f..fa82a7e48 100644
--- a/ui-react/src/components/dialogs/LoopProperties.js
+++ b/ui-react/src/components/dialogs/LoopProperties.js
@@ -30,7 +30,6 @@ import LoopService from '../../api/LoopService';
const ModalStyled = styled(Modal)`
background-color: transparent;
`
-
export default class LoopProperties extends React.Component {
state = {
@@ -45,7 +44,7 @@ export default class LoopProperties extends React.Component {
this.handleClose = this.handleClose.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleChange = this.handleChange.bind(this);
-
+
this.renderDcaeParameters = this.renderDcaeParameters.bind(this);
this.renderAllParameters = this.renderAllParameters.bind(this);
this.getDcaeParameters = this.getDcaeParameters.bind(this);
@@ -55,7 +54,7 @@ export default class LoopProperties extends React.Component {
this.setState({
loopCache: newProps.loopCache,
temporaryPropertiesJson: JSON.parse(JSON.stringify(newProps.loopCache.getGlobalProperties())),
-
+
});
}
@@ -90,7 +89,7 @@ export default class LoopProperties extends React.Component {
} else {
return "";
}
-
+
}
renderDcaeParameters() {
diff --git a/ui-react/src/components/dialogs/OperationalPolicy/OperationalPolicyModal.js b/ui-react/src/components/dialogs/OperationalPolicy/OperationalPolicyModal.js
index 2a812c877..6db38fd23 100644
--- a/ui-react/src/components/dialogs/OperationalPolicy/OperationalPolicyModal.js
+++ b/ui-react/src/components/dialogs/OperationalPolicy/OperationalPolicyModal.js
@@ -24,8 +24,9 @@
import React from 'react'
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
-import './OperationalPolicy.css'
import styled from 'styled-components';
+import LoopService from '../../../api/LoopService';
+import JSONEditor from '@json-editor/json-editor';
const ModalStyled = styled(Modal)`
background-color: transparent;
@@ -36,512 +37,94 @@ export default class OperationalPolicyModal extends React.Component {
state = {
show: true,
loopCache: this.props.loopCache,
+ jsonEditor: null,
};
- allPolicies = [];
- policyIds = [];
-
constructor(props, context) {
super(props, context);
-
this.handleClose = this.handleClose.bind(this);
- this.initPolicySelect = this.initPolicySelect.bind(this);
- this.initPolicySelect();
+ this.handleSave = this.handleSave.bind(this);
+ this.renderJsonEditor = this.renderJsonEditor.bind(this);
+ this.setDefaultJsonEditorOptions();
}
- handleClose() {
- this.setState({ show: false });
- this.props.history.push('/')
- }
+ handleSave() {
+ var errors = this.state.jsonEditor.validate();
+ var editorData = this.state.jsonEditor.getValue();
- initPolicySelect() {
- if (this.allPolicies['operational_policy'] === undefined || this.allPolicies['operational_policy'] === null) {
- this.allPolicies = this.state.loopCache.getOperationalPolicyConfigurationJson();
+ if (errors.length !== 0) {
+ console.error("Errors detected during config policy data validation ", errors);
+ alert(errors);
}
- // Provision all policies ID first
- if (this.policyIds.length === 0 && this.allPolicies['operational_policy'] !== undefined) {
-
- for (let i = 0; i < this.allPolicies['operational_policy']['policies'].length; i++) {
- this.policyIds.push(this.allPolicies['operational_policy']['policies'][i]['id']);
- }
+ else {
+ console.info("NO validation errors found in config policy data");
+ this.state.loopCache.updateOperationalPolicyProperties(editorData);
+ LoopService.setOperationalPolicyProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getOperationalPolicies()).then(resp => {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ this.props.loadLoopFunction(this.state.loopCache.getLoopName());
+ });
}
}
- renderPolicyIdSelect() {
- return (
- <select type="text" id="trigger_policy" name="trigger_policy"
- className="form-control">
- <option value="">-- choose an option --</option>
- {this.policyIds.map(policyId => (<option key={policyId}>{policyId}</option>))}
- </select>
- );
+ handleClose() {
+ this.setState({ show: false });
+ this.props.history.push('/');
}
- serializeElement(element) {
- var o = {};
- element.serializeArray().forEach(function () {
- if (o[this.name]) {
- if (!o[this.name].push) {
- o[this.name] = [o[this.name]];
- }
- o[this.name].push(this.value || '');
- } else {
- o[this.name] = this.value || '';
- }
- });
- return o;
+ componentDidMount() {
+ this.renderJsonEditor();
}
- // When we change the name of a policy
- isDuplicatedId(event) {
- // update policy id structure
- var formNum = document.getElementById(event.target).closest('.formId').attr('id').substring(6);
- var policyId = document.getElementById(event.target).val();
- if (this.policyIds.includes(policyId)) {
- console.log("Duplicated ID, cannot proceed");
- return true;
- } else {
- this.duplicated = false;
- this.policyIds.splice(this.policyIds.indexOf(document.getElementById("#formId" + formNum + " #id").val()), 1);
- this.policyIds.push(document.getElementById(event.target).val());
- // Update the tab now
- document.getElementById("#go_properties_tab" + formNum).text(document.getElementById(event.target).val());
- }
+ setDefaultJsonEditorOptions() {
+ JSONEditor.defaults.options.theme = 'bootstrap4';
+ // JSONEditor.defaults.options.iconlib = 'bootstrap2';
+
+ JSONEditor.defaults.options.object_layout = 'grid';
+ JSONEditor.defaults.options.disable_properties = true;
+ JSONEditor.defaults.options.disable_edit_json = false;
+ JSONEditor.defaults.options.disable_array_reorder = true;
+ JSONEditor.defaults.options.disable_array_delete_last_row = true;
+ JSONEditor.defaults.options.disable_array_delete_all_rows = false;
+ JSONEditor.defaults.options.array_controls_top=true;
+ JSONEditor.defaults.options.show_errors = 'always';
+ JSONEditor.defaults.options.keep_oneof_values=false;
+ JSONEditor.defaults.options.ajax=true;
+ JSONEditor.defaults.options.collapsed=true;
+ //JSONEditor.defaults.options.template = 'default';
}
+
+ renderJsonEditor() {
+ console.debug("Rendering OperationalPolicyModal");
+ var schema_json = this.state.loopCache.getOperationalPolicyJsonSchema();
+
+ if (schema_json == null) {
+ console.error("NO Operational policy schema found");
+ return;
+ }
+ var operationalPoliciesData = this.state.loopCache.getOperationalPolicies();
- configureComponents() {
- console.log("Load properties to op policy");
- // Set the header
- document.getElementsByClassName('form-control').forEach(function () {
- this.val(this.allPolicies['operational_policy']['controlLoop'][this.id]);
- });
- // Set the sub-policies
- this.allPolicies['operational_policy']['policies'].forEach(function (opPolicyElemIndex, opPolicyElemValue) {
-
- /* var formNum = add_one_more();
- forEach(document.getElementsByClassName('policyProperties').find('.form-control'), function(opPolicyPropIndex, opPolicyPropValue) {
-
- $("#formId" + formNum + " .policyProperties").find("#" + opPolicyPropValue.id).val(
- allPolicies['operational_policy']['policies'][opPolicyElemIndex][opPolicyPropValue.id]);
- });
-
- // Initial TargetResourceId options
- initTargetResourceIdOptions(allPolicies['operational_policy']['policies'][opPolicyElemIndex]['target']['type'], formNum);
- $.each($('.policyTarget').find('.form-control'), function(opPolicyTargetPropIndex, opPolicyTargetPropValue) {
-
- $("#formId" + formNum + " .policyTarget").find("#" + opPolicyTargetPropValue.id).val(
- allPolicies['operational_policy']['policies'][opPolicyElemIndex]['target'][opPolicyTargetPropValue.id]);
- });
-
- // update the current tab label
- $("#go_properties_tab" + formNum).text(
- allPolicies['operational_policy']['policies'][opPolicyElemIndex]['id']);
- // Check if there is a guard set for it
- $.each(allPolicies['guard_policies'], function(guardElemId, guardElemValue) {
-
- if (guardElemValue.recipe === $($("#formId" + formNum + " #recipe")[0]).val()) {
- // Found one, set all guard prop
- $.each($('.guardProperties').find('.form-control'), function(guardPropElemIndex,
- guardPropElemValue) {
-
- guardElemValue['id'] = guardElemId;
- $("#formId" + formNum + " .guardProperties").find("#" + guardPropElemValue.id).val(
- guardElemValue[guardPropElemValue.id]);
- });
- iniGuardPolicyType(guardElemId, formNum);
- // And finally enable the flag
- $("#formId" + formNum + " #enableGuardPolicy").prop("checked", true);
- }
- });*/
- });
+ this.setState({
+ jsonEditor: new JSONEditor(document.getElementById("editor"),
+ { schema: schema_json.schema, startval: operationalPoliciesData })
+ })
}
render() {
return (
- <ModalStyled size="lg" show={this.state.show} onHide={this.handleClose}>
+ <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Operational policies</Modal.Title>
</Modal.Header>
<Modal.Body>
- <div attribute-test="policywindowproperties" id="configure-widgets"
- className="disabled-block-container">
- <div attribute-test="policywindowpropertiesb" className="modal-body row">
- <div className="panel panel-default col-sm-10 policyPanel">
- <form id="operationalPolicyHeaderForm" className="form-horizontal">
- <div className="form-group clearfix">
- <label className="col-sm-2">Parent policy</label>
- <div className="col-sm-3" style={{ padding: '0px' }}>
- {this.renderPolicyIdSelect()}
- </div>
-
- <label htmlFor="timeout" className="col-sm-3"
- style={{ paddingLeft: '5px', paddingRight: '10px' }}>Overall
- Time Limit</label>
- <div className="col-sm-2" style={{ paddingLeft: '0px' }}>
- <input type="text" ng-pattern="/^[0-9]*$/" ng-model="number"
- className="form-control" id="timeout" name="timeout" />
- </div>
-
- <label htmlFor="abatement" className="col-sm-2">Abatement</label>
- <div className="col-sm-2" style={{ paddingLeft: '0px' }}>
- <select className="form-control" id="abatement" name="abatement">
- <option value="false">False</option>
- <option value="true">True</option>
- </select>
- </div>
- </div>
- <div className="form-group clearfix row">
- <label className="col-sm-4 control-label" htmlFor="clname">ControlLoopName</label>
- <div className="col-sm-8">
- <input type="text" className="form-control" name="controlLoopName"
- readOnly="readonly" id="clname" value={this.state.loopCache.getLoopName()} />
- </div>
- </div>
- </form>
- <div className="panel-heading" style={{ backgroundColor: 'white' }}>
- <ul id="nav_Tabs" className="nav nav-tabs">
- <li>
- <a id="add_one_more" href="#desc_tab">
- <span
- className="glyphicon glyphicon-plus" aria-hidden="true">
- </span>
- </a>
- </li>
- </ul>
- </div>
- <div className="panel-body">
- <div className="tab-content">
- <div id="properties_tab" className="tab-pane fade in active"></div>
- </div>
- </div>
- </div>
-
- <span id="formSpan" style={{ display: 'none' }}>
- <form className="policyProperties form-horizontal"
- style={{ border: '2px dotted gray' }}
- title="Operational Policy Properties">
- <div className="form-group clearfix">
- <label className="col-sm-4 control-label" htmlFor="id">ID</label>
- <div className="col-sm-8">
- <input type="text" className="form-control" name="id" id="id"
- onKeyUp="updateTabLabel($event)" />
- <span >ID must be unique</span>
- </div>
- </div>
- <div className="form-group clearfix">
- <label className="col-sm-4 control-label" htmlFor="recipe">Recipe</label>
- <div className="col-sm-8">
- <select className="form-control" name="recipe" id="recipe"
- ng-model="recipe" ng-click="updateGuardRecipe($event)">
- <option value="">-- choose an option --</option>
- <option value="Restart">Restart</option>
- <option value="Rebuild">Rebuild</option>
- <option value="Migrate">Migrate</option>
- <option value="Health-Check">Health-Check</option>
- <option value="ModifyConfig">ModifyConfig</option>
- <option value="VF Module Create">VF Module Create</option>
- <option value="VF Module Delete">VF Module Delete</option>
- <option value="Reroute">Reroute</option>
- </select>
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="retry" className="col-sm-4 control-label"> Retry</label>
- <div className="col-sm-8">
- <input type="text" maxLength="5" className="form-control" id="retry"
- ng-pattern="/^[0-9]*$/" ng-model="number" name="retry">
- </input>
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="timeout" className="col-sm-4 control-label">
- Timeout</label>
- <div className="col-sm-8">
- <input type="text" maxLength="5" className="form-control"
- id="timeout" ng-pattern="/^[0-9]*$/" ng-model="number"
- name="timeout"></input>
- </div>
- </div>
-
- <div className="form-group clearfix">
- <label htmlFor="actor" className="col-sm-4 control-label"> Actor</label>
- <div className="col-sm-8">
- <select className="form-control" id="actor" name="actor" ng-click="updateGuardActor($event)" ng-model="actor">
- <option value="">-- choose an option --</option>
- <option value="APPC">APPC</option>
- <option value="SO">SO</option>
- <option value="VFC">VFC</option>
- <option value="SDNC">SDNC</option>°
- <option value="SDNR">SDNR</option>°
- </select>
- </div>
-
- <label htmlFor="payload" className="col-sm-4 control-label">
- Payload (YAML)</label>
- <div className="col-sm-8">
- <textarea className="form-control" id="payload" name="payload"></textarea>
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="success" className="col-sm-4 control-label">When
- Success</label>
- <div className="col-sm-8">
- <select className="form-control" id="success" name="success"
- ng-model="null_dump"
- ng-options="policy for policy in policy_ids track by policy">
- <option value="">-- choose an option --</option>
- </select>
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="failure" className="col-sm-4 control-label">When
- Failure</label>
- <div className="col-sm-8">
- <select className="form-control" id="failure" name="failure"
- ng-model="null_dump"
- ng-options="policy for policy in policy_ids track by policy">
- <option value="">-- choose an option --</option>
- </select>
-
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="failure_timeout" className="col-sm-4 control-label">When
- Failure Timeout</label>
- <div className="col-sm-8">
- <select className="form-control" id="failure_timeout"
- name="failure_timeout" ng-model="null_dump"
- ng-options="policy for policy in policy_ids track by policy">
- <option value="">-- choose an option --</option>
- </select>
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="failure_retries" className="col-sm-4 control-label">When
- Failure Retries</label>
- <div className="col-sm-8">
- <select className="form-control" id="failure_retries"
- name="failure_retries" ng-model="null_dump"
- ng-options="policy for policy in policy_ids track by policy">
- <option value="">-- choose an option --</option>
- </select>
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="failure_exception" className="col-sm-4 control-label">When
- Failure Exception</label>
- <div className="col-sm-8">
- <select className="form-control" id="failure_exception"
- name="failure_exception" ng-model="null_dump"
- ng-options="policy for policy in policy_ids track by policy">
- <option value="">-- choose an option --</option>
- </select>
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="failure_guard" className="col-sm-4 control-label">When
- Failure Guard</label>
- <div className="col-sm-8">
- <select className="form-control" id="failure_guard"
- name="failure_guard" ng-model="null_dump"
- ng-options="policy for policy in policy_ids track by policy">
- <option value="">-- choose an option --</option>
- </select>
- </div>
- </div>
- </form>
- <form className="policyTarget form-horizontal"
- title="Operational Policy Target" style={{ border: '2px dotted gray' }}>
- <div className="form-group clearfix">
- <label htmlFor="type" className="col-sm-4 control-label"> Target
- Type</label>
- <div className="col-sm-8">
- <select className="form-control" name="type" id="type"
- ng-click="initTargetResourceId($event)" ng-model="type">
- <option value="">-- choose an option --</option>
- <option value="VFMODULE">VFMODULE</option>
- <option value="VM">VM</option>
- <option value="VNF">VNF</option>
- </select>
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="resourceID" className="col-sm-4 control-label">
- Target ResourceId</label>
- <div className="col-sm-8">
- <select className="form-control" name="resourceID" id="resourceID"
- ng-click="changeTargetResourceId($event)"
- ng-model="resourceId">
- <option value="">-- choose an option --</option>
- </select>
- </div>
- </div>
- <div id="metadata">
- <div className="form-group clearfix">
- <label htmlFor="modelInvariantId" className="col-sm-4 control-label">
- Model Invariant Id</label>
- <div className="col-sm-8">
- <input className="form-control" name="modelInvariantId"
- id="modelInvariantId" readOnly />
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="modelVersionId" className="col-sm-4 control-label">
- Model Version Id</label>
- <div className="col-sm-8">
- <input className="form-control" name="modelVersionId"
- id="modelVersionId" readOnly />
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="modelName" className="col-sm-4 control-label">
- Model Name</label>
- <div className="col-sm-8">
- <input className="form-control" name="modelName" id="modelName"
- readOnly />
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="modelVersion" className="col-sm-4 control-label">
- Model Version</label>
- <div className="col-sm-8">
- <input className="form-control" name="modelVersion"
- id="modelVersion" readOnly />
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="modelCustomizationId" className="col-sm-4 control-label">
- Model Customization Id</label>
- <div className="col-sm-8">
- <input className="form-control" name="modelCustomizationId"
- id="modelCustomizationId" readOnly />
- </div>
- </div>
- </div>
- </form>
- <div className="form-group clearfix">
- <label htmlFor="enableGuardPolicy" className="col-sm-4 control-label">
- Enable Guard Policy</label>
- <div className="col-sm-8">
- <input type="checkbox" className="form-control"
- name="enableGuardPolicy" id="enableGuardPolicy" />
- </div>
-
- <div className="col-sm-8">
- <label htmlFor="guardPolicyType" className="col-sm-4 control-label">
- Guard Policy Type</label> <select className="form-control"
- name="guardPolicyType" id="guardPolicyType"
- ng-click="changeGuardPolicyType()" ng-model="guardType">
- <option value="GUARD_MIN_MAX">MinMax</option>
- <option value="GUARD_YAML">FrequencyLimiter</option>
- </select>
- </div>
- </div>
- <form className="guardProperties form-horizontal"
- title="Guard policy associated" style={{ border: '2px dotted gray' }}>
-
- <div className="form-group clearfix withnote">
- <label className="col-sm-4 control-label" htmlFor="id">Guard Policy ID</label>
- <div className="col-sm-8">
- <input type="text" className="form-control" name="id" id="id" ng-blur="changeGuardId()" ng-model="id" />
- </div>
- </div>
- <div>
- <label className="form-group note">Note: Prefix will be added to Guard Policy ID automatically based on Guard Policy Type</label>
- </div>
- <div className="form-group clearfix">
- <label className="col-sm-4 control-label" htmlFor="recipe">Recipe</label>
- <div className="col-sm-8">
- <input type="text" className="form-control" name="recipe"
- readOnly="readonly" id="recipe" />
- </div>
- </div>
- <div className="form-group clearfix">
- <label className="col-sm-4 control-label" htmlFor="clname">ControlLoopName</label>
- <div className="col-sm-8">
- <input type="text" className="form-control" name="clname"
- readOnly="readonly" id="clname" ng-model="clname" />
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="actor" className="col-sm-4 control-label">Actor</label>
- <div className="col-sm-8">
- <input type="text" className="form-control" name="actor"
- readOnly="readonly" id="actor" />
- </div>
- </div>
- <div className="form-group clearfix">
-
- <label htmlFor="targets" className="col-sm-4 control-label">Guard
- targets</label>
- <div className="col-sm-8">
- <input className="form-control" name="targets" id="targets" />
- </div>
- </div>
-
- <div className="form-group clearfix" id="minMaxGuardPolicyDiv">
- <label htmlFor="min" className="col-sm-4 control-label"> Min
- Guard</label>
- <div className="col-sm-8">
- <input className="form-control" name="min" id="min" />
- </div>
- <label htmlFor="max" className="col-sm-4 control-label"> Max
- Guard</label>
- <div className="col-sm-8">
- <input className="form-control" name="max" id="max" />
- </div>
- </div>
- <div className="form-group clearfix"
- id="frequencyLimiterGuardPolicyDiv" style={{ display: 'none' }}>
- <label htmlFor="limit" className="col-sm-4 control-label">Limit</label>
- <div className="col-sm-8">
- <input className="form-control" name="limit" id="limit" />
- </div>
- <label htmlFor="timeUnits" className="col-sm-4 control-label">Time Units</label>
- <div className="col-sm-8">
- <select className="form-control" name="timeUnits"
- id="timeUnits">
- <option value=""></option>
- <option value="minute">minute</option>
- <option value="hour">hour</option>
- <option value="day">day</option>
- <option value="week">week</option>
- <option value="month">month</option>
- <option value="year">year</option>
- </select>
- </div>
- <label htmlFor="timeWindow" className="col-sm-4 control-label">Time Window</label>
- <div className="col-sm-8">
- <input className="form-control" name="timeWindow" id="timeWindow" />
- </div>
- </div>
- <div className="form-group clearfix">
- <label htmlFor="guardActiveStart" className="col-sm-4 control-label">
- Guard Active Start</label>
- <div className="col-sm-8">
- <input className="form-control" name="guardActiveStart"
- id="guardActiveStart" value="00:00:00Z" />
- </div>
- <label htmlFor="guardActiveEnd" className="col-sm-4 control-label">
- Guard Active End</label>
- <div className="col-sm-8">
- <input className="form-control" name="guardActiveEnd"
- id="guardActiveEnd" value="00:00:01Z" />
- </div>
- </div>
-
- </form>
-
- </span>
- </div>
- </div>
+ <div id="editor" />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.handleClose}>
Close
</Button>
- <Button variant="primary" onClick={this.handleClose}>
+ <Button variant="primary" onClick={this.handleSave}>
Save Changes
</Button>
</Modal.Footer>
diff --git a/ui-react/src/components/dialogs/PerformActions.js b/ui-react/src/components/dialogs/PerformActions.js
new file mode 100644
index 000000000..9c34e141b
--- /dev/null
+++ b/ui-react/src/components/dialogs/PerformActions.js
@@ -0,0 +1,85 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import LoopActionService from '../../api/LoopActionService';
+import Spinner from 'react-bootstrap/Spinner'
+import styled from 'styled-components';
+
+const StyledSpinnerDiv = styled.div`
+ justify-content: center !important;
+ display: flex !important;
+`;
+
+export default class PerformActions extends React.Component {
+ state = {
+ loopName: this.props.loopCache.getLoopName(),
+ loopAction: this.props.loopAction
+ };
+ constructor(props, context) {
+ super(props, context);
+
+ this.refreshStatus = this.refreshStatus.bind(this);
+ }
+ componentWillReceiveProps(newProps) {
+ this.setState({
+ loopName: newProps.loopCache.getLoopName(),
+ loopAction: newProps.loopAction
+ });
+ }
+
+ componentDidMount() {
+ const action = this.state.loopAction;
+ const loopName = this.state.loopName;
+ console.log("Perform action:" + action);
+ LoopActionService.performAction(loopName, action).then(pars => {
+ alert("Action " + action + " successfully performed");
+ // refresh status and update loop logs
+ this.refreshStatus(loopName);
+ })
+ .catch(error => {
+ alert("Action " + action + " failed");
+ // refresh status and update loop logs
+ this.refreshStatus(loopName);
+ });
+
+ }
+
+ refreshStatus(loopName) {
+ LoopActionService.refreshStatus(loopName).then(data => {
+ this.props.updateLoopFunction(data);
+ this.props.history.push('/');
+ })
+ .catch(error => {
+ this.props.history.push('/');
+ });
+ }
+
+ render() {
+ return (
+ <StyledSpinnerDiv>
+ <Spinner animation="border" role="status">
+ </Spinner>
+ </StyledSpinnerDiv>
+ );
+ }
+}
diff --git a/ui-react/src/components/dialogs/RefreshStatus.js b/ui-react/src/components/dialogs/RefreshStatus.js
new file mode 100644
index 000000000..cf08655ee
--- /dev/null
+++ b/ui-react/src/components/dialogs/RefreshStatus.js
@@ -0,0 +1,66 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import LoopActionService from '../../api/LoopActionService';
+import Spinner from 'react-bootstrap/Spinner'
+import styled from 'styled-components';
+
+const StyledSpinnerDiv = styled.div`
+ justify-content: center !important;
+ display: flex !important;
+`;
+
+export default class RefreshStatus extends React.Component {
+ state = {
+ loopName: this.props.loopCache.getLoopName()
+ };
+
+ componentWillReceiveProps(newProps) {
+ this.setState({
+ loopName: newProps.loopCache.getLoopName()
+ });
+ }
+
+ componentDidMount() {
+ console.log("Refresh status for: " + this.state.loopName);
+ // refresh status and update loop logs
+ LoopActionService.refreshStatus(this.state.loopName).then(data => {
+ alert("Status successfully refreshed")
+ this.props.updateLoopFunction(data);
+ this.props.history.push('/');
+ })
+ .catch(error => {
+ alert("Status refreshing failed");
+ this.props.history.push('/');
+ });
+ }
+
+ render() {
+ return (
+ <StyledSpinnerDiv>
+ <Spinner animation="border" role="status">
+ </Spinner>
+ </StyledSpinnerDiv>
+ );
+ }
+}
diff --git a/ui-react/src/components/loop_viewer/svg/LoopSvg.js b/ui-react/src/components/loop_viewer/svg/LoopSvg.js
index 3ac2f31fd..1b1e24280 100644
--- a/ui-react/src/components/loop_viewer/svg/LoopSvg.js
+++ b/ui-react/src/components/loop_viewer/svg/LoopSvg.js
@@ -61,13 +61,14 @@ class LoopViewSvg extends React.Component {
return this.state.svgContent !== nextState.svgContent;
}
- componentWillReceiveProps(newProps) {
- this.setState({
- loopCache: newProps.loopCache,
- componentModalMapping: LoopComponentConverter.buildMapOfComponents(newProps.loopCache),
-
- });
- this.getSvg(newProps.loopCache.getLoopName());
+ componentWillReceiveProps(newProps) {
+ if (this.state.loopCache !== newProps.loopCache) {
+ this.setState({
+ loopCache: newProps.loopCache,
+ componentModalMapping: LoopComponentConverter.buildMapOfComponents(newProps.loopCache),
+ });
+ this.getSvg(newProps.loopCache.getLoopName());
+ }
}
getSvg(loopName) {
@@ -79,6 +80,8 @@ class LoopViewSvg extends React.Component {
this.setState({ svgContent: LoopViewSvg.emptySvg })
}
});
+ } else {
+ this.setState({ svgContent: LoopViewSvg.emptySvg })
}
}
diff --git a/ui-react/src/components/menu/MenuBar.js b/ui-react/src/components/menu/MenuBar.js
index 811a48ba0..121787ffd 100644
--- a/ui-react/src/components/menu/MenuBar.js
+++ b/ui-react/src/components/menu/MenuBar.js
@@ -21,21 +21,14 @@
*
*/
import React from 'react';
+import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
+import LoopUI from '../../LoopUI';
import 'bootstrap-css-only/css/bootstrap.min.css';
import styled from 'styled-components';
import { Link } from 'react-router-dom'
-const StyledNavDropdownItem = styled(NavDropdown.Item)`
- color: ${props => props.theme.menuFontColor};
- background-color: ${props => props.theme.menuBackgroundColor};
- :hover {
- background-color: ${props => props.theme.menuHighlightedBackgroundColor};
- color: ${props => props.theme.menuHighlightedFontColor};
- }
-`;
-
const StyledLink = styled(Link)`
color: ${props => props.theme.menuColor};
background-color: ${props => props.theme.menuBackgroundColor};
@@ -53,31 +46,53 @@ const StyledLink = styled(Link)`
color: ${props => props.theme.loopViewerHeaderFontColor};
}
`;
-
+const StyledNavLink = styled(Nav.Link)`
+ color: ${props => props.theme.menuColor};
+ background-color: ${props => props.theme.menuBackgroundColor};
+ font-weight: normal;
+ padding: .25rem 1.5rem;
+ :hover {
+ background-color: ${props => props.theme.loopViewerHeaderBackgroundColor};
+ color: ${props => props.theme.loopViewerHeaderFontColor}
+ }
+`;
export default class MenuBar extends React.Component {
+ state = {
+ loopName: this.props.loopName,
+ disabled: true
+ };
+
+ componentWillReceiveProps(newProps) {
+ if (newProps.loopName !== LoopUI.defaultLoopName) {
+ this.setState({ disabled: false });
+ } else {
+ this.setState({ disabled: true });
+ }
+ }
+
render () {
return (
- <Navbar.Collapse id="basic-navbar-nav" className="justify-content-center">
- <NavDropdown title="Closed Loop" id="basic-nav-dropdown">
- <StyledNavDropdownItem as={StyledLink} to="/openLoop">Open CL</StyledNavDropdownItem>
- <StyledNavDropdownItem as={StyledLink} to="/loopProperties">Properties CL</StyledNavDropdownItem>
- <StyledNavDropdownItem as={StyledLink} to="/closeLoop">Close Model</StyledNavDropdownItem>
+ <Navbar.Collapse>
+ <NavDropdown title="Closed Loop">
+ <NavDropdown.Item as={StyledLink} to="/openLoop">Open CL</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/loopProperties" disabled={this.state.disabled}>Properties CL</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/closeLoop" disabled={this.state.disabled}>Close Model</NavDropdown.Item>
</NavDropdown>
- <NavDropdown title="Manage" id="basic-nav-dropdown">
- <StyledNavDropdownItem as={StyledLink} to="/operationalPolicyModal">Submit</StyledNavDropdownItem>
- <StyledNavDropdownItem as={StyledLink} to="#action/3.2">Stop</StyledNavDropdownItem>
- <StyledNavDropdownItem as={StyledLink} to="#action/3.3">Restart</StyledNavDropdownItem>
- <StyledNavDropdownItem as={StyledLink} to="#action/3.3">Delete</StyledNavDropdownItem>
- <StyledNavDropdownItem as={StyledLink} to="#action/3.3">Deploy</StyledNavDropdownItem>
- <StyledNavDropdownItem as={StyledLink} to="#action/3.3">UnDeploy</StyledNavDropdownItem>
+ <NavDropdown title="Manage">
+ <NavDropdown.Item as={StyledLink} to="/submit" disabled={this.state.disabled}>Submit</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/stop" disabled={this.state.disabled}>Stop</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/restart" disabled={this.state.disabled}>Restart</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/delete" disabled={this.state.disabled}>Delete</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/deploy" disabled={this.state.disabled}>Deploy</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/undeploy" disabled={this.state.disabled}>UnDeploy</NavDropdown.Item>
</NavDropdown>
- <NavDropdown title="View" id="basic-nav-dropdown">
- <StyledNavDropdownItem as={StyledLink} to="#action/3.1">Refresh Status</StyledNavDropdownItem>
+ <NavDropdown title="View">
+ <NavDropdown.Item as={StyledLink} to="/refreshStatus" disabled={this.state.disabled}>Refresh Status</NavDropdown.Item>
</NavDropdown>
- <NavDropdown title="Help" id="basic-nav-dropdown">
- <StyledNavDropdownItem href="https://wiki.onap.org/" target="_blank">Wiki</StyledNavDropdownItem>
- <StyledNavDropdownItem href="mailto:onap-discuss@lists.onap.org?subject=CLAMP&body=Please send us suggestions or feature enhancements or defect. If possible, please send us the steps to replicate any defect.">Contact Us</StyledNavDropdownItem>
- <StyledNavDropdownItem as={StyledLink} to="/userInfo">User Info</StyledNavDropdownItem>
+ <NavDropdown title="Help">
+ <StyledNavLink href="https://wiki.onap.org/" target="_blank">Wiki</StyledNavLink>
+ <StyledNavLink href="mailto:onap-discuss@lists.onap.org?subject=CLAMP&body=Please send us suggestions or feature enhancements or defect. If possible, please send us the steps to replicate any defect.">Contact Us</StyledNavLink>
+ <NavDropdown.Item as={StyledLink} to="/userInfo">User Info</NavDropdown.Item>
</NavDropdown>
</Navbar.Collapse>
);
diff --git a/ui-react/src/index.js b/ui-react/src/index.js
index 39df36427..cbbdc65ef 100644
--- a/ui-react/src/index.js
+++ b/ui-react/src/index.js
@@ -32,7 +32,7 @@ const routing = (
</BrowserRouter>
);
-ReactDOM.render(
+export var mainClamp = ReactDOM.render(
routing,
document.getElementById('root')
)
diff --git a/ui-react/src/theme/globalStyle.js b/ui-react/src/theme/globalStyle.js
index cbd86b199..0f6fb91c6 100644
--- a/ui-react/src/theme/globalStyle.js
+++ b/ui-react/src/theme/globalStyle.js
@@ -65,6 +65,19 @@ export const GlobalClampStyle = createGlobalStyle`
width: 100%;
height: 100%;
}
+
+ button {
+ background-color: ${props => (props.theme.loopViewerHeaderBackgroundColor)};
+ border: 1px;
+ color: white;
+ padding: 15px 32px;
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ font-size: ${props => props.theme.fontSize};
+ font-family: ${props => props.theme.fontFamily};
+
+ }
`
export const DefaultClampTheme = {