From dd1fd8d3f4f30766a82f7c5200400bedec683354 Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Thu, 30 Jul 2020 18:05:02 -0400 Subject: Add Step classes for usecases controller Add usecases-specific classes for managing preprocessor steps. Issue-ID: POLICY-2748 Change-Id: I62a2bf8fbeb656a5017531a3f3de6a6dbad5a004 Signed-off-by: Jim Hahn --- .../apps/controller/usecases/step/AaiCqStep2.java | 66 ++++ .../controller/usecases/step/AaiGetPnfStep2.java | 70 ++++ .../usecases/step/AaiGetTenantStep2.java | 94 +++++ .../usecases/step/GetTargetEntityStep2.java | 60 +++ .../apps/controller/usecases/step/GuardStep2.java | 115 ++++++ .../apps/controller/usecases/step/LockStep2.java | 71 ++++ .../apps/controller/usecases/step/Step2.java | 433 +++++++++++++++++++++ 7 files changed, 909 insertions(+) create mode 100644 controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2.java create mode 100644 controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2.java create mode 100644 controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2.java create mode 100644 controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2.java create mode 100644 controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2.java create mode 100644 controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2.java create mode 100644 controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/Step2.java (limited to 'controlloop/common/controller-usecases/src/main/java') diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2.java new file mode 100644 index 000000000..9ae1d7fb0 --- /dev/null +++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 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.policy.drools.apps.controller.usecases.step; + +import org.onap.policy.aai.AaiCqResponse; +import org.onap.policy.controlloop.actor.aai.AaiActor; +import org.onap.policy.controlloop.actor.aai.AaiCustomQueryOperation; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; + +/** + * Wrapper for {@link AaiCustomQueryOperation}. The {@link #success(OperationOutcome)} + * method stores the resultant "tenant" object in the step's context. + */ +public class AaiCqStep2 extends Step2 { + + /** + * Constructs the object using information from another step. + * + * @param otherStep step whose information should be used + */ + public AaiCqStep2(Step2 otherStep) { + super(otherStep, AaiActor.NAME, AaiCustomQueryOperation.NAME); + } + + /** + * Skips the operation if we already have the data. + */ + @Override + public boolean start(long remainingMs) { + if (stepContext.contains(AaiCqResponse.CONTEXT_KEY)) { + // already have the data + return false; + } + + return super.start(remainingMs); + } + + /** + * Saves the response for later use. + */ + @Override + public void success(OperationOutcome outcome) { + AaiCqResponse resp = outcome.getResponse(); + stepContext.setProperty(AaiCqResponse.CONTEXT_KEY, resp); + + super.success(outcome); + } +} diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2.java new file mode 100644 index 000000000..131daef9d --- /dev/null +++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 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.policy.drools.apps.controller.usecases.step; + +import org.onap.policy.common.utils.coder.StandardCoderObject; +import org.onap.policy.controlloop.actor.aai.AaiActor; +import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; + +/** + * Wrapper for {@link AaiGetPnfOperation}. The {@link #success(OperationOutcome)} method + * stores the resultant PNF object in the step's context. + *

+ * Note: this assumes that the target entity is one of the properties returned by + * {@link AaiGetPnfOperation#getPropertyNames()}. + */ +public class AaiGetPnfStep2 extends Step2 { + + + /** + * Constructs the object using information from another step. + * + * @param otherStep step whose information should be used + */ + public AaiGetPnfStep2(Step2 otherStep) { + super(otherStep, AaiActor.NAME, AaiGetPnfOperation.NAME); + } + + /** + * Skips the operation if we already have the data. + */ + @Override + public boolean start(long remainingMs) { + if (stepContext.contains(AaiGetPnfOperation.getKey(getTargetEntity()))) { + // already have the data + return false; + } + + return super.start(remainingMs); + } + + /** + * Saves the response for later use. + */ + @Override + public void success(OperationOutcome outcome) { + StandardCoderObject resp = outcome.getResponse(); + stepContext.setProperty(AaiGetPnfOperation.getKey(getTargetEntity()), resp); + + super.success(outcome); + } +} diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2.java new file mode 100644 index 000000000..d1851dd42 --- /dev/null +++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 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.policy.drools.apps.controller.usecases.step; + +import java.util.Collections; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.onap.policy.common.utils.coder.StandardCoderObject; +import org.onap.policy.controlloop.actor.aai.AaiActor; +import org.onap.policy.controlloop.actor.aai.AaiGetTenantOperation; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.OperationProperties; + +/** + * Wrapper for {@link AaiGetTenantOperation}. The vserver name is extracted from the + * enrichment data and passed as the target entity for the operation. The + * {@link #success(OperationOutcome)} method stores the resultant "tenant" object in the + * step's context. + */ +public class AaiGetTenantStep2 extends Step2 { + + private final String vserver; + + + /** + * Constructs the object using information from another step. + * + * @param otherStep step whose information should be used + */ + public AaiGetTenantStep2(Step2 otherStep) { + super(otherStep, AaiActor.NAME, AaiGetTenantOperation.NAME); + + vserver = event.getAai().get(VSERVER_VSERVER_NAME); + if (StringUtils.isBlank(vserver)) { + throw new IllegalArgumentException("missing " + VSERVER_VSERVER_NAME + " in enrichment data"); + } + } + + /** + * The vserver is passed as the target entity, thus we don't need to include the + * target entity in the property list. + */ + @Override + public List getPropertyNames() { + return Collections.emptyList(); + } + + @Override + public void setProperties() { + getOperation().setProperty(OperationProperties.AAI_TARGET_ENTITY, vserver); + } + + /** + * Skips the operation if we already have the data. + */ + @Override + public boolean start(long remainingMs) { + if (stepContext.contains(AaiGetTenantOperation.getKey(vserver))) { + // already have the data + return false; + } + + return super.start(remainingMs); + } + + /** + * Saves the response for later use. + */ + @Override + public void success(OperationOutcome outcome) { + StandardCoderObject resp = outcome.getResponse(); + stepContext.setProperty(AaiGetTenantOperation.getKey(vserver), resp); + + super.success(outcome); + } +} diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2.java new file mode 100644 index 000000000..06201b13c --- /dev/null +++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 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.policy.drools.apps.controller.usecases.step; + +import org.onap.policy.controlloop.actorserviceprovider.Operation; +import org.onap.policy.drools.apps.controller.usecases.GetTargetEntityOperation2; +import org.onap.policy.drools.apps.controller.usecases.UsecasesConstants; + +/** + * Wrapper for {@link GetTargetEntityOperation2}. The {@link #start(long)} method always + * returns {@code false}, as the Operation should never actually be started. + */ +public class GetTargetEntityStep2 extends Step2 { + + + /** + * Constructs the object using information from another step. + * + * @param otherStep step whose information should be used + */ + public GetTargetEntityStep2(Step2 otherStep) { + super(otherStep, UsecasesConstants.GET_TARGET_ENTITY_ACTOR, UsecasesConstants.GET_TARGET_ENTITY_OPERATION); + } + + @Override + protected Operation buildOperation() { + return new GetTargetEntityOperation2(stepContext, event, params); + } + + /** + * The operation does not actually have to be executed, as it populates the target + * entity as soon as {@link Operation#setProperty(String, Object)} is invoked. + */ + @Override + public boolean start(long remainingMs) { + if (!isInitialized()) { + throw new IllegalStateException("step has not been initialized"); + } + + return false; + } +} diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2.java new file mode 100644 index 000000000..b7247ce69 --- /dev/null +++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2.java @@ -0,0 +1,115 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 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.policy.drools.apps.controller.usecases.step; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.onap.policy.controlloop.actor.guard.DecisionOperation; +import org.onap.policy.controlloop.actor.guard.GuardActor; +import org.onap.policy.controlloop.actor.so.VfModuleCreate; +import org.onap.policy.controlloop.actorserviceprovider.Operation; +import org.onap.policy.controlloop.actorserviceprovider.OperationProperties; + +/** + * Wrapper for a Guard operation. Note: this makes a clone of the operation parameters, + * replacing the payload. It overrides the operation's property names with that are + * relevant for guards. In addition, it overrides the relevant loadXxx() methods to load + * the data into the payload instead of into the operation's properties. It also + * increments or decrements the VF Count, depending whether the operation is a "VF Module + * Create" or not. + */ +public class GuardStep2 extends Step2 { + public static final String PAYLOAD_KEY_TARGET_ENTITY = "target"; + public static final String PAYLOAD_KEY_VF_COUNT = "vfCount"; + + private final Operation policyOper; + + + /** + * Constructs the object using information from another step. + * + * @param otherStep step whose information should be used + */ + public GuardStep2(Step2 otherStep, String closedLoopControlName) { + super(otherStep, GuardActor.NAME, DecisionOperation.NAME); + + if (!otherStep.isInitialized()) { + throw new IllegalStateException("policy operation must be initialized before the guard operation"); + } + + this.policyOper = otherStep.getOperation(); + + Map payload = new LinkedHashMap<>(); + payload.put("actor", otherStep.getActorName()); + payload.put("operation", otherStep.getOperationName()); + payload.put("requestId", params.getRequestId()); + payload.put("clname", closedLoopControlName); + + params = params.toBuilder().payload(payload).build(); + } + + @Override + public boolean acceptsEvent() { + return true; + } + + /** + * Builds the list of properties on the policy's actual operation. + */ + @Override + public List getPropertyNames() { + List names = new ArrayList<>(1); + + // include VF Count if the policy's operation needs it + if (policyOper.getPropertyNames().contains(OperationProperties.DATA_VF_COUNT)) { + names.add(OperationProperties.DATA_VF_COUNT); + } + + return names; + } + + /** + * Load the target entity into the payload instead of the operation's properties. + */ + @Override + protected void loadTargetEntity(String propName) { + params.getPayload().put(PAYLOAD_KEY_TARGET_ENTITY, getTargetEntity()); + } + + /** + * Load the VF Count into the payload instead of the operation's properties. + * Increments the count for "VF Module Create". Decrements it otherwise. + */ + @Override + protected void loadVfCount(String propName) { + // run guard with the proposed VF count + int count = getVfCount(); + if (VfModuleCreate.NAME.equals(policyOper.getName())) { + ++count; + } else { + --count; + } + + params.getPayload().put(PAYLOAD_KEY_VF_COUNT, count); + } +} diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2.java new file mode 100644 index 000000000..507a08116 --- /dev/null +++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 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.policy.drools.apps.controller.usecases.step; + +import org.onap.policy.controlloop.actorserviceprovider.Operation; +import org.onap.policy.controlloop.eventmanager.ActorConstants; +import org.onap.policy.drools.apps.controller.usecases.LockOperation2; + +/** + * Wrapper for the LOCK pseudo operation. Arranges for the lock's future to generate an + * outcome. + */ +public class LockStep2 extends Step2 { + + /** + * Constructs the object using information from another step. + * + * @param otherStep step whose information should be used + */ + public LockStep2(Step2 otherStep) { + super(otherStep, ActorConstants.LOCK_ACTOR, ActorConstants.LOCK_OPERATION); + } + + @Override + public boolean acceptsEvent() { + return true; + } + + @Override + public boolean start(long remainingMs) { + super.start(remainingMs); + + if (future != null) { + future.whenComplete((outcome, thrown) -> { + outcome.setFinalOutcome(true); + params.getCompleteCallback().accept(outcome); + }); + } + + /* + * ELSE: The operation must have thrown an exception. Nothing more to do as + * super.start() will have already propagated the exception to the completion + * handler. + */ + + return true; + } + + @Override + protected Operation buildOperation() { + return new LockOperation2(stepContext, params); + } +} diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/Step2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/Step2.java new file mode 100644 index 000000000..9275f791d --- /dev/null +++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/Step2.java @@ -0,0 +1,433 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 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.policy.drools.apps.controller.usecases.step; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.onap.aai.domain.yang.CloudRegion; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ModelVer; +import org.onap.aai.domain.yang.ServiceInstance; +import org.onap.aai.domain.yang.Tenant; +import org.onap.policy.aai.AaiCqResponse; +import org.onap.policy.common.utils.coder.StandardCoderObject; +import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation; +import org.onap.policy.controlloop.actor.aai.AaiGetTenantOperation; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.OperationProperties; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.eventmanager.Step; +import org.onap.policy.controlloop.eventmanager.StepContext; +import org.onap.policy.drools.apps.controller.usecases.UsecasesConstants; + +/** + * Steps specific to the usecases controller. The {@link #setProperties()} method is used + * to load the various properties into the operation, extracting enrichment data where + * appropriate, and extracting other data from the step's context. For each property, + * there is a getXxx() method for extracting the value and a loadXxx() method for loading + * the extracted value into the operation. In addition, the + * {@link #success(OperationOutcome)} method is responsible for extracting responses from + * an operation outcome and recording the data in the step's context for use by subsequent + * steps. + */ +public class Step2 extends Step { + public static final String TARGET_INFO_MSG = "Target information"; + public static final String ENRICHMENT_PREFIX = "enrichment/"; + public static final String VSERVER_VSERVER_NAME = "vserver.vserver-name"; + public static final String RESOURCE_LINK = "resource-link"; + public static final String RESULT_DATA = "result-data"; + + private static final Map> PROPERTY_LOADER; + private static final Map> PROPERTY_SAVER; + + static { + /* + * Populate map for PROPERTY_LOADER. + */ + Map> map = new HashMap<>(); + + map.put(OperationProperties.AAI_DEFAULT_CLOUD_REGION, Step2::loadCloudRegion); + map.put(OperationProperties.AAI_DEFAULT_TENANT, Step2::loadTenant); + map.put(OperationProperties.AAI_PNF, Step2::loadPnf); + map.put(OperationProperties.AAI_RESOURCE_VNF, Step2::loadResourceVnf); + map.put(OperationProperties.AAI_SERVICE, Step2::loadService); + map.put(OperationProperties.AAI_SERVICE_MODEL, Step2::loadServiceModel); + map.put(OperationProperties.AAI_TARGET_ENTITY, Step2::loadTargetEntity); + map.put(OperationProperties.AAI_VNF, Step2::loadVnf); + map.put(OperationProperties.AAI_VNF_MODEL, Step2::loadVnfModel); + map.put(OperationProperties.AAI_VSERVER_LINK, Step2::loadVserverLink); + map.put(OperationProperties.DATA_VF_COUNT, Step2::loadVfCount); + map.put(OperationProperties.EVENT_ADDITIONAL_PARAMS, Step2::loadAdditionalEventParams); + map.put(OperationProperties.EVENT_PAYLOAD, Step2::loadEventPayload); + map.put(OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES, Step2::loadOptCdsGrpcAaiProperties); + + map.put(UsecasesConstants.AAI_DEFAULT_GENERIC_VNF, Step2::loadDefaultGenericVnf); + + PROPERTY_LOADER = Collections.unmodifiableMap(map); + + + /* + * Populate map for PROPERTY_SAVER. + */ + Map> map2 = new HashMap<>(); + + map2.put(OperationProperties.DATA_VF_COUNT, Step2::storeVfCount); + + PROPERTY_SAVER = Collections.unmodifiableMap(map2); + } + + + protected final StepContext stepContext; + protected final VirtualControlLoopEvent event; + + /** + * {@code True} if the associated preprocessing steps have been loaded, {@code false} + * otherwise. + */ + @Getter + @Setter + private boolean preprocessed; + + /** + * Actions to take to store the Operation's properties back into the context. + */ + private List> postProcessors = new LinkedList<>(); + + + /** + * Constructs the object. This is used when constructing the step for the policy's + * actual operation. + * + * @param stepContext the step's context + * @param params operation parameters + * @param event the event being processed + */ + public Step2(StepContext stepContext, ControlLoopOperationParams params, VirtualControlLoopEvent event) { + super(params, new AtomicReference<>()); + this.stepContext = stepContext; + this.event = event; + } + + /** + * Constructs the object using information from another step. This is used when + * constructing a preprocessing step. + * + * @param otherStep step whose information should be used + * @param actor actor name + * @param operation operation name + */ + public Step2(Step2 otherStep, String actor, String operation) { + super(otherStep, actor, operation); + this.stepContext = otherStep.stepContext; + this.event = otherStep.event; + } + + /** + * Determines if starting this step indicates acceptance of the event. The default + * method simply invokes {@link #isPolicyStep()}. + * + * @return {@code true} if this step accepts the event, {@code false} if it is still + * indeterminate + */ + public boolean acceptsEvent() { + return isPolicyStep(); + } + + /** + * Indicates that the step succeeded with the given outcome. Invoked by the rules. The + * default method invokes the post processors. + * + * @param outcome operation's outcome + */ + public void success(OperationOutcome outcome) { + for (Consumer proc : postProcessors) { + proc.accept(this); + } + } + + /** + * Gets the names of the properties required by the operation. The default method just + * delegates to the operation to identify the properties. + * + * @return the names of the properties required by the operation + */ + public List getPropertyNames() { + return getOperation().getPropertyNames(); + } + + /** + * Sets the operation's properties. This is invoked after any preprocessor + * steps have been performed. It also adds items to {@link #postProcessors}. + */ + public void setProperties() { + postProcessors.clear(); + + for (String propName : getPropertyNames()) { + // identify the saver, if any + Consumer saver = PROPERTY_SAVER.get(propName); + if (saver != null) { + postProcessors.add(saver); + } + + + // load data + if (propName.startsWith(ENRICHMENT_PREFIX)) { + loadEnrichment(propName); + continue; + } + + BiConsumer loader = PROPERTY_LOADER.get(propName); + if (loader == null) { + throw new IllegalArgumentException("unknown property " + propName + " needed by " + getActorName() + "." + + getOperationName()); + } + + loader.accept(this, propName); + } + } + + protected void loadCloudRegion(String propName) { + getOperation().setProperty(propName, getCloudRegion()); + } + + protected void loadTenant(String propName) { + getOperation().setProperty(propName, getTenant()); + } + + protected void loadPnf(String propName) { + getOperation().setProperty(propName, getPnf()); + } + + protected void loadResourceVnf(String propName) { + getOperation().setProperty(propName, getResourceVnf()); + } + + protected void loadService(String propName) { + getOperation().setProperty(propName, getService()); + } + + protected void loadServiceModel(String propName) { + getOperation().setProperty(propName, getServiceModel()); + } + + protected void loadTargetEntity(String propName) { + getOperation().setProperty(propName, getTargetEntity()); + } + + protected void loadVnf(String propName) { + getOperation().setProperty(propName, getVnf()); + } + + protected void loadVnfModel(String propName) { + getOperation().setProperty(propName, getVnfModel()); + } + + protected void loadVserverLink(String propName) { + getOperation().setProperty(propName, getVserverLink()); + } + + protected void loadVfCount(String propName) { + getOperation().setProperty(propName, getVfCount()); + } + + protected void loadEnrichment(String propName) { + getOperation().setProperty(propName, getEnrichment(propName)); + } + + protected void loadAdditionalEventParams(String propName) { + getOperation().setProperty(propName, getAdditionalEventParams()); + } + + protected void loadEventPayload(String propName) { + getOperation().setProperty(propName, getEventPayload()); + } + + protected void loadOptCdsGrpcAaiProperties(String propName) { + // do nothing + } + + protected void loadDefaultGenericVnf(String propName) { + getOperation().setProperty(propName, getDefaultGenericVnf()); + } + + protected CloudRegion getCloudRegion() { + AaiCqResponse aaicq = getCustomQueryData(); + return aaicq.getDefaultCloudRegion(); + } + + protected Tenant getTenant() { + AaiCqResponse aaicq = getCustomQueryData(); + return aaicq.getDefaultTenant(); + } + + protected StandardCoderObject getPnf() { + return stepContext.getProperty(AaiGetPnfOperation.getKey(getTargetEntity())); + } + + protected GenericVnf getResourceVnf() { + verifyNotNull(TARGET_INFO_MSG, params.getTarget()); + + String resourceId = params.getTarget().getResourceID(); + + verifyNotNull("Target resource ID", resourceId); + + AaiCqResponse aaicq = getCustomQueryData(); + return aaicq.getGenericVnfByModelInvariantId(resourceId); + } + + protected ServiceInstance getService() { + AaiCqResponse aaicq = getCustomQueryData(); + return aaicq.getServiceInstance(); + } + + protected ModelVer getServiceModel() { + AaiCqResponse aaicq = getCustomQueryData(); + ServiceInstance service = aaicq.getServiceInstance(); + return aaicq.getModelVerByVersionId(service.getModelVersionId()); + } + + /** + * The default method assumes there is only one target entity and that it's stored + * within the step's context. + */ + protected String getTargetEntity() { + return stepContext.getProperty(OperationProperties.AAI_TARGET_ENTITY); + } + + protected GenericVnf getVnf() { + verifyNotNull(TARGET_INFO_MSG, params.getTarget()); + + String modelInvariantId = params.getTarget().getModelInvariantId(); + + verifyNotNull("modelInvariantId", modelInvariantId); + + AaiCqResponse aaicq = getCustomQueryData(); + return aaicq.getGenericVnfByVfModuleModelInvariantId(modelInvariantId); + } + + protected ModelVer getVnfModel() { + GenericVnf vnf = getVnf(); + AaiCqResponse aaicq = getCustomQueryData(); + return aaicq.getModelVerByVersionId(vnf.getModelVersionId()); + } + + protected String getVserverLink() { + String vserver = event.getAai().get(VSERVER_VSERVER_NAME); + if (StringUtils.isBlank(vserver)) { + throw new IllegalArgumentException("missing " + VSERVER_VSERVER_NAME + " in enrichment data"); + } + + StandardCoderObject tenant = stepContext.getProperty(AaiGetTenantOperation.getKey(vserver)); + verifyNotNull("tenant data", tenant); + + String resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK); + verifyNotNull("tenant data resource-link", resourceLink); + + return stripPrefix(resourceLink, 3); + } + + protected Integer getVfCount() { + if (stepContext.contains(OperationProperties.DATA_VF_COUNT)) { + return stepContext.getProperty(OperationProperties.DATA_VF_COUNT); + } + + verifyNotNull(TARGET_INFO_MSG, params.getTarget()); + + String modelCustomizationId = params.getTarget().getModelCustomizationId(); + String modelInvariantId = params.getTarget().getModelInvariantId(); + String modelVersionId = params.getTarget().getModelVersionId(); + + verifyNotNull("target modelCustomizationId", modelCustomizationId); + verifyNotNull("target modelInvariantId", modelInvariantId); + verifyNotNull("target modelVersionId", modelVersionId); + + AaiCqResponse aaicq = getCustomQueryData(); + return aaicq.getVfModuleCount(modelCustomizationId, modelInvariantId, modelVersionId); + } + + protected String getEnrichment(String propName) { + String enrichmentKey = propName.substring(ENRICHMENT_PREFIX.length()); + String value = event.getAai().get(enrichmentKey); + verifyNotNull(propName, value); + + return value; + } + + protected Map getAdditionalEventParams() { + return event.getAdditionalEventParams(); + } + + protected String getEventPayload() { + return event.getPayload(); + } + + protected GenericVnf getDefaultGenericVnf() { + AaiCqResponse aaicq = getCustomQueryData(); + return aaicq.getDefaultGenericVnf(); + } + + protected AaiCqResponse getCustomQueryData() { + AaiCqResponse aaicq = stepContext.getProperty(AaiCqResponse.CONTEXT_KEY); + verifyNotNull("custom query data", aaicq); + + return aaicq; + } + + protected void storeVfCount() { + if (!getOperation().containsProperty(OperationProperties.DATA_VF_COUNT)) { + return; + } + + int vfcount = getOperation().getProperty(OperationProperties.DATA_VF_COUNT); + stepContext.setProperty(OperationProperties.DATA_VF_COUNT, vfcount); + } + + protected void verifyNotNull(String propName, Object value) { + if (value == null) { + throw new IllegalArgumentException( + "missing " + propName + " for " + getActorName() + "." + getOperationName()); + } + } + + protected static String stripPrefix(String resourceLink, int ncomponents) { + int previdx = -1; + for (int nslashes = 0; nslashes < ncomponents; ++nslashes) { + int idx = resourceLink.indexOf('/', previdx + 1); + if (idx < 0) { + break; + } + + previdx = idx; + } + + return resourceLink.substring(Math.max(0, previdx)); + } +} -- cgit 1.2.3-korg