diff options
author | Sirisha_Manchikanti <sirisha.manchikanti@est.tech> | 2021-05-07 15:17:52 +0100 |
---|---|---|
committer | Sirisha_Manchikanti <sirisha.manchikanti@est.tech> | 2021-05-13 09:00:52 +0100 |
commit | f83411a86e2277adae69e780e8511913d61a0f17 (patch) | |
tree | d75f197e703270cda608c9bd0d236f7ce8c12e13 /runtime/src/main/java/org | |
parent | cac5cc982413ab9593186d308eda8936e9603ad9 (diff) |
Modular structure of clamp including controlloop
This commit is the first commit that puts in multi module structure while
changing the existing CLAMP code as little as possible.
It adds a structure where common, models, participant and runtime are direct children under clamp,
and current clamp code is moved under runtime. This runtime directory will host controlloop
runtime code in later commits.
Issue-ID: POLICY-3215
Signed-off-by: Sirisha_Manchikanti <sirisha.manchikanti@est.tech>
Change-Id: I15bc8be92ed020343bff4024c4718fec462c40d7
Signed-off-by: liamfallon <liam.fallon@est.tech>
Diffstat (limited to 'runtime/src/main/java/org')
139 files changed, 17039 insertions, 0 deletions
diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/AuthorizationController.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/AuthorizationController.java new file mode 100644 index 000000000..89be4fc28 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/AuthorizationController.java @@ -0,0 +1,182 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2019, 2021 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 + * + * 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.clamp.authorization; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.util.Date; +import org.apache.camel.Exchange; +import org.onap.policy.clamp.clds.config.ClampProperties; +import org.onap.policy.clamp.clds.exception.NotAuthorizedException; +import org.onap.policy.clamp.clds.model.ClampInformation; +import org.onap.policy.clamp.clds.util.LoggingUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +/** + * Verify user has right permissions. + */ +@Component +public class AuthorizationController { + + protected static final EELFLogger logger = + EELFManager.getInstance().getLogger(AuthorizationController.class); + protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger(); + protected static final EELFLogger securityLogger = EELFManager.getInstance().getSecurityLogger(); + + // By default we'll set it to a default handler + @Autowired + private ClampProperties refProp; + + public static final String PERM_PREFIX = "security.permission.type."; + private static final String PERM_INSTANCE = "security.permission.instance"; + + private static String retrieveUserName(SecurityContext securityContext) { + if (securityContext == null || securityContext.getAuthentication() == null) { + return null; + } + if ((securityContext.getAuthentication().getPrincipal()) instanceof String) { + // anonymous case + return ((String) securityContext.getAuthentication().getPrincipal()); + } else { + return ((UserDetails) securityContext.getAuthentication().getPrincipal()).getUsername(); + } + } + + /** + * Get the principal name. + * + * @return The principal name + */ + public static String getPrincipalName(SecurityContext securityContext) { + String principal = AuthorizationController.retrieveUserName(securityContext); + return principal != null ? principal : "Not found"; + } + + /** + * Insert authorize the api based on the permission. + * + * @param camelExchange The Camel Exchange object containing the properties + * @param typeVar The type of the permissions + * @param instanceVar The instance of the permissions. e.g. dev + * @param action The action of the permissions. e.g. read + */ + public void authorize(Exchange camelExchange, String typeVar, String instanceVar, + String action) { + String type = refProp.getStringValue(PERM_PREFIX + typeVar); + String instance = refProp.getStringValue(PERM_INSTANCE); + + if (null == type || type.isEmpty()) { + // authorization is turned off, since the permission is not defined + return; + } + if (null != instanceVar && !instanceVar.isEmpty()) { + instance = instanceVar; + } + String principalName = AuthorizationController.getPrincipalName(SecurityContextHolder.getContext()); + SecureServicePermission perm = SecureServicePermission.create(type, instance, action); + Date startTime = new Date(); + LoggingUtils.setTargetContext("Clamp", "authorize"); + LoggingUtils.setTimeContext(startTime, new Date()); + securityLogger.debug("checking if {} has permission: {}", principalName, perm); + + if (!isUserPermitted(perm)) { + String msg = principalName + " does not have permission: " + perm; + LoggingUtils.setErrorContext("100", "Authorization Error"); + securityLogger.warn(msg); + throw new NotAuthorizedException(msg); + } + } + + /** + * Insert authorize the api based on the permission. + * + * @param inPermission Security permission in input + * @return True if user is permitted + */ + public boolean isUserPermitted(SecureServicePermission inPermission) { + + String principalName = AuthorizationController.getPrincipalName(SecurityContextHolder.getContext()); + // check if the user has the permission key or the permission key with a + // combination of all instance and/or all action. + if (hasRole(inPermission.getKey()) || hasRole(inPermission.getKeyAllInstance())) { + auditLogger.info("{} authorized because user has permission with * for instance: {}", + principalName, inPermission.getKey().replace("|", ":")); + return true; + // the rest of these don't seem to be required - isUserInRole method + // appears to take * as a wildcard + } else if (hasRole(inPermission.getKeyAllInstanceAction())) { + auditLogger.info( + "{} authorized because user has permission with * for instance and * for action: {}", + principalName, inPermission.getKey().replace("|", ":")); + return true; + } else if (hasRole(inPermission.getKeyAllAction())) { + auditLogger.info("{} authorized because user has permission with * for action: {}", + principalName, inPermission.getKey().replace("|", ":")); + return true; + } else { + return false; + } + } + + protected boolean hasRole(String role) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + return false; + } + for (GrantedAuthority auth : authentication.getAuthorities()) { + if (role.equals(auth.getAuthority())) { + return true; + } + } + return false; + } + + /** + * Gets clds info. CLDS IFO service will return 3 things 1. User Name 2. CLDS + * code version that is currently installed from pom.xml file 3. User + * permissions + * + * @return the clds info + */ + public ClampInformation getClampInformation() { + ClampInformation clampInfo = new ClampInformation(); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + return new ClampInformation(); + } + clampInfo.setUserName(AuthorizationController.getPrincipalName(SecurityContextHolder.getContext())); + for (GrantedAuthority auth : authentication.getAuthorities()) { + clampInfo.getAllPermissions().add(auth.getAuthority()); + } + return clampInfo; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/CldsUser.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/CldsUser.java new file mode 100644 index 000000000..8f1e2bf67 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/CldsUser.java @@ -0,0 +1,97 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.clamp.authorization; + +import java.util.Arrays; + +/** + * The class represents the CldsUser that can be extracted from cldsusers.json. + */ +public class CldsUser { + + private String user; + private String password; + private SecureServicePermission[] permissions; + + /** + * Returns the user. + * + * @return the user + */ + public String getUser() { + return user; + } + + /** + * Sets the user. + * + * @param user + * the user to set + */ + public void setUser(String user) { + this.user = user; + } + + /** + * Returns the password. + * + * @return the password + */ + public String getPassword() { + return password; + } + + /** + * Sets the password. + * + * @param password + * the password to set + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Returns the permissions. + * + * @return the permissions + */ + public SecureServicePermission[] getPermissions() { + return Arrays.copyOf(permissions, permissions.length); + } + + public String[] getPermissionsString() { + return Arrays.stream(getPermissions()).map(SecureServicePermission::getKey).toArray(String[]::new); + } + + /** + * Sets the permissions. + * + * @param permissionsArray + * the permissions to set + */ + public void setPermissions(SecureServicePermission[] permissionsArray) { + this.permissions = Arrays.copyOf(permissionsArray, permissionsArray.length); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermission.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermission.java new file mode 100644 index 000000000..41887a315 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermission.java @@ -0,0 +1,203 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017 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.clamp.authorization; + +/** + * Permission class that can be instantiated easily using constructor or factory + * methods. + */ +public class SecureServicePermission { + public static final String ALL = "*"; + + private String type; + private String instance; + private String action; + + /** + * Factory method to create permission given type, instance, and action. + * + * @param type type of the permission + * @param instance instance of the permission + * @param action action of the permission + * @return instance of SecureServicePermission with type, instance and action + */ + public static SecureServicePermission create(String type, String instance, String action) { + return new SecureServicePermission(type, instance, action); + } + + /** + * Factory method to create permission given type and instance. Default + * action to ALL/*. + * + * @param type type of the permission + * @param instance instance of the permission + * @return instance of SecureServicePermission with type, instance and default action + */ + public static SecureServicePermission create(String type, String instance) { + return new SecureServicePermission(type, instance, ALL); + } + + /** + * Factory method to create permission given type. Default instance and + * action to ALL/*. + * + * @param type type of the permission + * @return instance of SecureServicePermission with type and default instance and action + */ + public static SecureServicePermission create(String type) { + return new SecureServicePermission(type, ALL, ALL); + } + + /** + * Instantiate permission given type, instance, and action. + * + * @param type type of the permission + * @param instance instance of the permission + * @param action action of the permission + */ + public SecureServicePermission(String type, String instance, String action) { + this.type = type; + this.instance = instance; + this.action = action; + } + + /** + * Instantiate permission given type from concatenated string. + * + * @param concatenatedString + * the string type|instance|action, less than 3 params can be + * provided (e.g. "permission-type-cl", "permission-type-cl|dev", + * "permission-type-cl|dev|update" ) + */ + public SecureServicePermission(String concatenatedString) { + String[] userInfo = concatenatedString.split("[|]"); + // We should have at least 1 string + this.type = userInfo[0]; + this.instance = (userInfo.length > 1 ? userInfo[1] : ALL); + this.action = (userInfo.length > 2 ? userInfo[2] : ALL); + } + + /** + * Override toString - return permission in key format. + */ + @Override + public String toString() { + return getKey(); + } + + /** + * Return Permission in Key format = type, instance, and action separate by + * pipe character. + * + * @return permission in key format + */ + public String getKey() { + return type + "|" + instance + "|" + action; + } + + /** + * Return Permission in Key format = type, all instance, and action separate + * by pipe character. + * + * @return permission in key format + */ + public String getKeyAllInstance() { + return type + "|" + ALL + "|" + action; + } + + /** + * Return Permission in Key format = type, all instance, and all action + * separate by pipe character. + * + * @return permission in key format + */ + public String getKeyAllInstanceAction() { + return type + "|" + ALL + "|" + ALL; + } + + /** + * Return Permission in Key format = type, instance, and all action separate + * by pipe character. + * + * @return permission in key format + */ + public String getKeyAllAction() { + return type + "|" + instance + "|" + ALL; + } + + /** + * Returns the permission type. + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * Sets the type of permission. + * + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + + /** + * Returns the instance of permission. + * + * @return the instance + */ + public String getInstance() { + return instance; + } + + /** + * Sets the instance of permission. + * + * @param instance the instance to set + */ + public void setInstance(String instance) { + this.instance = instance; + } + + /** + * Returns the action of permission. + * + * @return the action + */ + public String getAction() { + return action; + } + + /** + * Sets the action of permission. + * + * @param action the action to set + */ + public void setAction(String action) { + this.action = action; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermissionDeserializer.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermissionDeserializer.java new file mode 100644 index 000000000..0b178c256 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermissionDeserializer.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.clamp.authorization; + + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import java.lang.reflect.Type; + +public class SecureServicePermissionDeserializer implements JsonDeserializer<SecureServicePermission> { + + @Override + public SecureServicePermission deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (json.isJsonPrimitive()) { + return new SecureServicePermission(json.getAsString()); + } else { + // if not string try default deserialization + return new Gson().fromJson(json, SecureServicePermission.class); + } + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/UserService.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/UserService.java new file mode 100644 index 000000000..96347f82f --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/UserService.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.clamp.authorization; + +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; + +/** + * User service used for authorization verification at the login page. Do not + * remove this class. + */ +@Controller +public class UserService { + + /** + * REST service that returns the username. + * + * @return the user name + */ + public String getUser() { + return AuthorizationController.getPrincipalName(SecurityContextHolder.getContext()); + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/Application.java b/runtime/src/main/java/org/onap/policy/clamp/clds/Application.java new file mode 100644 index 000000000..ba300ac09 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/Application.java @@ -0,0 +1,195 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2017-2018, 2021 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 + * + * 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.clamp.clds; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import org.apache.camel.component.servlet.springboot.ServletMappingAutoConfiguration; +import org.apache.catalina.connector.Connector; +import org.onap.policy.clamp.clds.util.ClampVersioning; +import org.onap.policy.clamp.clds.util.ResourceFileUtils; +import org.onap.policy.clamp.util.PassDecoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@ComponentScan(basePackages = {"org.onap.policy.clamp"}) +@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class, + ServletMappingAutoConfiguration.class}) +@EnableJpaRepositories(basePackages = {"org.onap.policy.clamp"}) +@EntityScan(basePackages = {"org.onap.policy.clamp"}) +@EnableTransactionManagement +@EnableConfigurationProperties +@EnableAsync +@EnableScheduling +@EnableJpaAuditing +public class Application extends SpringBootServletInitializer { + + protected static final EELFLogger eelfLogger = EELFManager.getInstance().getLogger(Application.class); + // This settings is an additional one to Spring config, + // only if we want to have an additional port automatically redirected to + // HTTPS + @Value("${server.http-to-https-redirection.port:#{null}}") + private String httpRedirectedPort; + /** + * This 8080 is the default port used by spring if this parameter is not + * specified in application.properties. + */ + @Value("${server.port:8080}") + private String springServerPort; + + @Value("${server.ssl.key-store:#{null}}") + private String keystoreFile; + + @Value("${server.ssl.key-store-password:#{null}}") + private String keyStorePass; + + @Value("${server.ssl.key-store-type:JKS}") + private String keyStoreType; + + + @Value("${clamp.config.keyFile:classpath:/clds/aaf/org.onap.clamp.keyfile}") + private String keyFile; + + @Autowired + private Environment env; + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(Application.class); + } + + /** + * Main method that starts the Clamp backend. + * + * @param args app params + */ + public static void main(String[] args) { + // Start the Spring application + SpringApplication.run(Application.class, args); + } + + /** + * This method is used to declare the camel servlet. + * + * @return A servlet bean + * @throws IOException IO Exception + */ + @Bean + public ServletRegistrationBean camelServletRegistrationBean() throws IOException { + eelfLogger.info(ResourceFileUtils.getResourceAsString("boot-message.txt") + "(v" + + ClampVersioning.getCldsVersionFromProps() + ")" + System.getProperty("line.separator") + + getSslExpirationDate()); + ServletRegistrationBean registration = new ServletRegistrationBean(new ClampServlet(), "/restservices/clds/*"); + registration.setName("CamelServlet"); + return registration; + } + + /** + * This method is used by Spring to create the servlet container factory. + * + * @return The TomcatEmbeddedServletContainerFactory just created + */ + @Bean + public ServletWebServerFactory getEmbeddedServletContainerFactory() { + TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); + if (httpRedirectedPort != null && keystoreFile != null) { + // Automatically redirect to HTTPS + tomcat = new TomcatEmbeddedServletContainerFactoryRedirection(); + Connector newConnector = createRedirectConnector(Integer.parseInt(springServerPort)); + if (newConnector != null) { + tomcat.addAdditionalTomcatConnectors(newConnector); + } + } + return tomcat; + } + + private Connector createRedirectConnector(int redirectSecuredPort) { + if (redirectSecuredPort <= 0) { + eelfLogger.warn("HTTP port redirection to HTTPS is disabled because the HTTPS port is 0 (random port) or -1" + + " (Connector disabled)"); + return null; + } + Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); + connector.setScheme("http"); + connector.setSecure(false); + connector.setPort(Integer.parseInt(httpRedirectedPort)); + connector.setRedirectPort(redirectSecuredPort); + return connector; + } + + private String getSslExpirationDate() throws IOException { + StringBuilder result = new StringBuilder(" :: SSL Certificates :: "); + try { + if (keystoreFile != null) { + KeyStore keystore = KeyStore.getInstance(keyStoreType); + keystore.load(ResourceFileUtils.getResourceAsStream(keystoreFile.replace("classpath:", "")), + PassDecoder.decode(keyStorePass, keyFile).toCharArray()); + + Enumeration<String> aliases = keystore.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + if ("X.509".equals(keystore.getCertificate(alias).getType())) { + result.append("* " + alias + " expires " + + ((X509Certificate) keystore.getCertificate(alias)).getNotAfter() + + System.getProperty("line.separator")); + } + } + } else { + result.append("* NONE HAS been configured"); + } + } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException e) { + eelfLogger.warn("SSL certificate access error ", e); + + } + return result.toString(); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/ClampInUserAuditorAware.java b/runtime/src/main/java/org/onap/policy/clamp/clds/ClampInUserAuditorAware.java new file mode 100644 index 000000000..939cea49c --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/ClampInUserAuditorAware.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds; + +import java.util.Optional; +import org.onap.policy.clamp.authorization.AuthorizationController; +import org.springframework.data.domain.AuditorAware; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +@Component +public class ClampInUserAuditorAware implements AuditorAware<String> { + + @Override + public Optional<String> getCurrentAuditor() { + return Optional.of(AuthorizationController.getPrincipalName(SecurityContextHolder.getContext())); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/ClampServlet.java b/runtime/src/main/java/org/onap/policy/clamp/clds/ClampServlet.java new file mode 100644 index 000000000..ccde7cf11 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/ClampServlet.java @@ -0,0 +1,160 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2018, 2021 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 + * + * 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.clamp.clds; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.camel.component.servlet.CamelHttpTransportServlet; +import org.apache.commons.lang3.StringUtils; +import org.onap.policy.clamp.authorization.SecureServicePermission; +import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +public class ClampServlet extends CamelHttpTransportServlet { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -4198841134910211542L; + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(ClampServlet.class); + private static final String PERM_INSTANCE = "clamp.config.security.permission.instance"; + private static final String PERM_CL = "clamp.config.security.permission.type.cl"; + private static final String PERM_TEMPLATE = "clamp.config.security.permission.type.template"; + private static final String PERM_VF = "clamp.config.security.permission.type.filter.vf"; + private static final String PERM_MANAGE = "clamp.config.security.permission.type.cl.manage"; + private static final String PERM_TOSCA = "clamp.config.security.permission.type.tosca"; + private static final String PERM_POLICIES = "clamp.config.security.permission.type.policies"; + private static final String AUTHENTICATION_CLASS = "clamp.config.security.authentication.class"; + private static final String READ = "read"; + private static final String UPDATE = "update"; + + private static List<SecureServicePermission> permissionList; + + private synchronized List<String> loadDynamicAuthenticationClasses() { + WebApplicationContext webAppContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); + if (webAppContext != null) { + String authClassProperty = webAppContext.getEnvironment().getProperty(AUTHENTICATION_CLASS); + if (!StringUtils.isBlank(authClassProperty)) { + return Arrays.stream(authClassProperty.split(",")).map(String::trim) + .collect(Collectors.toList()); + } + logger.warn( + "No authentication classes defined in Clamp BE config " + AUTHENTICATION_CLASS + + " AAF authentication could be broken due to that"); + } else { + logger.error( + "WebApplicationContext is NULL, no authentication classes will be loaded in clamp BE" + + ", AAF authentication could be broken"); + } + return Collections.emptyList(); + } + + private synchronized List<SecureServicePermission> getPermissionList() { + if (permissionList == null) { + permissionList = new ArrayList<>(); + ApplicationContext applicationContext = WebApplicationContextUtils + .getWebApplicationContext(getServletContext()); + String cldsPermissionInstance = applicationContext.getEnvironment().getProperty(PERM_INSTANCE); + permissionList.add(SecureServicePermission.create(applicationContext.getEnvironment().getProperty(PERM_CL), + cldsPermissionInstance, READ)); + permissionList.add(SecureServicePermission.create(applicationContext.getEnvironment().getProperty(PERM_CL), + cldsPermissionInstance, UPDATE)); + permissionList.add(SecureServicePermission.create( + applicationContext.getEnvironment().getProperty(PERM_TEMPLATE), cldsPermissionInstance, READ)); + permissionList.add(SecureServicePermission.create( + applicationContext.getEnvironment().getProperty(PERM_TEMPLATE), cldsPermissionInstance, UPDATE)); + permissionList.add(SecureServicePermission.create(applicationContext.getEnvironment().getProperty(PERM_VF), + cldsPermissionInstance, "*")); + permissionList.add(SecureServicePermission + .create(applicationContext.getEnvironment().getProperty(PERM_MANAGE), cldsPermissionInstance, "*")); + permissionList.add(SecureServicePermission + .create(applicationContext.getEnvironment().getProperty(PERM_TOSCA), cldsPermissionInstance, READ)); + permissionList.add(SecureServicePermission + .create(applicationContext.getEnvironment().getProperty(PERM_TOSCA), cldsPermissionInstance, + UPDATE)); + permissionList.add(SecureServicePermission + .create(applicationContext.getEnvironment().getProperty(PERM_POLICIES), cldsPermissionInstance, + READ)); + permissionList.add(SecureServicePermission + .create(applicationContext.getEnvironment().getProperty(PERM_POLICIES), cldsPermissionInstance, + UPDATE)); + } + return permissionList; + } + + /** + * When AAF is enabled, request object will contain a cadi Wrapper, so queries + * to isUserInRole will invoke a http call to AAF server. + */ + @Override + protected void doService(HttpServletRequest request, HttpServletResponse response) { + Principal principal = request.getUserPrincipal(); + if (principal != null && loadDynamicAuthenticationClasses().stream() + .anyMatch(className -> className.equals(principal.getClass().getName()))) { + // When AAF is enabled, there is a need to provision the permissions to Spring + // system + List<GrantedAuthority> grantedAuths = new ArrayList<>(); + for (SecureServicePermission perm : getPermissionList()) { + String permString = perm.toString(); + if (request.isUserInRole(permString)) { + grantedAuths.add(new SimpleGrantedAuthority(permString)); + } + } + Authentication auth = new UsernamePasswordAuthenticationToken(new User(principal.getName(), "", + grantedAuths), "", grantedAuths); + SecurityContextHolder.getContext().setAuthentication(auth); + } + try { + super.doService(request, response); + } catch (ServletException | IOException ioe) { + logger.error("Exception caught when executing doService in servlet", ioe); + try { + response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value()); + } catch (IOException e) { + logger.error("Exception caught when executing HTTP sendError in servlet", e); + } + } + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java b/runtime/src/main/java/org/onap/policy/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java new file mode 100644 index 000000000..f66a09c41 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017 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.clamp.clds; + +import org.apache.catalina.Context; +import org.apache.tomcat.util.descriptor.web.SecurityCollection; +import org.apache.tomcat.util.descriptor.web.SecurityConstraint; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; + +/** + * This class is a factory that redirects by default all HTTP to HTTPS + * connector. It is used by the Application.java class and defined in a Spring + * Bean. + * In order to do this, the method postProcessContext has been overridden to + * provide another behavior. + */ +public class TomcatEmbeddedServletContainerFactoryRedirection extends TomcatServletWebServerFactory { + + /** + * This method is there to force the automatic redirection of all calls done + * on the tomcat server to a Secure connection. + */ + @Override + protected void postProcessContext(Context context) { + SecurityConstraint securityConstraint = new SecurityConstraint(); + securityConstraint.setUserConstraint("CONFIDENTIAL"); + SecurityCollection collection = new SecurityCollection(); + collection.addPattern("/*"); + securityConstraint.addCollection(collection); + context.addConstraint(securityConstraint); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/client/CdsServices.java b/runtime/src/main/java/org/onap/policy/clamp/clds/client/CdsServices.java new file mode 100644 index 000000000..cb74ad9e4 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/client/CdsServices.java @@ -0,0 +1,229 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * Modifications Copyright (C) 2021 AT&T. + * ================================================================================ + * 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.clamp.clds.client; + +import static java.lang.Boolean.parseBoolean; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import java.io.IOException; +import java.util.Date; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.ExchangeBuilder; +import org.onap.policy.clamp.clds.exception.cds.CdsParametersException; +import org.onap.policy.clamp.clds.model.cds.CdsBpWorkFlowListResponse; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.clds.util.LoggingUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * This class implements the communication with CDS for the service inventory. + */ +@Component +public class CdsServices { + + @Autowired + CamelContext camelContext; + + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(CdsServices.class); + + private static final String TYPE = "type"; + private static final String PROPERTIES = "properties"; + private static final String LIST = "list"; + + /** + * Query CDS to get blueprint's workflow list. + * + * @param blueprintName CDS blueprint name + * @param blueprintVersion CDS blueprint version + * @return CdsBpWorkFlowListResponse CDS blueprint's workflow list + */ + public CdsBpWorkFlowListResponse getBlueprintWorkflowList(String blueprintName, String blueprintVersion) { + LoggingUtils.setTargetContext("CDS", "getBlueprintWorkflowList"); + + try (ProducerTemplate producerTemplate = camelContext.createProducerTemplate()) { + Exchange exchangeResponse = + producerTemplate.send("direct:get-blueprint-workflow-list", ExchangeBuilder.anExchange(camelContext) + .withProperty("blueprintName", blueprintName) + .withProperty("blueprintVersion", blueprintVersion) + .withProperty("raiseHttpExceptionFlag", false).build()); + + if (HttpStatus.valueOf((Integer) exchangeResponse.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)) + .is2xxSuccessful()) { + String cdsResponse = (String) exchangeResponse.getIn().getBody(); + logger.info("getBlueprintWorkflowList, response from CDS:" + cdsResponse); + LoggingUtils.setResponseContext("0", "Get Blueprint workflow list", this.getClass().getName()); + Date startTime = new Date(); + LoggingUtils.setTimeContext(startTime, new Date()); + return JsonUtils.GSON_JPA_MODEL.fromJson(cdsResponse, CdsBpWorkFlowListResponse.class); + } else { + logger.error("CDS getBlueprintWorkflowList FAILED"); + } + } catch (IOException e) { + logger.error("IOException caught when trying to execute get-blueprint-workflow-list flow", e); + } + return null; + } + + /** + * Query CDS to get input properties of workflow. + * + * @param blueprintName CDS blueprint name + * @param blueprintVersion CDS blueprint name + * @param workflow CDS blueprint's workflow + * @return input properties in json format + */ + public JsonObject getWorkflowInputProperties(String blueprintName, String blueprintVersion, + String workflow) { + LoggingUtils.setTargetContext("CDS", "getWorkflowInputProperties"); + + try (ProducerTemplate producerTemplate = camelContext.createProducerTemplate()) { + Exchange exchangeResponse = producerTemplate + .send("direct:get-blueprint-workflow-input-properties", ExchangeBuilder.anExchange(camelContext) + .withBody(getCdsPayloadForWorkFlow(blueprintName, blueprintVersion, workflow)) + .withProperty("raiseHttpExceptionFlag", false).build()); + if (HttpStatus.valueOf((Integer) exchangeResponse.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)) + .is2xxSuccessful()) { + String cdsResponse = (String) exchangeResponse.getIn().getBody(); + logger.info("getWorkflowInputProperties, response from CDS:" + cdsResponse); + LoggingUtils + .setResponseContext("0", "Get Blueprint workflow input properties", this.getClass().getName()); + Date startTime = new Date(); + LoggingUtils.setTimeContext(startTime, new Date()); + return parseCdsResponse(cdsResponse); + } else { + logger.error("CDS getWorkflowInputProperties FAILED"); + } + } catch (IOException e) { + logger.error("IOException caught when trying to execute get-blueprint-workflow-input-properties flow", e); + } + return null; + } + + protected JsonObject parseCdsResponse(String response) { + JsonObject root = JsonParser.parseString(response).getAsJsonObject(); + JsonObject inputs = root.getAsJsonObject("workFlowData").getAsJsonObject("inputs"); + JsonObject dataTypes = root.getAsJsonObject("dataTypes"); + + JsonObject workFlowProperties = new JsonObject(); + workFlowProperties.add("inputs", getInputProperties(inputs, dataTypes, new JsonObject())); + return workFlowProperties; + } + + private JsonObject getInputProperties(JsonObject inputs, JsonObject dataTypes, JsonObject inputObject) { + if (inputs == null) { + return inputObject; + } + + for (Map.Entry<String, JsonElement> entry : inputs.entrySet()) { + String key = entry.getKey(); + JsonObject inputProperty = inputs.getAsJsonObject(key); + String type = inputProperty.get(TYPE).getAsString(); + if (isComplexType(type, dataTypes)) { + inputObject.add(key, handleComplexType(type, dataTypes)); + } else if (LIST.equalsIgnoreCase(type)) { + handleListType(key, inputProperty, dataTypes, inputObject); + } else if (isInputParam(inputProperty)) { + inputObject.add(key, entry.getValue()); + } + } + return inputObject; + } + + private void handleListType(String propertyName, + JsonObject inputProperty, + JsonObject dataTypes, + JsonObject inputObject) { + if (inputProperty.get("entry_schema") == null) { + throw new CdsParametersException("Entry schema is null for " + propertyName); + } + + String type = inputProperty.get("entry_schema").getAsJsonObject().get( + TYPE).getAsString(); + if (dataTypes != null && dataTypes.get(type) != null) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty(TYPE, LIST); + jsonObject.add(PROPERTIES, getPropertiesObject(type, dataTypes)); + inputObject.add(propertyName, jsonObject); + } else if (isInputParam(inputProperty)) { + inputObject.add(propertyName, inputProperty); + } + } + + private JsonObject handleComplexType(String key, JsonObject dataTypes) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty(TYPE, "object"); + jsonObject.add(PROPERTIES, getPropertiesObject(key, dataTypes)); + return jsonObject; + } + + private JsonObject getPropertiesObject(String key, JsonObject dataTypes) { + JsonObject properties = dataTypes.get(key).getAsJsonObject().get(PROPERTIES).getAsJsonObject(); + JsonObject object = new JsonObject(); + getInputProperties(properties, dataTypes, object); + return object; + } + + private boolean isComplexType(String type, JsonObject dataTypes) { + if (dataTypes == null) { + return false; + } + return dataTypes.get(type) != null; + } + + private boolean isInputParam(JsonObject inputProperty) { + JsonElement inputParam = inputProperty.get("input-param"); + if (inputParam == null) { + return false; + } + return parseBoolean(inputParam.getAsString()); + } + + /** + * Creates payload to query CDS to get workflow input properties. + * + * @param blueprintName CDS blueprint name + * @param version CDS blueprint version + * @param workflow CDS blueprint workflow + * @return returns payload in json format + */ + public String getCdsPayloadForWorkFlow(String blueprintName, String version, String workflow) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("blueprintName", blueprintName); + jsonObject.addProperty("version", version); + jsonObject.addProperty("returnContent", "json"); + jsonObject.addProperty("workflowName", workflow); + jsonObject.addProperty("specType", "TOSCA"); + return jsonObject.toString(); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/client/DcaeInventoryServices.java b/runtime/src/main/java/org/onap/policy/clamp/clds/client/DcaeInventoryServices.java new file mode 100644 index 000000000..843107040 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/client/DcaeInventoryServices.java @@ -0,0 +1,144 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2017-2018, 2021 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============================================ + * Modifications copyright (c) 2018 Nokia + * =================================================================== + * + */ + +package org.onap.policy.clamp.clds.client; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import java.util.Date; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.ExchangeBuilder; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.onap.policy.clamp.clds.config.ClampProperties; +import org.onap.policy.clamp.clds.model.dcae.DcaeInventoryResponse; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.clds.util.LoggingUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * This class implements the communication with DCAE for the service inventory. + */ +@Component +public class DcaeInventoryServices { + + @Autowired + CamelContext camelContext; + + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(DcaeInventoryServices.class); + protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger(); + protected static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger(); + public static final String DCAE_INVENTORY_URL = "dcae.inventory.url"; + public static final String DCAE_INVENTORY_RETRY_INTERVAL = "dcae.intentory.retry.interval"; + public static final String DCAE_INVENTORY_RETRY_LIMIT = "dcae.intentory.retry.limit"; + private final ClampProperties refProp; + + /** + * Constructor. + */ + @Autowired + public DcaeInventoryServices(ClampProperties refProp) { + this.refProp = refProp; + } + + private int getTotalCountFromDcaeInventoryResponse(String responseStr) throws ParseException { + JSONParser parser = new JSONParser(); + Object obj0 = parser.parse(responseStr); + JSONObject jsonObj = (JSONObject) obj0; + Long totalCount = (Long) jsonObj.get("totalCount"); + return totalCount.intValue(); + } + + private DcaeInventoryResponse getItemsFromDcaeInventoryResponse(String responseStr) throws ParseException { + JSONParser parser = new JSONParser(); + Object obj0 = parser.parse(responseStr); + JSONObject jsonObj = (JSONObject) obj0; + JSONArray itemsArray = (JSONArray) jsonObj.get("items"); + JSONObject dcaeServiceType0 = (JSONObject) itemsArray.get(0); + return JsonUtils.GSON.fromJson(dcaeServiceType0.toString(), DcaeInventoryResponse.class); + } + + /** + * DO a query to DCAE to get some Information. + * + * @param artifactName The artifact Name + * @param serviceUuid The service UUID + * @param resourceUuid The resource UUID + * @return The DCAE inventory for the artifact in DcaeInventoryResponse + * @throws IOException In case of issues with the stream + * @throws ParseException In case of issues with the Json parsing + */ + public DcaeInventoryResponse getDcaeInformation(String artifactName, String serviceUuid, String resourceUuid) + throws IOException, ParseException, InterruptedException { + LoggingUtils.setTargetContext("DCAE", "getDcaeInformation"); + + int retryInterval = 0; + int retryLimit = 1; + if (refProp.getStringValue(DCAE_INVENTORY_RETRY_LIMIT) != null) { + retryLimit = Integer.valueOf(refProp.getStringValue(DCAE_INVENTORY_RETRY_LIMIT)); + } + if (refProp.getStringValue(DCAE_INVENTORY_RETRY_INTERVAL) != null) { + retryInterval = Integer.valueOf(refProp.getStringValue(DCAE_INVENTORY_RETRY_INTERVAL)); + } + for (int i = 0; i < retryLimit; i++) { + metricsLogger.info("Attempt n°" + i + " to contact DCAE inventory"); + try (ProducerTemplate producerTemplate = camelContext.createProducerTemplate()) { + Exchange exchangeResponse = producerTemplate + .send("direct:get-dcae-blueprint-inventory", ExchangeBuilder.anExchange(camelContext) + .withProperty("blueprintResourceId", resourceUuid) + .withProperty("blueprintServiceId", serviceUuid) + .withProperty("blueprintName", artifactName) + .withProperty("raiseHttpExceptionFlag", false).build()); + + if (HttpStatus.valueOf((Integer) exchangeResponse.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)) + .is2xxSuccessful()) { + String dcaeResponse = (String) exchangeResponse.getIn().getBody(); + int totalCount = getTotalCountFromDcaeInventoryResponse(dcaeResponse); + metricsLogger.info("getDcaeInformation complete: totalCount returned=" + totalCount); + if (totalCount > 0) { + logger.info("getDcaeInformation, answer from DCAE inventory:" + dcaeResponse); + LoggingUtils.setResponseContext("0", "Get Dcae Information success", this.getClass().getName()); + Date startTime = new Date(); + LoggingUtils.setTimeContext(startTime, new Date()); + return getItemsFromDcaeInventoryResponse(dcaeResponse); + } else { + logger.info("Dcae inventory totalCount returned is 0, so waiting " + retryInterval + + "ms before retrying ..."); + // wait for a while and try to connect to DCAE again + Thread.sleep(retryInterval); + } + } + } + } + logger.warn("Dcae inventory totalCount returned is still 0, after " + retryLimit + " attempts, returning NULL"); + return null; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/AafConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/AafConfiguration.java new file mode 100644 index 000000000..9b6338e00 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/AafConfiguration.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018, 2021 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.clamp.clds.config; + +import javax.servlet.Filter; +import org.onap.policy.clamp.clds.filter.ClampCadiFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("clamp-aaf-authentication") +public class AafConfiguration { + + /** + * Method to return clamp cadi filter. + * + * @return Filter + */ + @Bean(name = "cadiFilter") + public Filter cadiFilter() { + return new ClampCadiFilter(); + } + + /** + * Method to register cadi filter. + * + * @return FilterRegistrationBean + */ + @Bean + public FilterRegistrationBean cadiFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(cadiFilter()); + registration.addUrlPatterns("/restservices/clds/v1/user/*"); + registration.addUrlPatterns("/restservices/clds/v2/dictionary/*"); + registration.addUrlPatterns("/restservices/clds/v2/templates/*"); + registration.addUrlPatterns("/restservices/clds/v2/clampInformation/*"); + registration.addUrlPatterns("/restservices/clds/v2/policyToscaModels/*"); + registration.addUrlPatterns("/restservices/clds/v2/policies/*"); + registration.addUrlPatterns("/restservices/clds/v2/loop/*"); + registration.setName("cadiFilter"); + registration.setOrder(0); + return registration; + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/CamelConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/CamelConfiguration.java new file mode 100644 index 000000000..5f10c0afb --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/CamelConfiguration.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2018, 2021 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.clamp.clds.config; + +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.Objects; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.http.HttpComponent; +import org.apache.camel.model.rest.RestBindingMode; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.onap.policy.clamp.clds.util.ClampVersioning; +import org.onap.policy.clamp.clds.util.ResourceFileUtils; +import org.onap.policy.clamp.util.PassDecoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class CamelConfiguration extends RouteBuilder { + + private static final String HTTP = "http"; + private static final String HTTPS = "https"; + + @Autowired + CamelContext camelContext; + + @Value("${server.ssl.key-store:#{null}}") + private String keyStore; + + @Value("${server.ssl.key-store-type:JKS}") + private String keyStoreType; + + @Value("${server.ssl.key-store-password:#{null}}") + private String keyStorePass; + + @Value("${server.ssl.trust-store:#{null}}") + private String trustStore; + + @Value("${server.ssl.trust-store-password:#{null}}") + private String trustStorePass; + + @Value("${server.ssl.trust-store-type:JKS}") + private String trustStoreType; + + @Value("${server.ssl.trust-store-algorithm:PKIX}") + private String trustStoreAlgorithm; + + @Value("${clamp.config.httpclient.connectTimeout:-1}") + private int connectTimeout; + + @Value("${clamp.config.httpclient.connectRequestTimeout:-1}") + private int connectRequestTimeout; + + @Value("${clamp.config.httpclient.socketTimeout:-1}") + private int socketTimeout; + + @Value("${clamp.config.keyFile:#{null}}") + private String keyFile; + + + @Autowired + private ClampProperties clampProperties; + + private void configureDefaultSslProperties() { + if (trustStore != null) { + System.setProperty("javax.net.ssl.trustStore", Thread.currentThread().getContextClassLoader() + .getResource(trustStore.replaceFirst("classpath:", "")).getPath()); + System.setProperty("javax.net.ssl.trustStorePassword", Objects.requireNonNull( + PassDecoder.decode(trustStorePass, keyFile))); + System.setProperty("javax.net.ssl.trustStoreType", trustStoreType); + System.setProperty("ssl.TrustManagerFactory.algorithm", trustStoreAlgorithm); + } + if (keyStore != null) { + System.setProperty("javax.net.ssl.keyStore", Thread.currentThread().getContextClassLoader() + .getResource(keyStore.replaceFirst("classpath:", "")).getPath()); + System.setProperty("javax.net.ssl.keyStorePassword", Objects.requireNonNull( + PassDecoder.decode(keyStorePass, keyFile))); + System.setProperty("javax.net.ssl.keyStoreType", keyStoreType); + } + + } + + private void configureCamelHttpComponent() + throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException, + IOException { + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(connectTimeout) + .setConnectionRequestTimeout(connectRequestTimeout) + .setSocketTimeout(socketTimeout).build(); + + if (trustStore != null) { + KeyStore truststore = KeyStore.getInstance(trustStoreType); + truststore.load( + ResourceFileUtils.getResourceAsStream(trustStore), + Objects.requireNonNull(PassDecoder.decode(trustStorePass, keyFile)).toCharArray()); + TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm); + trustFactory.init(truststore); + SSLContext sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init(null, trustFactory.getTrustManagers(), null); + camelContext.getComponent(HTTPS, HttpComponent.class).setHttpClientConfigurer(builder -> { + SSLSocketFactory factory = new SSLSocketFactory(sslcontext, + SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + builder.setSSLSocketFactory(factory); + builder.setConnectionManager(new BasicHttpClientConnectionManager( + RegistryBuilder.<ConnectionSocketFactory>create().register(HTTPS, factory).build())) + .setDefaultRequestConfig(requestConfig); + }); + } + camelContext.getComponent(HTTP, HttpComponent.class).setHttpClientConfigurer(builder -> { + Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() + .register(HTTP, PlainConnectionSocketFactory.getSocketFactory()).build(); + builder.setConnectionManager(new BasicHttpClientConnectionManager(registry)) + .setDefaultRequestConfig(requestConfig); + }); + } + + @Override + public void configure() + throws KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, + IOException { + restConfiguration().component("servlet").bindingMode(RestBindingMode.json).jsonDataFormat("clamp-gson") + .dataFormatProperty("prettyPrint", "true")// .enableCORS(true) + // turn on swagger api-doc + .apiContextPath("api-doc").apiVendorExtension(true).apiProperty("api.title", "Clamp Rest API") + .apiProperty("api.version", ClampVersioning.getCldsVersionFromProps()) + .apiProperty("base.path", "/restservices/clds/"); + + // Configure httpClient properties for Camel HTTP/HTTPS calls + configureDefaultSslProperties(); + configureCamelHttpComponent(); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/ClampProperties.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/ClampProperties.java new file mode 100644 index 000000000..f11e16733 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/ClampProperties.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.clamp.clds.config; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * Holds Clamp properties and add some functionalities. + */ +@Component +public class ClampProperties { + + @Autowired + private ApplicationContext appContext; + @Autowired + private Environment env; + public static final String CONFIG_PREFIX = "clamp.config."; + + /** + * get property value. + * + * @param key The first key + * @return The string with the value + */ + public String getStringValue(String key) { + return env.getProperty(CONFIG_PREFIX + key); + } + + /** + * get property value for a combo key (key1 + "." + key2). If not found just use + * key1. + * + * @param key1 The first key + * @param key2 The second key after a dot + * @return The string with the value + */ + public String getStringValue(String key1, String key2) { + String value = getStringValue(key1 + "." + key2); + if (value == null || value.length() == 0) { + value = getStringValue(key1); + } + return value; + } + + /** + * Return the file content. The value obtained from the clds-reference file will + * be used as a filename. + * + * @param key The key that will be used to access the clds-reference file + * @return File content in String + * @throws IOException In case of issues with the JSON parser + */ + public String getFileContent(String key) throws IOException { + String fileReference = getStringValue(key); + return (fileReference != null) ? getFileContentFromPath(fileReference) : null; + } + + /** + * Return the file content. First try with combo key (key1 + "." + key2), + * otherwise default to just key1. The value obtained from the clds-reference + * file will be used as a filename. + * + * @param key1 The first key + * @param key2 The second key after a dot + * @return File content in String + * @throws IOException In case of issues with the JSON parser + */ + public String getFileContent(String key1, String key2) throws IOException { + String fileReference = getStringValue(key1, key2); + return (fileReference != null) ? getFileContentFromPath(fileReference) : null; + } + + private String getFileContentFromPath(String filepath) throws IOException { + URL url = appContext.getResource(filepath).getURL(); + return IOUtils.toString(url, StandardCharsets.UTF_8); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoder.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoder.java new file mode 100644 index 000000000..20d7143fb --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoder.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-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 + * + * 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.clamp.clds.config; + +import com.google.gson.JsonParseException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import org.apache.commons.io.IOUtils; +import org.onap.policy.clamp.authorization.CldsUser; +import org.onap.policy.clamp.clds.exception.CldsUsersException; +import org.onap.policy.clamp.clds.util.JsonUtils; + +public class CldsUserJsonDecoder { + + private CldsUserJsonDecoder() { + } + + /** + * This method decodes the JSON file provided to a CldsUser Array. The stream is + * closed after this call, this is not possible to reuse it. + * + * @param cldsUsersFile + * The inputStream containing the users json file + * @return CldsUser[] Array containing a list of the user defined in the JSON + * file + */ + public static CldsUser[] decodeJson(InputStream cldsUsersFile) { + try { + return decodeJson(IOUtils.toString(cldsUsersFile, StandardCharsets.UTF_8.name())); + } catch (IOException e) { + throw new CldsUsersException("Exception occurred during the decoding of the clds-users.json", e); + } + } + + /** + * This method decodes the JSON string to a CldsUser Array. + * + * @param cldsUsersString JSON string + * @return CldsUser[] Array containing a list of the user defined in the JSON + */ + public static CldsUser[] decodeJson(String cldsUsersString) { + try { + // the ObjectMapper readValue method closes the stream no need to do + // it + return JsonUtils.GSON.fromJson(cldsUsersString, CldsUser[].class); + } catch (JsonParseException e) { + throw new CldsUsersException("Exception occurred during the decoding of the clds-users.json", e); + } + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultDictionaryElements.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultDictionaryElements.java new file mode 100644 index 000000000..27cf0b941 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultDictionaryElements.java @@ -0,0 +1,167 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.config; + +import javax.annotation.PostConstruct; +import org.onap.policy.clamp.tosca.Dictionary; +import org.onap.policy.clamp.tosca.DictionaryElement; +import org.onap.policy.clamp.tosca.DictionaryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("default-dictionary-elements") +public class DefaultDictionaryElements { + + @Autowired + private DictionaryService dictionaryService; + + /** + * Init method. + */ + @PostConstruct + public void init() { + preProvisionDefaultActors(); + preProvisionDefaultOperations(); + } + + private void preProvisionDefaultActors() { + // Set up dictionary elements + Dictionary actorDictionary = new Dictionary(); + actorDictionary.setName("DefaultActors"); + actorDictionary.setSecondLevelDictionary(0); + actorDictionary.setSubDictionaryType(""); + + DictionaryElement elementSo = new DictionaryElement(); + elementSo.setName("SO"); + elementSo.setShortName("SO"); + elementSo.setType("string"); + elementSo.setDescription("SO component"); + actorDictionary.addDictionaryElements(elementSo); + + DictionaryElement elementSdnc = new DictionaryElement(); + elementSdnc.setName("SDNC"); + elementSdnc.setShortName("SDNC"); + elementSdnc.setType("string"); + elementSdnc.setDescription("SDNC component"); + actorDictionary.addDictionaryElements(elementSdnc); + + DictionaryElement elementAppc = new DictionaryElement(); + elementAppc.setName("APPC"); + elementAppc.setShortName("APPC"); + elementAppc.setType("string"); + elementAppc.setDescription("APPC component"); + actorDictionary.addDictionaryElements(elementAppc); + + DictionaryElement elementVfc = new DictionaryElement(); + elementVfc.setName("VFC"); + elementVfc.setShortName("VFC"); + elementVfc.setType("string"); + elementVfc.setDescription("VFC component"); + actorDictionary.addDictionaryElements(elementVfc); + + DictionaryElement elementSdnr = new DictionaryElement(); + elementSdnr.setName("SDNR"); + elementSdnr.setShortName("SDNR"); + elementSdnr.setType("string"); + elementSdnr.setDescription("SDNR component"); + actorDictionary.addDictionaryElements(elementSdnr); + + dictionaryService.saveOrUpdateDictionary(actorDictionary); + } + + private void preProvisionDefaultOperations() { + // Set up dictionary elements + Dictionary operationDictionary = new Dictionary(); + operationDictionary.setName("DefaultOperations"); + operationDictionary.setSecondLevelDictionary(0); + operationDictionary.setSubDictionaryType(""); + + DictionaryElement elementRestart = new DictionaryElement(); + elementRestart.setName("Restart"); + elementRestart.setShortName("Restart (APPC operation)"); + elementRestart.setType("string"); + elementRestart.setDescription("APPC operation"); + operationDictionary.addDictionaryElements(elementRestart); + + DictionaryElement elementRebuild = new DictionaryElement(); + elementRebuild.setName("Rebuild"); + elementRebuild.setShortName("Rebuild (APPC operation)"); + elementRebuild.setType("string"); + elementRebuild.setDescription("APPC operation"); + operationDictionary.addDictionaryElements(elementRebuild); + + DictionaryElement elementMigrate = new DictionaryElement(); + elementMigrate.setName("Migrate"); + elementMigrate.setShortName("Migrate (APPC operation)"); + elementMigrate.setType("string"); + elementMigrate.setDescription("APPC operation"); + operationDictionary.addDictionaryElements(elementMigrate); + + DictionaryElement elementHealthCheck = new DictionaryElement(); + elementHealthCheck.setName("Health-Check"); + elementHealthCheck.setShortName("Health-Check (APPC operation)"); + elementHealthCheck.setType("string"); + elementHealthCheck.setDescription("APPC operation"); + operationDictionary.addDictionaryElements(elementHealthCheck); + + DictionaryElement elementModifyConfig = new DictionaryElement(); + elementModifyConfig.setName("ModifyConfig"); + elementModifyConfig.setShortName("ModifyConfig (APPC/VFC operation)"); + elementModifyConfig.setType("string"); + elementModifyConfig.setDescription("APPC/VFC operation"); + operationDictionary.addDictionaryElements(elementModifyConfig); + + DictionaryElement elementVfModuleCreate = new DictionaryElement(); + elementVfModuleCreate.setName("VF Module Create"); + elementVfModuleCreate.setShortName("VF Module Create (SO operation)"); + elementVfModuleCreate.setType("string"); + elementVfModuleCreate.setDescription("SO operation"); + operationDictionary.addDictionaryElements(elementVfModuleCreate); + + DictionaryElement elementVfModuleDelete = new DictionaryElement(); + elementVfModuleDelete.setName("VF Module Delete"); + elementVfModuleDelete.setShortName("VF Module Delete (SO operation)"); + elementVfModuleDelete.setType("string"); + elementVfModuleDelete.setDescription("SO operation"); + operationDictionary.addDictionaryElements(elementVfModuleDelete); + + DictionaryElement elementReroute = new DictionaryElement(); + elementReroute.setName("Reroute"); + elementReroute.setShortName("Reroute (SDNC operation)"); + elementReroute.setType("string"); + elementReroute.setDescription("SDNC operation"); + operationDictionary.addDictionaryElements(elementReroute); + + DictionaryElement elementBandwidthOnDemand = new DictionaryElement(); + elementBandwidthOnDemand.setName("BandwidthOnDemand"); + elementBandwidthOnDemand.setShortName("BandwidthOnDemand (SDNC operation)"); + elementBandwidthOnDemand.setType("string"); + elementBandwidthOnDemand.setDescription("SDNC operation"); + operationDictionary.addDictionaryElements(elementBandwidthOnDemand); + + dictionaryService.saveOrUpdateDictionary(operationDictionary); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultUserConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultUserConfiguration.java new file mode 100644 index 000000000..bb7b76af3 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultUserConfiguration.java @@ -0,0 +1,140 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2017-2018, 2021 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 + * + * 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.clamp.clds.config; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import org.onap.policy.clamp.authorization.CldsUser; +import org.onap.policy.clamp.clds.exception.CldsConfigException; +import org.onap.policy.clamp.clds.exception.CldsUsersException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * This class is used to enable the HTTP authentication to login. It requires a + * specific JSON file containing the user definition + * (classpath:clds/clds-users.json). + */ +@Configuration +@EnableWebSecurity +@Profile("clamp-default-user") +public class DefaultUserConfiguration extends WebSecurityConfigurerAdapter { + + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(DefaultUserConfiguration.class); + + private static final String SETUP_WEB_USERS_EXCEPTION_MSG = "Exception occurred during the " + + " setup of the Web users in memory"; + @Autowired + private ClampProperties refProp; + @Value("${clamp.config.security.permission.type.cl:permission-type-cl}") + private String cldsPersmissionTypeCl; + @Value("${CLDS_PERMISSION_INSTANCE:dev}") + private String cldsPermissionInstance; + @Value("${clamp.config.security.encoder:bcrypt}") + private String cldsEncoderMethod; + @Value("${clamp.config.security.encoder.bcrypt.strength:10}") + private Integer cldsBcryptEncoderStrength; + + /** + * This method configures on which URL the authorization will be enabled. + */ + @Override + protected void configure(HttpSecurity http) { + try { + // Do no remove the csrf as recommended by Sonar otherwise Put/post will not work + // Moreover this default user class is only used by dev, on prod we use AAF and this code will be disabled + http.csrf().disable().httpBasic().and().authorizeRequests().antMatchers("/restservices/clds/v1/user/**") + .authenticated().anyRequest().permitAll().and().sessionManagement() + .maximumSessions(1); + + } catch (Exception e) { + logger.error(SETUP_WEB_USERS_EXCEPTION_MSG, e); + throw new CldsUsersException(SETUP_WEB_USERS_EXCEPTION_MSG, e); + } + } + + /** + * This method is called by the framework and is used to load all the users + * defined in cldsUsersFile variable (this file path can be configured in the + * application.properties). + * + * @param auth authentication manager builder + */ + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) { + // configure algorithm used for password hashing + final PasswordEncoder passwordEncoder = getPasswordEncoder(); + + try { + CldsUser[] usersList = loadUsers(); + // no users defined + if (null == usersList) { + logger.warn("No users defined. Users should be defined under clds-users.json"); + return; + } + for (CldsUser user : usersList) { + auth.inMemoryAuthentication().withUser(user.getUser()).password(user.getPassword()) + .authorities(user.getPermissionsString()).and().passwordEncoder(passwordEncoder); + } + } catch (Exception e) { + logger.error(SETUP_WEB_USERS_EXCEPTION_MSG, e); + throw new CldsUsersException(SETUP_WEB_USERS_EXCEPTION_MSG, e); + } + } + + /** + * This method loads physically the JSON file and convert it to an Array of + * CldsUser. + * + * @return The array of CldsUser + * @throws IOException In case of the file is not found + */ + private CldsUser[] loadUsers() throws IOException { + logger.info("Load from clds-users.properties"); + return CldsUserJsonDecoder.decodeJson(refProp.getFileContent("files.cldsUsers")); + } + + /** + * This methods returns the chosen encoder for password hashing. + */ + private PasswordEncoder getPasswordEncoder() { + if ("bcrypt".equals(cldsEncoderMethod)) { + return new BCryptPasswordEncoder(cldsBcryptEncoderStrength); + } else { + throw new CldsConfigException( + "Invalid clamp.config.security.encoder value. 'bcrypt' is the only option at this time."); + } + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/SslConfig.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/SslConfig.java new file mode 100644 index 000000000..a72cffd09 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/SslConfig.java @@ -0,0 +1,97 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019, 2021 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.clamp.clds.config; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import org.onap.policy.clamp.clds.util.ResourceFileUtils; +import org.onap.policy.clamp.util.PassDecoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.SslStoreProvider; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; + +@Configuration +@Profile("clamp-ssl-config") +public class SslConfig { + @Autowired + private Environment env; + + @Bean + WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer(ServerProperties serverProperties, + ResourceLoader resourceLoader) { + return (tomcat) -> tomcat.setSslStoreProvider(new SslStoreProvider() { + @Override + public KeyStore getKeyStore() throws KeyStoreException, + NoSuchAlgorithmException, CertificateException, IOException { + KeyStore keystore = KeyStore.getInstance(env.getProperty("server.ssl.key-store-type")); + String password = PassDecoder.decode(env.getProperty("server.ssl.key-store-password"), + env.getProperty("clamp.config.keyFile")); + keystore.load(ResourceFileUtils.getResourceAsStream(env.getProperty("server.ssl.key-store")), + password.toCharArray()); + return keystore; + } + + @Override + public KeyStore getTrustStore() throws KeyStoreException, + NoSuchAlgorithmException, CertificateException, IOException { + KeyStore truststore = KeyStore.getInstance("JKS"); + String password = PassDecoder.decode(env.getProperty("server.ssl.trust-store-password"), + env.getProperty("clamp.config.keyFile")); + truststore.load( + ResourceFileUtils.getResourceAsStream(env.getProperty("server.ssl.trust-store")), + password.toCharArray()); + return truststore; + } + + }); + } + + @Bean + WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatSslCustomizer(ServerProperties serverProperties, + ResourceLoader resourceLoader) { + return (tomcat) -> tomcat.setSsl(new Ssl() { + @Override + public String getKeyPassword() { + return PassDecoder.decode(env.getProperty("server.ssl.key-password"), + env.getProperty("clamp.config.keyFile")); + } + + @Override + public String getKeyAlias() { + return env.getProperty("server.ssl.key-alias"); + } + }); + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/SystemPropertiesLoader.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/SystemPropertiesLoader.java new file mode 100644 index 000000000..3e2e62b66 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/SystemPropertiesLoader.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.config; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.util.Properties; +import javax.annotation.Resource; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +@Component +public class SystemPropertiesLoader implements ApplicationListener<ContextRefreshedEvent> { + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(SystemPropertiesLoader.class); + + @Resource(name = "mapper") + private Properties myTranslator; + + @Override + public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { + logger.info("Loading additional JVM properties:" + myTranslator.toString()); + System.getProperties().putAll(myTranslator); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcControllersConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcControllersConfiguration.java new file mode 100644 index 000000000..5d8cbb05e --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcControllersConfiguration.java @@ -0,0 +1,100 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2018, 2021 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 + * + * 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.clamp.clds.config.sdc; + +import com.google.gson.JsonObject; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.onap.policy.clamp.clds.exception.sdc.controller.SdcParametersException; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; + +/** + * This class maps the SDC config JSON file. This JSON can have multiple + * sdc-controller config. So the json is loaded in a static way and the instance + * must specify the controller name that it represents. + */ +public class SdcControllersConfiguration { + + private static final String CONTROLLER_SUBTREE_KEY = "sdc-connections"; + @Autowired + protected ApplicationContext appContext; + + @Value("${clamp.config.keyFile:classpath:/clds/aaf/org.onap.clamp.keyfile}") + private String keyFile; + + /** + * The file name that will be loaded by Spring. + */ + @Value("${clamp.config.files.sdcController:classpath:/clds/sdc-controllers-config.json}") + protected String sdcControllerFile; + /** + * The root of the JSON. + */ + private JsonObject jsonRootNode; + + /** + * Loads configuration from SDC controller config file. + * + * @throws IOException IO Exception + */ + @PostConstruct + public void loadConfiguration() throws IOException { + try (InputStreamReader controllerFile = new InputStreamReader( + appContext.getResource(sdcControllerFile).getInputStream(), StandardCharsets.UTF_8)) { + jsonRootNode = JsonUtils.GSON.fromJson(controllerFile, JsonObject.class); + } + } + + public SdcSingleControllerConfiguration getSdcSingleControllerConfiguration(String controllerName) { + return getAllDefinedControllers().get(controllerName); + } + + /** + * This method reads all Controllers configurations and returns them. + * + * @return A list of controller Names defined in the config + */ + public Map<String, SdcSingleControllerConfiguration> getAllDefinedControllers() { + Map<String, SdcSingleControllerConfiguration> result = new HashMap<>(); + if (jsonRootNode.get(CONTROLLER_SUBTREE_KEY) != null) { + jsonRootNode.get(CONTROLLER_SUBTREE_KEY).getAsJsonObject().entrySet().forEach( + entry -> result.put(entry.getKey(), + new SdcSingleControllerConfiguration(entry.getValue().getAsJsonObject(), entry.getKey(), + keyFile))); + } else { + throw new SdcParametersException( + CONTROLLER_SUBTREE_KEY + " key not found in the file: " + sdcControllerFile); + } + return result; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java new file mode 100644 index 000000000..67060d776 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java @@ -0,0 +1,272 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2018, 2021 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.clamp.clds.config.sdc; + +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.onap.policy.clamp.clds.exception.sdc.controller.SdcParametersException; +import org.onap.policy.clamp.util.PassDecoder; +import org.onap.sdc.api.consumer.IConfiguration; + +/** + * This class maps the SDC config JSON for one controller. + */ +public class SdcSingleControllerConfiguration implements IConfiguration { + + private final String keyFile; + + /** + * The sdc Controller name corresponding. + */ + private String sdcControllerName; + /** + * The root of the JSON. + */ + private JsonObject jsonRootNode; + // All keys that can be present in the JSON + public static final String CONSUMER_GROUP_ATTRIBUTE_NAME = "consumerGroup"; + public static final String CONSUMER_ID_ATTRIBUTE_NAME = "consumerId"; + public static final String ENVIRONMENT_NAME_ATTRIBUTE_NAME = "environmentName"; + public static final String SDC_KEY_ATTRIBUTE_NAME = "password"; + public static final String POLLING_INTERVAL_ATTRIBUTE_NAME = "pollingInterval"; + public static final String RELEVANT_ARTIFACT_TYPES_ATTRIBUTE_NAME = "relevantArtifactTypes"; + public static final String USER_ATTRIBUTE_NAME = "user"; + public static final String SDC_ADDRESS_ATTRIBUTE_NAME = "sdcAddress"; + public static final String POLLING_TIMEOUT_ATTRIBUTE_NAME = "pollingTimeout"; + public static final String ACTIVATE_SERVER_TLS_AUTH = "activateServerTLSAuth"; + public static final String KEY_STORE_KEY = "keyStorePassword"; + public static final String KEY_STORE_PATH = "keyStorePath"; + public static final String MESSAGE_BUS_ADDRESSES = "messageBusAddresses"; + private String errorMessageKeyNotFound; + /** + * Supported artifact types. + */ + public static final String HEAT = "HEAT"; + public static final String HEAT_ARTIFACT = "HEAT_ARTIFACT"; + public static final String HEAT_ENV = "HEAT_ENV"; + public static final String HEAT_NESTED = "HEAT_NESTED"; + public static final String HEAT_NET = "HEAT_NET"; + public static final String HEAT_VOL = "HEAT_VOL"; + public static final String OTHER = "OTHER"; + public static final String TOSCA_CSAR = "TOSCA_CSAR"; + public static final String VF_MODULES_METADATA = "VF_MODULES_METADATA"; + private static final String[] SUPPORTED_ARTIFACT_TYPES = {TOSCA_CSAR, VF_MODULES_METADATA}; + public static final List<String> SUPPORTED_ARTIFACT_TYPES_LIST = List.of(SUPPORTED_ARTIFACT_TYPES); + + /** + * This constructor builds a SdcSingleControllerConfiguration from the + * corresponding json. + * + * @param jsonNode The JSON node + * @param controllerName The controller name that must appear in the JSON + * @param keyFileLocation The location of the file to decode the password using CADI + */ + public SdcSingleControllerConfiguration(JsonObject jsonNode, String controllerName, String keyFileLocation) { + jsonRootNode = jsonNode; + keyFile = keyFileLocation; + setSdcControllerName(controllerName); + testAllRequiredParameters(); + } + + public String getSdcControllerName() { + return sdcControllerName; + } + + /** + * Sets SDC controller name. + * + * @param controllerName SDC controller name + */ + public void setSdcControllerName(String controllerName) { + this.sdcControllerName = controllerName; + errorMessageKeyNotFound = " parameter cannot be found in config file for controller name" + sdcControllerName; + testAllRequiredParameters(); + } + + private String getStringConfig(String key) { + if (jsonRootNode != null && jsonRootNode.get(key) != null) { + String config = jsonRootNode.get(key).getAsString(); + return config.isEmpty() ? null : config; + } + return null; + } + + private Integer getIntConfig(String key) { + if (jsonRootNode != null && jsonRootNode.get(key) != null) { + return jsonRootNode.get(key).getAsInt(); + } else { + return 0; + } + } + + private String getEncryptedStringConfig(String key) { + if (jsonRootNode != null && jsonRootNode.get(key) != null) { + return jsonRootNode.get(key).getAsString().isEmpty() ? null + : PassDecoder.decode(jsonRootNode.get(key).getAsString(), keyFile); + } + return null; + } + + @Override + public java.lang.Boolean isUseHttpsWithDmaap() { + return false; + } + + @Override + public String getConsumerGroup() { + if (jsonRootNode != null && jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME) != null) { + String config = jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME).getAsString(); + return "NULL".equals(config) || config.isEmpty() ? null : config; + } + return null; + } + + @Override + public String getConsumerID() { + return getStringConfig(CONSUMER_ID_ATTRIBUTE_NAME); + } + + @Override + public String getEnvironmentName() { + return getStringConfig(ENVIRONMENT_NAME_ATTRIBUTE_NAME); + } + + @Override + public String getPassword() { + return getEncryptedStringConfig(SDC_KEY_ATTRIBUTE_NAME); + } + + @Override + public int getPollingInterval() { + return getIntConfig(POLLING_INTERVAL_ATTRIBUTE_NAME); + } + + @Override + public List<String> getRelevantArtifactTypes() { + // DO not return the Static List SUPPORTED_ARTIFACT_TYPES_LIST because + // the ASDC Client could try to modify it !!! + return Arrays.asList(SUPPORTED_ARTIFACT_TYPES); + } + + @Override + public String getUser() { + return getStringConfig(USER_ATTRIBUTE_NAME); + } + + @Override + public String getAsdcAddress() { + return getStringConfig(SDC_ADDRESS_ATTRIBUTE_NAME); + } + + @Override + public int getPollingTimeout() { + return getIntConfig(POLLING_TIMEOUT_ATTRIBUTE_NAME); + } + + @Override + public boolean activateServerTLSAuth() { + if (jsonRootNode != null && jsonRootNode.get(ACTIVATE_SERVER_TLS_AUTH) != null + && jsonRootNode.get(ACTIVATE_SERVER_TLS_AUTH).isJsonPrimitive()) { + return jsonRootNode.get(ACTIVATE_SERVER_TLS_AUTH).getAsBoolean(); + } else { + return false; + } + } + + @Override + public String getKeyStorePassword() { + return getEncryptedStringConfig(KEY_STORE_KEY); + } + + @Override + public String getKeyStorePath() { + return getStringConfig(KEY_STORE_PATH); + } + + /** + * This method can be used to validate all required parameters are well + * there. + */ + public void testAllRequiredParameters() { + // Special case for this attribute that can be null from + // getConsumerGroup + if (jsonRootNode == null) { + throw new SdcParametersException("Json is null for controller " + this.getSdcControllerName()); + } + if (this.getConsumerGroup() == null && (jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME) == null + || !"NULL".equals(jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME).getAsString()))) { + throw new SdcParametersException(CONSUMER_GROUP_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getConsumerID() == null || this.getConsumerID().isEmpty()) { + throw new SdcParametersException(CONSUMER_ID_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getEnvironmentName() == null || this.getEnvironmentName().isEmpty()) { + throw new SdcParametersException(ENVIRONMENT_NAME_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getAsdcAddress() == null || this.getAsdcAddress().isEmpty()) { + throw new SdcParametersException(SDC_ADDRESS_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getMsgBusAddress() == null || this.getMsgBusAddress().isEmpty()) { + throw new SdcParametersException(MESSAGE_BUS_ADDRESSES + errorMessageKeyNotFound); + } + if (this.getPassword() == null || this.getPassword().isEmpty()) { + throw new SdcParametersException(SDC_KEY_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getPollingInterval() == 0) { + throw new SdcParametersException(POLLING_INTERVAL_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getPollingTimeout() == 0) { + throw new SdcParametersException(POLLING_TIMEOUT_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getRelevantArtifactTypes() == null || this.getRelevantArtifactTypes().isEmpty()) { + throw new SdcParametersException(RELEVANT_ARTIFACT_TYPES_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getUser() == null || this.getUser().isEmpty()) { + throw new SdcParametersException(USER_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + } + + /** + * The flag allows the client to receive metadata for all resources of the + * service regardless of the artifacts associated to them. Setting the flag + * to false will preserve legacy behavior. + */ + @Override + public boolean isFilterInEmptyResources() { + return false; + } + + @Override + public List<String> getMsgBusAddress() { + List<String> addressesList = new ArrayList<>(); + if (jsonRootNode != null && jsonRootNode.get(MESSAGE_BUS_ADDRESSES) != null) { + jsonRootNode.get(MESSAGE_BUS_ADDRESSES).getAsJsonArray().forEach(k -> addressesList.add(k.getAsString())); + return addressesList; + } else { + return addressesList; + } + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/CldsConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/CldsConfiguration.java new file mode 100644 index 000000000..72f09ce13 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/CldsConfiguration.java @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.clamp.clds.config.spring; + +import org.onap.policy.clamp.clds.config.ClampProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.PropertiesFactoryBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("clamp-default") +public class CldsConfiguration { + + @Autowired + private ApplicationContext appContext; + @Autowired + private ClampProperties refProp; + + + /** + * This loads the file system.properties. + * + * @return The PropertiesFactoryBean + */ + @Bean(name = "mapper") + public PropertiesFactoryBean mapper() { + PropertiesFactoryBean bean = new PropertiesFactoryBean(); + bean.setLocation(appContext.getResource(refProp.getStringValue("files.systemProperties"))); + return bean; + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/SdcControllerConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/SdcControllerConfiguration.java new file mode 100644 index 000000000..6005b0d39 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/SdcControllerConfiguration.java @@ -0,0 +1,110 @@ +/*- + * ============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.policy.clamp.clds.config.spring; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import org.onap.policy.clamp.clds.config.ClampProperties; +import org.onap.policy.clamp.clds.config.sdc.SdcControllersConfiguration; +import org.onap.policy.clamp.clds.exception.sdc.controller.SdcControllerException; +import org.onap.policy.clamp.clds.sdc.controller.SdcSingleController; +import org.onap.policy.clamp.clds.sdc.controller.SdcSingleControllerStatus; +import org.onap.policy.clamp.loop.CsarInstaller; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; + +@Configuration +@Profile("clamp-sdc-controller") +public class SdcControllerConfiguration { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(SdcControllerConfiguration.class); + private List<SdcSingleController> sdcControllersList = new ArrayList<>(); + private final ClampProperties clampProp; + private final CsarInstaller csarInstaller; + + @Autowired + public SdcControllerConfiguration(ClampProperties clampProp, + @Qualifier("csarInstaller") CsarInstaller csarInstaller) { + this.clampProp = clampProp; + this.csarInstaller = csarInstaller; + } + + /** + * Loads SDC controller configuration. + */ + @PostConstruct + public void loadSdcControllers() { + SdcControllersConfiguration sdcControllersConfig = getSdcControllersConfiguration(); + sdcControllersConfig.getAllDefinedControllers().forEach((key, value) -> { + logger.info("Creating controller instance:" + key); + SdcSingleController sdcController = new SdcSingleController(clampProp, csarInstaller, value, null); + sdcControllersList.add(sdcController); + }); + } + + /** + * Checks whether all SDC controllers defined are up and running. + */ + @Scheduled(fixedRate = 120000) + public void checkAllSdcControllers() { + logger.info("Checking that all SDC Controllers defined are up and running"); + for (SdcSingleController controller : sdcControllersList) { + try { + if (SdcSingleControllerStatus.STOPPED.equals(controller.getControllerStatus())) { + controller.initSdc(); + } + } catch (SdcControllerException e) { + logger.error("Exception caught when booting sdc controller", e); + } + } + logger.info("SDC Controllers check completed"); + } + + /** + * Closes all SDC Controller and the SDC Client. + */ + @PreDestroy + public void killSdcControllers() { + sdcControllersList.forEach(e -> { + try { + e.closeSdc(); + } catch (SdcControllerException e1) { + logger.error("Exception caught when stopping sdc controller", e1); + } + }); + } + + @Bean(name = "sdcControllersConfiguration") + public SdcControllersConfiguration getSdcControllersConfiguration() { + return new SdcControllersConfiguration(); + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsConfigException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsConfigException.java new file mode 100644 index 000000000..ef1ced0a3 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsConfigException.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017 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.clamp.clds.exception; + +/** + * New exception to CldsUser errors. + * + */ +public class CldsConfigException extends RuntimeException { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = 5958873136187918505L; + + /** + * This constructor can be used to create a new CldsConfigException. + * + * @param message + * A string message detailing the problem + * @param ex + * The exception sent by the code + */ + public CldsConfigException(String message, Throwable ex) { + super(message, ex); + } + + /** + * This constructor can be used to create a new CldsConfigException. Use + * this constructor only if you are creating a new exception stack, not if + * an exception was already raised by another code. + * + * @param message + * A string message detailing the problem + */ + public CldsConfigException(String message) { + super(message); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsUsersException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsUsersException.java new file mode 100644 index 000000000..4d4855b6f --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsUsersException.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017 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.clamp.clds.exception; + +/** + * New exception to CldsUser errors. + * + */ +public class CldsUsersException extends RuntimeException { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = 933535057227505342L; + + /** + * This constructor can be used to create a new CldsUsersException. + * + * @param message + * A string message detailing the problem + * @param ex + * The exception sent by the code + */ + public CldsUsersException(String message, Throwable ex) { + super(message, ex); + } + + /** + * This constructor can be used to create a new CldsUsersException. Use this + * constructor only if you are creating a new exception stack, not if an + * exception was already raised by another code. + * + * @param message + * A string message detailing the problem + */ + public CldsUsersException(String message) { + super(message); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/NotAuthorizedException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/NotAuthorizedException.java new file mode 100644 index 000000000..73c117932 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/NotAuthorizedException.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.exception; + +/** + * New exception to request errors. + * + */ +public class NotAuthorizedException extends RuntimeException { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -5738167530541646123L; + + /** + * This constructor can be used to create a new CldsConfigException. + * + * @param message + * A string message detailing the problem + * @param ex + * The exception sent by the code + */ + public NotAuthorizedException(String message, Throwable ex) { + super(message, ex); + } + + /** + * This constructor can be used to create a new CldsConfigException. Use this + * constructor only if you are creating a new exception stack, not if an + * exception was already raised by another code. + * + * @param message + * A string message detailing the problem + */ + public NotAuthorizedException(String message) { + super(message); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/cds/CdsParametersException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/cds/CdsParametersException.java new file mode 100644 index 000000000..b4a013eb4 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/cds/CdsParametersException.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.clamp.clds.exception.cds; + +/** + * Exception while parsing CDS response. + */ +public class CdsParametersException extends RuntimeException { + + /** + * serialization id. + */ + private static final long serialVersionUID = 8425657297510362736L; + + /** + * This constructor can be used to create a new CdsParametersException. + * + * @param message The message to dump + */ + public CdsParametersException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new CdsParametersException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public CdsParametersException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/dcae/DcaeDeploymentException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/dcae/DcaeDeploymentException.java new file mode 100644 index 000000000..78c2c6331 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/dcae/DcaeDeploymentException.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017 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.clamp.clds.exception.dcae; + +/** + * New exception to capture DCAE communication errors. + * + */ +public class DcaeDeploymentException extends RuntimeException { + + /** + * Generated ID. + */ + private static final long serialVersionUID = 8452294782552680243L; + + /** + * This constructor can be used to create a new DcaeDeploymentException. + * + * @param message + * A string message detailing the problem + * @param ex + * The exception sent by the code + */ + public DcaeDeploymentException(String message, Throwable ex) { + super(message, ex); + } + + /** + * This constructor can be used to create a new DcaeDeploymentException. Use + * this constructor only if you are creating a new exception stack, not if + * an exception was already raised by another code. + * + * @param message + * A string message detailing the problem + */ + public DcaeDeploymentException(String message) { + super(message); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/BlueprintParserException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/BlueprintParserException.java new file mode 100644 index 000000000..6939fdf06 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/BlueprintParserException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.exception.sdc.controller; + +/** + * Exception during blueprint parsing. + */ +public class BlueprintParserException extends Exception { + + /** + * Serial ID. + */ + private static final long serialVersionUID = -3044162346353623199L; + + /** + * This constructor can be used to create a new SdcDownloadException. + * + * @param message The message to dump + */ + public BlueprintParserException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcDownloadException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public BlueprintParserException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/CsarHandlerException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/CsarHandlerException.java new file mode 100644 index 000000000..e3f16f908 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/CsarHandlerException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.exception.sdc.controller; + +/** + * Exception during Csar operations. + */ +public class CsarHandlerException extends Exception { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -7628640776124409155L; + + /** + * This constructor can be used to create a new CsarHandlerException. + * + * @param message The message to dump + */ + public CsarHandlerException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new CsarHandlerException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public CsarHandlerException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java new file mode 100644 index 000000000..1202ec199 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.exception.sdc.controller; + +/** + * Exception during SDC artifact installation. + */ +public class SdcArtifactInstallerException extends Exception { + + /** + * serialization id. + */ + private static final long serialVersionUID = 4095937499475915021L; + + /** + * This constructor can be used to create a new SdcArtifactInstallerException. + * + * @param message The message to dump + */ + public SdcArtifactInstallerException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcArtifactInstallerException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public SdcArtifactInstallerException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcControllerException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcControllerException.java new file mode 100644 index 000000000..e391ee7e8 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcControllerException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.exception.sdc.controller; + +/** + * Exception of the SDC controller. + */ +public class SdcControllerException extends Exception { + + /** + * serialization id. + */ + private static final long serialVersionUID = -4236006447255525130L; + + /** + * This constructor can be used to create a new SdcControllerException. + * + * @param message The message to dump + */ + public SdcControllerException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcControllerException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public SdcControllerException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcDownloadException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcDownloadException.java new file mode 100644 index 000000000..3c0240ef3 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcDownloadException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.exception.sdc.controller; + +/** + * Exception during download from SDC. + */ +public class SdcDownloadException extends Exception { + + /** + * serialization id. + */ + private static final long serialVersionUID = -5276848693231134901L; + + /** + * This constructor can be used to create a new SdcDownloadException. + * + * @param message The message to dump + */ + public SdcDownloadException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcDownloadException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public SdcDownloadException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcParametersException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcParametersException.java new file mode 100644 index 000000000..fe573882f --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcParametersException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.exception.sdc.controller; + +/** + * Exception of the SDC controller. + */ +public class SdcParametersException extends RuntimeException { + + /** + * serialization id. + */ + private static final long serialVersionUID = 8425657297510362736L; + + /** + * This constructor can be used to create a new SdcParametersException. + * + * @param message The message to dump + */ + public SdcParametersException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcParametersException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public SdcParametersException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/filter/ClampCadiFilter.java b/runtime/src/main/java/org/onap/policy/clamp/clds/filter/ClampCadiFilter.java new file mode 100644 index 000000000..6fa8ecb2b --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/filter/ClampCadiFilter.java @@ -0,0 +1,190 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.clamp.clds.filter; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.StandardCopyOption; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.policy.clamp.clds.util.ResourceFileUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; + +public class ClampCadiFilter extends CadiFilter { + private static final EELFLogger logger = EELFManager.getInstance().getLogger(ClampCadiFilter.class); + + @Autowired + private ApplicationContext appContext; + + @Value("${server.ssl.key-store:#{null}}") + private String keyStore; + + @Value("${server.ssl.key-store-password:#{null}}") + private String keyStorePass; + + @Value("${server.ssl.trust-store:#{null}}") + private String trustStore; + + @Value("${server.ssl.trust-store-password:#{null}}") + private String trustStorePass; + + @Value("${server.ssl.key-alias:clamp@clamp.onap.org}") + private String alias; + + @Value("${clamp.config.keyFile:#{null}}") + private String keyFile; + + @Value("${clamp.config.cadi.cadiLoglevel:#{null}}") + private String cadiLoglevel; + + @Value("${clamp.config.cadi.cadiLatitude:#{null}}") + private String cadiLatitude; + + @Value("${clamp.config.cadi.cadiLongitude:#{null}}") + private String cadiLongitude; + + @Value("${clamp.config.cadi.aafLocateUrl:#{null}}") + private String aafLocateUrl; + + @Value("${clamp.config.cadi.oauthTokenUrl:#{null}}") + private String oauthTokenUrl; + + @Value("${clamp.config.cadi.oauthIntrospectUrl:#{null}}") + private String oauthIntrospectUrl; + + @Value("${clamp.config.cadi.aafEnv:#{null}}") + private String aafEnv; + + @Value("${clamp.config.cadi.aafUrl:#{null}}") + private String aafUrl; + + @Value("${clamp.config.cadi.cadiX509Issuers:#{null}}") + private String cadiX509Issuers; + + @Value("${clamp.config.caCerts:#{null}}") + private String caCertsPath; + + private void checkIfNullProperty(String key, String value) { + /* + * When value is null, so not defined in application.properties set nothing in + * System properties + */ + if (value != null) { + /* + * Ensure that any properties already defined in System.prop by JVM params won't + * be overwritten by Spring application.properties values + */ + System.setProperty(key, System.getProperty(key, value)); + } + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // set some properties in System so that Cadi filter will find its config + // The JVM values set will always overwrite the Spring ones. + checkIfNullProperty(Config.CADI_KEYFILE, convertSpringToPath(keyFile)); + checkIfNullProperty(Config.CADI_LOGLEVEL, cadiLoglevel); + checkIfNullProperty(Config.CADI_LATITUDE, cadiLatitude); + checkIfNullProperty(Config.CADI_LONGITUDE, cadiLongitude); + + checkIfNullProperty(Config.AAF_LOCATE_URL, aafLocateUrl); + checkIfNullProperty(Config.AAF_OAUTH2_TOKEN_URL, oauthTokenUrl); + checkIfNullProperty(Config.AAF_OAUTH2_INTROSPECT_URL, oauthIntrospectUrl); + + checkIfNullProperty(Config.AAF_ENV, aafEnv); + checkIfNullProperty(Config.AAF_URL, aafUrl); + checkIfNullProperty(Config.CADI_X509_ISSUERS, cadiX509Issuers); + checkIfNullProperty(Config.CADI_KEYSTORE, convertSpringToPath(keyStore)); + checkIfNullProperty(Config.CADI_TRUSTSTORE, convertSpringToPath(trustStore)); + checkIfNullProperty(Config.CADI_ALIAS, alias); + checkIfNullProperty(Config.CADI_KEYSTORE_PASSWORD, keyStorePass); + checkIfNullProperty(Config.CADI_TRUSTSTORE_PASSWORD, trustStorePass); + + super.init(filterConfig); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + try { + String certHeader = ((HttpServletRequest) request).getHeader("X-SSL-Cert"); + if (certHeader != null) { + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) certificateFactory + .generateCertificate(new ByteArrayInputStream( + URLDecoder.decode(certHeader, StandardCharsets.UTF_8.toString()).getBytes())); + X509Certificate caCert = (X509Certificate) certificateFactory + .generateCertificate(new ByteArrayInputStream( + ResourceFileUtils.getResourceAsString(this.caCertsPath).getBytes())); + + X509Certificate[] certifArray = ((X509Certificate[]) request + .getAttribute("javax.servlet.request.X509Certificate")); + if (certifArray == null) { + certifArray = new X509Certificate[] { cert, caCert }; + request.setAttribute("javax.servlet.request.X509Certificate", certifArray); + } else { + certifArray[0] = cert; + certifArray[1] = caCert; + } + } + + } catch (CertificateException e) { + logger.error("Unable to inject the X.509 certificate", e); + } + super.doFilter(request, response, chain); + } + + private String convertSpringToPath(String fileName) { + try (InputStream ioFile = appContext.getResource(fileName).getInputStream()) { + if (!fileName.contains("file:")) { + File targetFile = new File(appContext.getResource(fileName).getFilename()); + java.nio.file.Files.copy(ioFile, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + return targetFile.getPath(); + } else { + return appContext.getResource(fileName).getFile().getPath(); + } + } catch (IOException e) { + logger.error("Unable to open and copy the file: " + fileName, e); + return null; + } + + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/ClampInformation.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/ClampInformation.java new file mode 100644 index 000000000..5708cb6ec --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/ClampInformation.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-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.clamp.clds.model; + +import com.google.gson.annotations.Expose; +import java.util.ArrayList; +import java.util.List; +import org.onap.policy.clamp.clds.util.ClampVersioning; + +public class ClampInformation { + @Expose + private String userName; + @Expose + private String cldsVersion = ClampVersioning.getCldsVersionFromProps(); + @Expose + List<String> allPermissions = new ArrayList<>(); + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getCldsVersion() { + return cldsVersion; + } + + public void setCldsVersion(String cldsVersion) { + this.cldsVersion = cldsVersion; + } + + public List<String> getAllPermissions() { + return allPermissions; + } + + public void setAllPermissions(List<String> allPermissions) { + this.allPermissions = allPermissions; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/CldsHealthCheck.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/CldsHealthCheck.java new file mode 100644 index 000000000..c814a628d --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/CldsHealthCheck.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017 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.clamp.clds.model; + +import com.google.gson.annotations.Expose; + +public class CldsHealthCheck { + @Expose + private String healthCheckComponent; + @Expose + private String healthCheckStatus; + @Expose + private String description; + + public String getHealthCheckComponent() { + return healthCheckComponent; + } + + public void setHealthCheckComponent(String healthCheckComponent) { + this.healthCheckComponent = healthCheckComponent; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getHealthCheckStatus() { + return healthCheckStatus; + } + + public void setHealthCheckStatus(String healthCheckStatus) { + this.healthCheckStatus = healthCheckStatus; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java new file mode 100644 index 000000000..a3b42524e --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.clamp.clds.model.cds; + +import com.google.gson.annotations.Expose; +import java.util.LinkedList; +import java.util.List; + +/** + * This class maps the CDS response to a pojo. + */ +public class CdsBpWorkFlowListResponse { + + @Expose + private String blueprintName; + + @Expose + private String version; + + @Expose + private List<String> workflows = new LinkedList<String>(); + + public String getBlueprintName() { + return blueprintName; + } + + public void setBlueprintName(String blueprintName) { + this.blueprintName = blueprintName; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public List<String> getWorkflows() { + return workflows; + } + + public void setWorkflows(List<String> workflows) { + this.workflows = workflows; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryCache.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryCache.java new file mode 100644 index 000000000..a69d1a353 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryCache.java @@ -0,0 +1,62 @@ +/*- + * ============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.policy.clamp.clds.model.dcae; + +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This class stores the multiple DcaeInventoryResponse coming back from DCAE. + * The structure is a map of list indexed by asdcServiceId. The list is sorted + * by asdcResourceId. Therefore it's possible to retrieve all the loops defined + * in the DCAE inventory and created by DCAE Mod. + */ +public class DcaeInventoryCache { + + private static Map<String, Set<DcaeInventoryResponse>> blueprintsMap = new ConcurrentHashMap<>(); + + /** + * Add Dcae inventory response. + * + * @param inventoryResponse the Dcae inventory response + */ + public void addDcaeInventoryResponse(DcaeInventoryResponse inventoryResponse) { + Set<DcaeInventoryResponse> responsesSet = blueprintsMap.get(inventoryResponse.getAsdcServiceId()); + if (responsesSet == null) { + responsesSet = new TreeSet<>(); + blueprintsMap.put(inventoryResponse.getAsdcServiceId(), responsesSet); + } + responsesSet.add(inventoryResponse); + } + + public Set<String> getAllLoopIds() { + return this.blueprintsMap.keySet(); + } + + public Set<DcaeInventoryResponse> getAllBlueprintsPerLoopId(String loopId) { + return blueprintsMap.getOrDefault(loopId, new TreeSet<>()); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponse.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponse.java new file mode 100644 index 000000000..72ae61359 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponse.java @@ -0,0 +1,102 @@ + +/*- + * ============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.policy.clamp.clds.model.dcae; + +import com.google.gson.annotations.Expose; + +/** + * This class maps the DCAE inventory answer to a nice pojo. + */ +public class DcaeInventoryResponse implements Comparable<DcaeInventoryResponse> { + + @Expose + private String typeName; + + @Expose + private String typeId; + + @Expose + private String blueprintTemplate; + + /** + * This field will be used to know all blueprints associated a loop. + */ + @Expose + private String asdcServiceId; + + /** + * This field will be used to know to order of each blueprint microservice in a + * loop. + */ + @Expose + private String asdcResourceId; + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public String getTypeId() { + return typeId; + } + + public void setTypeId(String typeId) { + this.typeId = typeId; + } + + public String getBlueprintTemplate() { + return blueprintTemplate; + } + + public void setBlueprintTemplate(String blueprintTemplate) { + this.blueprintTemplate = blueprintTemplate; + } + + public String getAsdcServiceId() { + return asdcServiceId; + } + + public void setAsdcServiceId(String asdcServiceId) { + this.asdcServiceId = asdcServiceId; + } + + public String getAsdcResourceId() { + return asdcResourceId; + } + + public void setAsdcResourceId(String asdcResourceId) { + this.asdcResourceId = asdcResourceId; + } + + @Override + public int compareTo(DcaeInventoryResponse otherResponse) { + int thisResourceId = Integer.parseInt(this.asdcResourceId); + int otherResourceId = Integer.parseInt(otherResponse.getAsdcResourceId()); + return (thisResourceId < otherResourceId ? -1 : (thisResourceId > otherResourceId ? 1 : 0)); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeLinks.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeLinks.java new file mode 100644 index 000000000..4d6e544da --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeLinks.java @@ -0,0 +1,60 @@ +/*- + * ============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.policy.clamp.clds.model.dcae; + +import com.google.gson.annotations.Expose; + +public class DcaeLinks { + @Expose + private String self; + @Expose + private String status; + @Expose + private String uninstall; + + public String getSelf() { + return self; + } + + public void setSelf(String self) { + this.self = self; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getUninstall() { + return uninstall; + } + + public void setUninstall(String uninstall) { + this.uninstall = uninstall; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeOperationStatusResponse.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeOperationStatusResponse.java new file mode 100644 index 000000000..9389a51fc --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeOperationStatusResponse.java @@ -0,0 +1,88 @@ +/*- + * ============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.policy.clamp.clds.model.dcae; + +import com.google.gson.annotations.Expose; + +/** + * This class maps the DCAE deployment handler response to a nice pojo. + */ +public class DcaeOperationStatusResponse { + + @Expose + private String operationType; + + @Expose + private String status; + + @Expose + private String requestId; + + @Expose + private String error; + + @Expose + private DcaeLinks links; + + public String getOperationType() { + return operationType; + } + + public void setOperationType(String operationType) { + this.operationType = operationType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public DcaeLinks getLinks() { + return links; + } + + public void setLinks(DcaeLinks links) { + this.links = links; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/DistributionStatusMessage.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/DistributionStatusMessage.java new file mode 100644 index 000000000..ca46c6d31 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/DistributionStatusMessage.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.sdc.controller; + +import org.onap.sdc.api.consumer.IDistributionStatusMessage; +import org.onap.sdc.utils.DistributionStatusEnum; + +public class DistributionStatusMessage implements IDistributionStatusMessage { + + private String artifactUrl; + private String consumerId; + private String distributionId; + private DistributionStatusEnum distributionStatus; + private long timestamp; + + /** + * Distribution status message constructor. + * + * @param artifactUrl + * Url of specific SDC artifact(resource) + * @param consumerId + * Unique ID of SDC component instance + * @param distributionId + * Distribution ID published in the distribution notification. + * @param distributionStatusEnum + * Status to send in the message + * @param timestamp + * Timestamp of the message + */ + public DistributionStatusMessage(final String artifactUrl, final String consumerId, final String distributionId, + final DistributionStatusEnum distributionStatusEnum, final long timestamp) { + this.artifactUrl = artifactUrl; + this.consumerId = consumerId; + this.distributionId = distributionId; + this.distributionStatus = distributionStatusEnum; + this.timestamp = timestamp; + } + + @Override + public String getArtifactURL() { + return artifactUrl; + } + + @Override + public String getConsumerID() { + return consumerId; + } + + @Override + public String getDistributionID() { + return distributionId; + } + + @Override + public DistributionStatusEnum getStatus() { + return distributionStatus; + } + + @Override + public long getTimestamp() { + return timestamp; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleController.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleController.java new file mode 100644 index 000000000..39e64e46b --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleController.java @@ -0,0 +1,438 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2018-2019, 2021 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============================================ + * Modifications copyright (c) 2018 Nokia + * =================================================================== + * + */ + +package org.onap.policy.clamp.clds.sdc.controller; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.security.SecureRandom; +import java.util.Date; +import java.util.Map.Entry; +import org.onap.policy.clamp.clds.config.ClampProperties; +import org.onap.policy.clamp.clds.config.sdc.SdcSingleControllerConfiguration; +import org.onap.policy.clamp.clds.exception.sdc.controller.BlueprintParserException; +import org.onap.policy.clamp.clds.exception.sdc.controller.CsarHandlerException; +import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException; +import org.onap.policy.clamp.clds.exception.sdc.controller.SdcControllerException; +import org.onap.policy.clamp.clds.exception.sdc.controller.SdcDownloadException; +import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintArtifact; +import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler; +import org.onap.policy.clamp.clds.util.LoggingUtils; +import org.onap.policy.clamp.loop.CsarInstaller; +import org.onap.sdc.api.IDistributionClient; +import org.onap.sdc.api.consumer.IComponentDoneStatusMessage; +import org.onap.sdc.api.consumer.IDistributionStatusMessage; +import org.onap.sdc.api.consumer.INotificationCallback; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientFactory; +import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException; +import org.onap.sdc.utils.DistributionActionResultEnum; +import org.onap.sdc.utils.DistributionStatusEnum; + +/** + * This class handles one sdc controller defined in the config. + */ +public class SdcSingleController { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(SdcSingleController.class); + private boolean isSdcClientAutoManaged = false; + private CsarInstaller csarInstaller; + private ClampProperties refProp; + /** + * The constant CONFIG_SDC_FOLDER. + */ + public static final String CONFIG_SDC_FOLDER = "sdc.csarFolder"; + private int nbOfNotificationsOngoing = 0; + private SdcSingleControllerStatus controllerStatus = SdcSingleControllerStatus.STOPPED; + private SdcSingleControllerConfiguration sdcConfig; + private IDistributionClient distributionClient; + + /** + * Inner class for Notification callback. + */ + private final class SdcNotificationCallBack implements INotificationCallback { + + private SdcSingleController sdcController; + + /** + * Instantiates a new Sdc notification call back. + * + * @param controller the controller + */ + SdcNotificationCallBack(SdcSingleController controller) { + sdcController = controller; + } + + /** + * This method can be called multiple times at the same moment. The controller + * must be thread safe ! + */ + @Override + public void activateCallback(INotificationData notificationData) { + Date startTime = new Date(); + logger.info("Receive a callback notification in SDC, nb of resources: " + + notificationData.getResources().size()); + sdcController.treatNotification(notificationData); + LoggingUtils.setTimeContext(startTime, new Date()); + LoggingUtils.setResponseContext("0", "SDC Notification received and processed successfully", + this.getClass().getName()); + } + } + + /** + * Gets nb of notifications ongoing. + * + * @return the nb of notifications ongoing + */ + public int getNbOfNotificationsOngoing() { + return nbOfNotificationsOngoing; + } + + private void changeControllerStatusIdle() { + if (this.nbOfNotificationsOngoing > 1) { + --this.nbOfNotificationsOngoing; + } else { + this.nbOfNotificationsOngoing = 0; + this.controllerStatus = SdcSingleControllerStatus.IDLE; + } + } + + /** + * Change controller status. + * + * @param newControllerStatus the new controller status + */ + protected final synchronized void changeControllerStatus(SdcSingleControllerStatus newControllerStatus) { + switch (newControllerStatus) { + case BUSY: + ++this.nbOfNotificationsOngoing; + this.controllerStatus = newControllerStatus; + break; + case IDLE: + this.changeControllerStatusIdle(); + break; + default: + this.controllerStatus = newControllerStatus; + break; + } + } + + /** + * Gets controller status. + * + * @return the controller status + */ + public final synchronized SdcSingleControllerStatus getControllerStatus() { + return this.controllerStatus; + } + + /** + * Instantiates a new Sdc single controller. + * + * @param clampProp the clamp prop + * @param csarInstaller the csar installer + * @param sdcSingleConfig the sdc single config + * @param distributionClient the distribution client + */ + public SdcSingleController(ClampProperties clampProp, CsarInstaller csarInstaller, + SdcSingleControllerConfiguration sdcSingleConfig, + IDistributionClient distributionClient) { + this.distributionClient = distributionClient; + isSdcClientAutoManaged = (distributionClient == null); + this.sdcConfig = sdcSingleConfig; + this.refProp = clampProp; + this.csarInstaller = csarInstaller; + } + + /** + * This method initializes the SDC Controller and the SDC Client. + * + * @throws SdcControllerException It throws an exception if the SDC Client + * cannot be instantiated or if an init attempt + * is done when already initialized + */ + public void initSdc() throws SdcControllerException { + logger.info("Attempt to initialize the SDC Controller: " + sdcConfig.getSdcControllerName()); + if (this.getControllerStatus() != SdcSingleControllerStatus.STOPPED) { + throw new SdcControllerException("The controller is already initialized, call the closeSDC method first"); + } + if (distributionClient == null) { + distributionClient = DistributionClientFactory.createDistributionClient(); + } + IDistributionClientResult result = distributionClient.init(sdcConfig, new SdcNotificationCallBack(this)); + if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) { + logger.error("SDC distribution client init failed with reason:" + result.getDistributionMessageResult()); + this.changeControllerStatus(SdcSingleControllerStatus.STOPPED); + throw new SdcControllerException("Initialization of the SDC Controller failed with reason: " + + result.getDistributionMessageResult()); + } + logger.info("SDC Controller successfully initialized: " + sdcConfig.getSdcControllerName()); + logger.info("Attempt to start the SDC Controller: " + sdcConfig.getSdcControllerName()); + result = this.distributionClient.start(); + if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) { + logger.error("SDC distribution client start failed with reason:" + result.getDistributionMessageResult()); + this.changeControllerStatus(SdcSingleControllerStatus.STOPPED); + throw new SdcControllerException( + "Startup of the SDC Controller failed with reason: " + result.getDistributionMessageResult()); + } + logger.info("SDC Controller successfully started: " + sdcConfig.getSdcControllerName()); + this.changeControllerStatus(SdcSingleControllerStatus.IDLE); + } + + /** + * This method closes the SDC Controller and the SDC Client. + * + * @throws SdcControllerException It throws an exception if the SDC Client + * cannot be closed because it's currently BUSY + * in processing notifications. + */ + public void closeSdc() throws SdcControllerException { + if (this.getControllerStatus() == SdcSingleControllerStatus.BUSY) { + throw new SdcControllerException("Cannot close the SDC controller as it's currently in BUSY state"); + } + if (this.distributionClient != null) { + this.distributionClient.stop(); + // If auto managed we can set it to Null, SdcController controls it. + // In the other case the client of this class has specified it, so + // we can't reset it + if (isSdcClientAutoManaged) { + // Next init will initialize it with a new SDC Client + this.distributionClient = null; + } + } + this.changeControllerStatus(SdcSingleControllerStatus.STOPPED); + } + + private void sendAllNotificationForCsarHandler(INotificationData notificationData, CsarHandler csar, + NotificationType notificationType, + DistributionStatusEnum distributionStatus, String errorMessage) { + if (csar != null) { + // Notify for the CSAR + this.sendSdcNotification(notificationType, csar.getArtifactElement().getArtifactURL(), + sdcConfig.getConsumerID(), notificationData.getDistributionID(), distributionStatus, errorMessage, + System.currentTimeMillis()); + // Notify for all VF resources found + for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) { + // Normally always 1 artifact in resource for Clamp as we + // specified + // only VF_METADATA type + this.sendSdcNotification(notificationType, + blueprint.getValue().getResourceAttached().getArtifacts().get(0).getArtifactURL(), + sdcConfig.getConsumerID(), notificationData.getDistributionID(), distributionStatus, + errorMessage, System.currentTimeMillis()); + } + } else { + this.sendSdcNotification(notificationType, null, sdcConfig.getConsumerID(), + notificationData.getDistributionID(), distributionStatus, errorMessage, System.currentTimeMillis()); + } + } + + /** + * This method processes the notification received from Sdc. + * + * @param notificationData The INotificationData + */ + public void treatNotification(INotificationData notificationData) { + CsarHandler csar = null; + try { + // wait for a random time, so that 2 running Clamp will not treat + // the same Notification at the same time + Thread.sleep((new SecureRandom().nextInt(10) + 1) * 1000L); + logger.info("Notification received for service UUID:" + notificationData.getServiceUUID()); + this.changeControllerStatus(SdcSingleControllerStatus.BUSY); + csar = new CsarHandler(notificationData, this.sdcConfig.getSdcControllerName(), + refProp.getStringValue(CONFIG_SDC_FOLDER)); + csar.save(downloadTheArtifact(csar.getArtifactElement())); + if (csarInstaller.isCsarAlreadyDeployed(csar)) { + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DOWNLOAD, + DistributionStatusEnum.ALREADY_DOWNLOADED, null); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.ALREADY_DEPLOYED, null); + } else { + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DOWNLOAD, + DistributionStatusEnum.DOWNLOAD_OK, null); + csarInstaller.installTheCsar(csar); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_OK, null); + } + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_OK, null); + } catch (SdcArtifactInstallerException | SdcToscaParserException e) { + logger.error("SdcArtifactInstallerException exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + } catch (SdcDownloadException | CsarHandlerException e) { + logger.error("SdcDownloadException exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DOWNLOAD, + DistributionStatusEnum.DOWNLOAD_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + } catch (InterruptedException e) { + logger.error("Interrupt exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + Thread.currentThread().interrupt(); + } catch (BlueprintParserException e) { + logger.error("BlueprintParser exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + } catch (RuntimeException e) { + logger.error("Unexpected exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + } finally { + this.changeControllerStatus(SdcSingleControllerStatus.IDLE); + } + } + + private enum NotificationType { + /** + * Download notification type. + */ + DOWNLOAD, + /** + * Deploy notification type. + */ + DEPLOY + } + + private IDistributionClientDownloadResult downloadTheArtifact(IArtifactInfo artifact) throws SdcDownloadException { + logger.info("Trying to download the artifact : " + artifact.getArtifactURL() + " UUID: " + + artifact.getArtifactUUID()); + IDistributionClientDownloadResult downloadResult; + try { + downloadResult = distributionClient.download(artifact); + if (null == downloadResult) { + logger.info("downloadResult is Null for: " + artifact.getArtifactUUID()); + return null; + } + } catch (RuntimeException e) { + throw new SdcDownloadException("Exception caught when downloading the artifact", e); + } + if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) { + logger.info("Successfully downloaded the artifact " + artifact.getArtifactURL() + " UUID " + + artifact.getArtifactUUID() + "Size of payload " + downloadResult.getArtifactPayload().length); + } else { + throw new SdcDownloadException("Artifact " + artifact.getArtifactName() + + " could not be downloaded from SDC URL " + artifact.getArtifactURL() + " UUID " + + artifact.getArtifactUUID() + ")" + System.lineSeparator() + "Error message is " + + downloadResult.getDistributionMessageResult() + System.lineSeparator()); + } + return downloadResult; + } + + private void sendSdcNotification(NotificationType notificationType, String artifactUrl, String consumerId, + String distributionId, DistributionStatusEnum status, String errorReason, + long timestamp) { + String event = "Sending " + notificationType.name() + "(" + status.name() + ")" + + " notification to SDC for artifact:" + artifactUrl; + if (errorReason != null) { + event = event + "(" + errorReason + ")"; + } + logger.info(event); + String action = ""; + try { + IDistributionStatusMessage message = new DistributionStatusMessage(artifactUrl, consumerId, distributionId, + status, timestamp); + switch (notificationType) { + case DOWNLOAD: + this.sendDownloadStatus(message, errorReason); + action = "sendDownloadStatus"; + break; + case DEPLOY: + this.sendDeploymentStatus(message, errorReason); + action = "sendDeploymentdStatus"; + break; + default: + break; + } + } catch (RuntimeException e) { + logger.warn("Unable to send the SDC Notification (" + action + ") due to an exception", e); + } + logger.info("SDC Notification sent successfully(" + action + ")"); + } + + private void sendComponentStatus(INotificationData notificationData, DistributionStatusEnum status, + String errorReason) { + try { + IComponentDoneStatusMessage message = new IComponentDoneStatusMessage() { + + @Override + public String getDistributionID() { + return notificationData.getDistributionID(); + } + + @Override + public String getConsumerID() { + return sdcConfig.getConsumerID(); + } + + @Override + public long getTimestamp() { + return System.currentTimeMillis(); + } + + @Override + public DistributionStatusEnum getStatus() { + return status; + } + + @Override + public String getComponentName() { + return sdcConfig.getUser(); + } + }; + + if (errorReason != null) { + this.distributionClient.sendComponentDoneStatus(message, errorReason); + } else { + this.distributionClient.sendComponentDoneStatus(message); + } + } catch (RuntimeException e) { + logger.warn("Unable to send the SDC Notification (" + status.name() + ") due to an exception", e); + } + logger.info("SDC Notification sent successfully(" + status.name() + ")"); + } + + private void sendDownloadStatus(IDistributionStatusMessage message, String errorReason) { + if (errorReason != null) { + this.distributionClient.sendDownloadStatus(message, errorReason); + } else { + this.distributionClient.sendDownloadStatus(message); + } + } + + private void sendDeploymentStatus(IDistributionStatusMessage message, String errorReason) { + if (errorReason != null) { + this.distributionClient.sendDeploymentStatus(message, errorReason); + } else { + this.distributionClient.sendDeploymentStatus(message); + } + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleControllerStatus.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleControllerStatus.java new file mode 100644 index 000000000..fe269c486 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleControllerStatus.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.sdc.controller; + +public enum SdcSingleControllerStatus { + STOPPED, IDLE, BUSY +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintArtifact.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintArtifact.java new file mode 100644 index 000000000..df81cfb0c --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintArtifact.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.sdc.controller.installer; + +import org.onap.sdc.api.notification.IResourceInstance; + +/** + * This class is useful to store the information concerning + * blueprint artifact extracted from SDC CSAR. + */ +public class BlueprintArtifact { + + private String dcaeBlueprint; + private String blueprintArtifactName; + private String blueprintInvariantServiceUuid; + private IResourceInstance resourceAttached; + + public String getDcaeBlueprint() { + return dcaeBlueprint; + } + + public void setDcaeBlueprint(String dcaeBlueprint) { + this.dcaeBlueprint = dcaeBlueprint; + } + + public String getBlueprintArtifactName() { + return blueprintArtifactName; + } + + public void setBlueprintArtifactName(String blueprintArtifactName) { + this.blueprintArtifactName = blueprintArtifactName; + } + + public String getBlueprintInvariantServiceUuid() { + return blueprintInvariantServiceUuid; + } + + public void setBlueprintInvariantServiceUuid(String blueprintInvariantServiceUuid) { + this.blueprintInvariantServiceUuid = blueprintInvariantServiceUuid; + } + + public IResourceInstance getResourceAttached() { + return resourceAttached; + } + + public void setResourceAttached(IResourceInstance resourceAttached) { + this.resourceAttached = resourceAttached; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintMicroService.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintMicroService.java new file mode 100644 index 000000000..519a24f46 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintMicroService.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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============================================ + * Modifications copyright (c) 2019-2020 AT&T + * =================================================================== + * + */ + +package org.onap.policy.clamp.clds.sdc.controller.installer; + +import java.util.Objects; + +public class BlueprintMicroService { + private final String name; + private final String modelType; + private final String inputFrom; + private final String modelVersion; + + /** + * The Micro service constructor. + * + * @param name The name in String + * @param modelType The model type + * @param inputFrom Comes from (single chained) + */ + public BlueprintMicroService(String name, String modelType, String inputFrom, String modelVersion) { + this.name = name; + this.inputFrom = inputFrom; + this.modelType = modelType; + this.modelVersion = modelVersion; + } + + public String getName() { + return name; + } + + public String getModelType() { + return modelType; + } + + public String getInputFrom() { + return inputFrom; + } + + /** + * modelVerrsion getter. + * + * @return the modelVersion + */ + public String getModelVersion() { + return modelVersion; + } + + @Override + public String toString() { + return "MicroService {" + "name='" + name + '\'' + ", modelType='" + modelType + '\'' + ", inputFrom='" + + inputFrom + '\'' + ", modelVersion='" + modelVersion + '\'' + '}'; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + BlueprintMicroService that = (BlueprintMicroService) obj; + return name.equals(that.name) && modelType.equals(that.modelType) && inputFrom.equals(that.inputFrom) + && modelVersion.equals(that.modelVersion); + } + + @Override + public int hashCode() { + return Objects.hash(name, modelType, inputFrom, modelVersion); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParser.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParser.java new file mode 100644 index 000000000..ada47992a --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParser.java @@ -0,0 +1,220 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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============================================ + * Modifications copyright (c) 2019 AT&T + * =================================================================== + * + */ + +package org.onap.policy.clamp.clds.sdc.controller.installer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.json.JSONObject; +import org.onap.policy.clamp.clds.exception.sdc.controller.BlueprintParserException; +import org.yaml.snakeyaml.Yaml; + +public class BlueprintParser { + + static final String TCA = "TCA"; + private static final String NODE_TEMPLATES = "node_templates"; + private static final String DCAE_NODES = "dcae.nodes."; + private static final String DCAE_NODES_POLICY = ".nodes.policy"; + private static final String TYPE = "type"; + private static final String PROPERTIES = "properties"; + private static final String NAME = "name"; + private static final String INPUT = "inputs"; + private static final String GET_INPUT = "get_input"; + private static final String POLICY_MODEL_ID = "policy_model_id"; + private static final String POLICY_MODEL_VERSION = "policy_model_version"; + private static final String RELATIONSHIPS = "relationships"; + private static final String CLAMP_NODE_RELATIONSHIPS_GETS_INPUT_FROM = "clamp_node.relationships.gets_input_from"; + private static final String TARGET = "target"; + public static final String DEFAULT_VERSION = "1.0.0"; + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(BlueprintParser.class); + + private BlueprintParser() { + + } + + /** + * Get all micro services from blueprint. + * + * @param blueprintString the blueprint in a String + * @return A set of MircoService + * @throws BlueprintParserException In case of issues with the parsing + */ + public static Set<BlueprintMicroService> getMicroServices(String blueprintString) throws BlueprintParserException { + Set<BlueprintMicroService> microServices = new HashSet<>(); + JsonObject blueprintJson = BlueprintParser.convertToJson(blueprintString); + JsonObject nodeTemplateList = blueprintJson.get(NODE_TEMPLATES).getAsJsonObject(); + JsonObject inputList = blueprintJson.get(INPUT).getAsJsonObject(); + + for (Entry<String, JsonElement> entry : nodeTemplateList.entrySet()) { + JsonObject nodeTemplate = entry.getValue().getAsJsonObject(); + if (!nodeTemplate.get(TYPE).getAsString().contains(DCAE_NODES_POLICY) + && nodeTemplate.get(TYPE).getAsString().contains(DCAE_NODES)) { + BlueprintMicroService microService = getNodeRepresentation(entry, nodeTemplateList, inputList); + if (!microService.getModelType().isBlank()) { + microServices.add(microService); + } else { + logger.warn("Microservice " + microService.getName() + + " will NOT be used by CLAMP as the model type is not defined or has not been found"); + } + } + } + logger.debug("Those microservices have been found in the blueprint:" + microServices); + return microServices; + } + + /** + * Does a fallback to TCA. + * + * @return The list of microservices + */ + public static List<BlueprintMicroService> fallbackToOneMicroService() { + return Collections.singletonList( + new BlueprintMicroService(TCA, "onap.policies.monitoring.cdap.tca.hi.lo.app", "", DEFAULT_VERSION)); + } + + static String getName(Entry<String, JsonElement> entry) { + String microServiceYamlName = entry.getKey(); + JsonObject ob = entry.getValue().getAsJsonObject(); + if (ob.has(PROPERTIES)) { + JsonObject properties = ob.get(PROPERTIES).getAsJsonObject(); + if (properties.has(NAME)) { + return properties.get(NAME).getAsString(); + } + } + return microServiceYamlName; + } + + static String getInput(Entry<String, JsonElement> entry) { + JsonObject ob = entry.getValue().getAsJsonObject(); + if (ob.has(RELATIONSHIPS)) { + JsonArray relationships = ob.getAsJsonArray(RELATIONSHIPS); + for (JsonElement element : relationships) { + String target = getTarget(element.getAsJsonObject()); + if (!target.isEmpty()) { + return target; + } + } + } + return ""; + } + + static String findPropertyInRelationshipsArray(String propertyName, JsonArray relationshipsArray, + JsonObject blueprintNodeTemplateList, JsonObject blueprintInputList) throws BlueprintParserException { + for (JsonElement elem : relationshipsArray) { + if (blueprintNodeTemplateList.get(elem.getAsJsonObject().get(TARGET).getAsString()) == null) { + throw new BlueprintParserException( + "The Target mentioned in the blueprint is not a known entry in the blueprint: " + + elem.getAsJsonObject().get(TARGET).getAsString()); + } else { + String property = getPropertyValue(propertyName, + new AbstractMap.SimpleEntry<String, JsonElement>( + elem.getAsJsonObject().get(TARGET).getAsString(), blueprintNodeTemplateList + .get(elem.getAsJsonObject().get(TARGET).getAsString()).getAsJsonObject()), + blueprintNodeTemplateList, blueprintInputList); + if (!property.isEmpty()) { + return property; + } + } + } + return ""; + } + + static String getDirectOrInputPropertyValue(String propertyName, JsonObject blueprintInputList, + JsonObject nodeTemplateContent) { + JsonObject properties = nodeTemplateContent.get(PROPERTIES).getAsJsonObject(); + if (properties.has(propertyName)) { + if (properties.get(propertyName).isJsonObject()) { + // it's a blueprint parameter + return blueprintInputList + .get(properties.get(propertyName).getAsJsonObject().get(GET_INPUT).getAsString()) + .getAsJsonObject().get("default").getAsString(); + } else { + // It's a direct value + return properties.get(propertyName).getAsString(); + } + } + return ""; + } + + static String getPropertyValue(String propertyName, Entry<String, JsonElement> nodeTemplateEntry, + JsonObject blueprintNodeTemplateList, JsonObject blueprintIputList) throws BlueprintParserException { + JsonObject nodeTemplateContent = nodeTemplateEntry.getValue().getAsJsonObject(); + // Search first in this node template + if (nodeTemplateContent.has(PROPERTIES)) { + String propValue = getDirectOrInputPropertyValue(propertyName, blueprintIputList, nodeTemplateContent); + if (!propValue.isBlank()) { + return propValue; + } + } + // Or it's may be defined in a relationship + if (nodeTemplateContent.has(RELATIONSHIPS)) { + return findPropertyInRelationshipsArray(propertyName, + nodeTemplateContent.get(RELATIONSHIPS).getAsJsonArray(), blueprintNodeTemplateList, + blueprintIputList); + } + return ""; + } + + static BlueprintMicroService getNodeRepresentation(Entry<String, JsonElement> nodeTemplateEntry, + JsonObject blueprintNodeTemplateList, JsonObject blueprintInputList) throws BlueprintParserException { + String modelIdFound = getPropertyValue(POLICY_MODEL_ID, nodeTemplateEntry, blueprintNodeTemplateList, + blueprintInputList); + String versionFound = getPropertyValue(POLICY_MODEL_VERSION, nodeTemplateEntry, blueprintNodeTemplateList, + blueprintInputList); + if (modelIdFound.isBlank()) { + logger.warn("policy_model_id is not defined for the node template:" + nodeTemplateEntry.getKey()); + } + if (versionFound.isBlank()) { + logger.warn("policy_model_version is not defined (setting it to a default value) for the node template:" + + nodeTemplateEntry.getKey()); + } + return new BlueprintMicroService(getName(nodeTemplateEntry), modelIdFound, getInput(nodeTemplateEntry), + !versionFound.isBlank() ? versionFound : DEFAULT_VERSION); + } + + private static String getTarget(JsonObject elementObject) { + if (elementObject.has(TYPE) && elementObject.has(TARGET) + && elementObject.get(TYPE).getAsString().equals(CLAMP_NODE_RELATIONSHIPS_GETS_INPUT_FROM)) { + return elementObject.get(TARGET).getAsString(); + } + return ""; + } + + private static JsonObject convertToJson(String yamlString) { + Map<String, Object> map = new Yaml().load(yamlString); + return new Gson().fromJson(new JSONObject(map).toString(), JsonObject.class); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGenerator.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGenerator.java new file mode 100644 index 000000000..10e7a56a4 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGenerator.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.clamp.clds.sdc.controller.installer; + +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.springframework.stereotype.Component; + +@Component +public class ChainGenerator { + + ChainGenerator() { + } + + /** + * Get list of microservices chain. + * + * @param input A set of microservices + * @return The list of microservice chained + */ + public List<BlueprintMicroService> getChainOfMicroServices(Set<BlueprintMicroService> input) { + LinkedList<BlueprintMicroService> returnList = new LinkedList<>(); + if (preValidate(input)) { + LinkedList<BlueprintMicroService> theList = new LinkedList<>(); + for (BlueprintMicroService ms : input) { + insertNodeTemplateIntoChain(ms, theList); + } + if (postValidate(theList)) { + returnList = theList; + } + } + return returnList; + } + + private boolean preValidate(Set<BlueprintMicroService> input) { + List<BlueprintMicroService> noInputs = input.stream().filter(ms -> "".equals(ms.getInputFrom())) + .collect(Collectors.toList()); + return noInputs.size() == 1; + } + + private boolean postValidate(LinkedList<BlueprintMicroService> microServices) { + for (int i = 1; i < microServices.size() - 1; i++) { + BlueprintMicroService prev = microServices.get(i - 1); + BlueprintMicroService current = microServices.get(i); + if (!current.getInputFrom().equals(prev.getName())) { + return false; + } + } + return true; + } + + private void insertNodeTemplateIntoChain(BlueprintMicroService microServicetoInsert, + LinkedList<BlueprintMicroService> chainOfMicroServices) { + int insertIndex = 0; + for (int i = 0; i < chainOfMicroServices.size(); i++) { + BlueprintMicroService current = chainOfMicroServices.get(i); + if (microServicetoInsert.getName().equals(current.getInputFrom())) { + insertIndex = i; + break; + } else if (current.getName().equals(microServicetoInsert.getInputFrom())) { + insertIndex = i + 1; + break; + } + } + chainOfMicroServices.add(insertIndex, microServicetoInsert); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandler.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandler.java new file mode 100644 index 000000000..436e594ce --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandler.java @@ -0,0 +1,219 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.sdc.controller.installer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.apache.commons.io.IOUtils; +import org.codehaus.plexus.util.StringUtils; +import org.onap.policy.clamp.clds.exception.sdc.controller.CsarHandlerException; +import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.sdc.api.notification.IResourceInstance; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; +import org.onap.sdc.tosca.parser.api.ISdcCsarHelper; +import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException; +import org.onap.sdc.tosca.parser.impl.SdcToscaParserFactory; + +/** + * CsarDescriptor that will be used to deploy file in CLAMP file system. Some + * methods can also be used to get some data from it. + */ +public class CsarHandler { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(CsarHandler.class); + private IArtifactInfo artifactElement; + private String csarFilePath; + private String controllerName; + private SdcToscaParserFactory factory = SdcToscaParserFactory.getInstance(); + private ISdcCsarHelper sdcCsarHelper; + private Map<String, BlueprintArtifact> mapOfBlueprints = new HashMap<>(); + public static final String CSAR_TYPE = "TOSCA_CSAR"; + public static final String BLUEPRINT_TYPE = "DCAE_INVENTORY_BLUEPRINT"; + private INotificationData sdcNotification; + public static final String RESOURCE_INSTANCE_NAME_PREFIX = "/Artifacts/Resources/"; + public static final String RESOURCE_INSTANCE_NAME_SUFFIX = "/Deployment/"; + public static final String POLICY_DEFINITION_NAME_SUFFIX = "Definitions/policies.yml"; + public static final String DATA_DEFINITION_NAME_SUFFIX = "Definitions/data.yml"; + public static final String DATA_DEFINITION_KEY = "data_types:"; + + /** + * Constructor for CsarHandler taking sdc notification in input. + */ + public CsarHandler(INotificationData data, String controller, String clampCsarPath) throws CsarHandlerException { + this.sdcNotification = data; + this.controllerName = controller; + this.artifactElement = searchForUniqueCsar(data); + this.csarFilePath = buildFilePathForCsar(artifactElement, clampCsarPath); + } + + private String buildFilePathForCsar(IArtifactInfo artifactElement, String clampCsarPath) { + return clampCsarPath + "/" + controllerName + "/" + artifactElement.getArtifactName(); + } + + private IArtifactInfo searchForUniqueCsar(INotificationData notificationData) throws CsarHandlerException { + List<IArtifactInfo> serviceArtifacts = notificationData.getServiceArtifacts(); + for (IArtifactInfo artifact : serviceArtifacts) { + if (artifact.getArtifactType().equals(CSAR_TYPE)) { + return artifact; + } + } + throw new CsarHandlerException("Unable to find a CSAR in the Sdc Notification"); + } + + /** + * This saves the notification to disk and database. + * + * @param resultArtifact The artifact to install + * @throws SdcArtifactInstallerException In case of issues with the installation + * @throws SdcToscaParserException In case of issues with the parsing of + * the CSAR + */ + public synchronized void save(IDistributionClientDownloadResult resultArtifact) + throws SdcArtifactInstallerException, SdcToscaParserException { + try { + logger.info("Writing CSAR file to: " + csarFilePath + " UUID " + artifactElement.getArtifactUUID() + ")"); + Path path = Paths.get(csarFilePath); + Files.createDirectories(path.getParent()); + // Create or replace the file + try (OutputStream out = Files.newOutputStream(path)) { + out.write(resultArtifact.getArtifactPayload(), 0, resultArtifact.getArtifactPayload().length); + } + sdcCsarHelper = factory.getSdcCsarHelper(csarFilePath); + this.loadDcaeBlueprint(); + } catch (IOException e) { + throw new SdcArtifactInstallerException( + "Exception caught when trying to write the CSAR on the file system to " + csarFilePath, e); + } + } + + private IResourceInstance searchForResourceByInstanceName(String blueprintResourceInstanceName) + throws SdcArtifactInstallerException { + for (IResourceInstance resource : this.sdcNotification.getResources()) { + String filteredString = resource.getResourceInstanceName().replaceAll("-", ""); + filteredString = filteredString.replaceAll(" ", ""); + if (filteredString.equalsIgnoreCase(blueprintResourceInstanceName)) { + return resource; + } + } + throw new SdcArtifactInstallerException("Error when searching for " + blueprintResourceInstanceName + + " as ResourceInstanceName in Sdc notification and did not find it"); + } + + private void loadDcaeBlueprint() throws IOException, SdcArtifactInstallerException { + try (ZipFile zipFile = new ZipFile(csarFilePath)) { + Enumeration<? extends ZipEntry> entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (!entry.isDirectory() && entry.getName().contains(BLUEPRINT_TYPE)) { + BlueprintArtifact blueprintArtifact = new BlueprintArtifact(); + blueprintArtifact.setBlueprintArtifactName( + entry.getName().substring(entry.getName().lastIndexOf('/') + 1, entry.getName().length())); + blueprintArtifact + .setBlueprintInvariantServiceUuid(this.getSdcNotification().getServiceInvariantUUID()); + try (InputStream stream = zipFile.getInputStream(entry)) { + blueprintArtifact.setDcaeBlueprint(IOUtils.toString(stream, StandardCharsets.UTF_8)); + } + blueprintArtifact.setResourceAttached(searchForResourceByInstanceName(entry.getName().substring( + entry.getName().indexOf(RESOURCE_INSTANCE_NAME_PREFIX) + + RESOURCE_INSTANCE_NAME_PREFIX.length(), + entry.getName().indexOf(RESOURCE_INSTANCE_NAME_SUFFIX)))); + this.mapOfBlueprints.put(blueprintArtifact.getBlueprintArtifactName(), blueprintArtifact); + logger.info("Found a blueprint entry in the CSAR " + blueprintArtifact.getBlueprintArtifactName() + + " for resource instance Name " + + blueprintArtifact.getResourceAttached().getResourceInstanceName()); + } + } + logger.info(this.mapOfBlueprints.size() + " blueprint(s) will be converted to closed loop"); + } + } + + public IArtifactInfo getArtifactElement() { + return artifactElement; + } + + public String getFilePath() { + return csarFilePath; + } + + public String setFilePath(String newPath) { + return csarFilePath = newPath; + } + + public synchronized ISdcCsarHelper getSdcCsarHelper() { + return sdcCsarHelper; + } + + public INotificationData getSdcNotification() { + return sdcNotification; + } + + public Map<String, BlueprintArtifact> getMapOfBlueprints() { + return mapOfBlueprints; + } + + /** + * Get the whole policy model Yaml. It combines the content of policies.yaml and + * data.yaml. + * + * @return The whole policy model yaml + * @throws IOException The IO Exception + */ + public Optional<String> getPolicyModelYaml() throws IOException { + String result = null; + try (ZipFile zipFile = new ZipFile(csarFilePath)) { + ZipEntry entry = zipFile.getEntry(POLICY_DEFINITION_NAME_SUFFIX); + if (entry != null) { + ZipEntry data = zipFile.getEntry(DATA_DEFINITION_NAME_SUFFIX); + if (data != null) { + String dataStr = IOUtils.toString(zipFile.getInputStream(data), StandardCharsets.UTF_8); + String dataStrWithoutHeader = dataStr.substring(dataStr.indexOf(DATA_DEFINITION_KEY)); + String policyStr = IOUtils.toString(zipFile.getInputStream(entry), StandardCharsets.UTF_8); + StringUtils.chomp(policyStr); + result = policyStr.concat(dataStrWithoutHeader); + } else { + result = IOUtils.toString(zipFile.getInputStream(entry), StandardCharsets.UTF_8); + } + } else { + logger.info("Policy model not found inside the CSAR file: " + csarFilePath); + } + return Optional.ofNullable(result); + } + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/service/CldsHealthcheckService.java b/runtime/src/main/java/org/onap/policy/clamp/clds/service/CldsHealthcheckService.java new file mode 100644 index 000000000..02481494a --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/service/CldsHealthcheckService.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.clamp.clds.service; + +import java.util.Date; +import org.onap.policy.clamp.clds.model.CldsHealthCheck; +import org.onap.policy.clamp.clds.util.LoggingUtils; +import org.onap.policy.clamp.clds.util.OnapLogConstants; +import org.onap.policy.clamp.loop.LoopController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Service to retrieve the Health Check of the clds application. + * + */ +@Component +public class CldsHealthcheckService { + + @Autowired + private LoopController loopController; + + protected static final Logger logger = LoggerFactory.getLogger(CldsHealthcheckService.class); + + /** + * REST service that retrieves clds healthcheck information. + * + * @return CldsHealthCheck class containing healthcheck info + */ + public CldsHealthCheck gethealthcheck() { + CldsHealthCheck cldsHealthCheck = new CldsHealthCheck(); + Date startTime = new Date(); + LoggingUtils util = new LoggingUtils(logger); + LoggingUtils.setRequestContext("CldsService: GET healthcheck", "Clamp-Health-Check"); + LoggingUtils.setTimeContext(startTime, new Date()); + try { + loopController.getLoopNames(); + cldsHealthCheck.setHealthCheckComponent("CLDS-APP"); + cldsHealthCheck.setHealthCheckStatus("UP"); + cldsHealthCheck.setDescription("OK"); + LoggingUtils.setResponseContext("0", "Get healthcheck success", + this.getClass().getName()); + util.exiting(HttpStatus.OK.value(), "Healthcheck success", Level.INFO, + OnapLogConstants.ResponseStatus.COMPLETE); + } catch (Exception e) { + logger.error("CLAMP application Heath check failed", e); + LoggingUtils.setResponseContext("999", "Get healthcheck failed", + this.getClass().getName()); + cldsHealthCheck.setHealthCheckComponent("CLDS-APP"); + cldsHealthCheck.setHealthCheckStatus("DOWN"); + cldsHealthCheck.setDescription("NOT-OK"); + util.exiting(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Healthcheck failed", Level.INFO, + OnapLogConstants.ResponseStatus.ERROR); + } + return cldsHealthCheck; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/JsonEditorSchemaConstants.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/JsonEditorSchemaConstants.java new file mode 100644 index 000000000..32f328079 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/JsonEditorSchemaConstants.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018-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.policy.clamp.clds.tosca; + +public class JsonEditorSchemaConstants { + + //Data types in JSON Schema + public static final String TYPE_OBJECT = "object"; + public static final String TYPE_ARRAY = "array"; + public static final String TYPE_MAP = "map"; + public static final String TYPE_STRING = "string"; + public static final String TYPE_INTEGER = "integer"; + public static final String TYPE_DATE_TIME = "datetime"; + + //Key elements in JSON Schema + public static final String TYPE = "type"; + public static final String TITLE = "title"; + public static final String REQUIRED = "required"; + public static final String DEFAULT = "default"; + public static final String ENUM = "enum"; + public static final String ENUM_TITLES = "enum_titles"; + public static final String OPTIONS = "options"; + public static final String FORMAT = "format"; + public static final String ITEMS = "items"; + public static final String PROPERTIES = "properties"; + public static final String PROPERTY_ORDER = "propertyOrder"; + public static final String VALUES = "values"; + public static final String HEADER_TEMPLATE = "headerTemplate"; + public static final String HEADER_TEMPLATE_VALUE = "{{self.name}}"; + + public static final String MINIMUM = "minimum"; + public static final String MAXIMUM = "maximum"; + public static final String MIN_LENGTH = "minLength"; + public static final String MAX_LENGTH = "maxLength"; + public static final String EXCLUSIVE_MINIMUM = "exclusiveMinimum"; + public static final String EXCLUSIVE_MAXIMUM = "exclusiveMaximum"; + public static final String MINITEMS = "minItems"; + public static final String MAXITEMS = "maxItems"; + + public static final String CUSTOM_KEY_FORMAT = "format"; + public static final String CUSTOM_KEY_FORMAT_TABS_TOP = "tabs-top"; + public static final String CUSTOM_KEY_FORMAT_TABS = "tabs"; + public static final String CUSTOM_KEY_FORMAT_INPUT = "input"; + public static final String FORMAT_SELECT = "select"; + public static final String UNIQUE_ITEMS = "uniqueItems"; + public static final String TRUE = "true"; + public static final String QSSCHEMA = "qschema"; + public static final String TYPE_QBLDR = "qbldr"; + + public static final String ID = "id"; + public static final String LABEL = "label"; + public static final String OPERATORS = "operators"; + public static final String FILTERS = "filters"; + + public static final String SCHEMA = "schema"; + public static final String CURRENT_VALUES = "currentValues"; + + public static final String PLUGIN = "plugin"; + public static final String DATE_TIME_PICKER = "datetimepicker"; + public static final String VALIDATION = "validation"; + public static final String DATE_TIME_FORMAT = "YYYY/MM/DD HH:mm:ss"; + public static final String INPUT_EVENT = "input_event"; + public static final String DP_CHANGE = "dp.change"; + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/ToscaSchemaConstants.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/ToscaSchemaConstants.java new file mode 100644 index 000000000..c2b5d5963 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/ToscaSchemaConstants.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.tosca; + +public class ToscaSchemaConstants { + + // Data types in TOSCA Schema + public static final String TYPE_LIST = "list"; + public static final String TYPE_MAP = "map"; + public static final String TYPE_STRING = "string"; + public static final String TYPE_INTEGER = "integer"; + public static final String TYPE_NUMBER = "number"; + public static final String TYPE_DATE_TIME = "datetime"; + public static final String TYPE_FLOAT = "float"; + public static final String TYPE_BOOLEAN = "boolean"; + public static final String TYPE_USER_DEFINED = "userDefined"; + + // Key elements in Tosca + public static final String NODE_TYPES = "policy_types"; + public static final String DATA_TYPES = "data_types"; + public static final String TYPE = "type"; + public static final String DESCRIPTION = "description"; + public static final String DEFAULT = "default"; + public static final String PROPERTIES = "properties"; + public static final String REQUIRED = "required"; + public static final String ENTRY_SCHEMA = "entry_schema"; + + public static final String METADATA = "metadata"; + public static final String METADATA_POLICY_MODEL_TYPE = "policy_model_type"; + public static final String METADATA_ACRONYM = "acronym"; + public static final String METADATA_ELEMENT_NAME = "element_name"; + public static final String METADATA_HEADER_TEMPLATE = "header_template"; + public static final String METADATA_CLAMP_POSSIBLE_VALUES = "clamp_possible_values"; + + // Constraints + public static final String CONSTRAINTS = "constraints"; + public static final String VALID_VALUES = "valid_values"; + public static final String EQUAL = "equal"; + public static final String GREATER_THAN = "greater_than"; + public static final String GREATER_OR_EQUAL = "greater_or_equal"; + public static final String LESS_THAN = "less_than"; + public static final String LESS_OR_EQUAL = "less_or_equal"; + public static final String IN_RANGE = "in_range"; + public static final String LENGTH = "length"; + public static final String MIN_LENGTH = "min_length"; + public static final String MAX_LENGTH = "max_length"; + public static final String PATTERN = "pattern"; + + // Prefix for policy nodes + public static final String POLICY_NODE = "onap.policies."; + + // Prefix for data nodes + public static final String POLICY_DATA = "onap.datatypes."; + + // Prefix for dictionary elements + public static final String DICTIONARY = "Dictionary:"; + + // Custom Elements that must exist in the Tosca models + public static final String NAME = "name"; + public static final String CONTEXT = "context"; + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java new file mode 100644 index 000000000..6702a6200 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020-2021 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.clamp.clds.tosca.update; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import java.io.IOException; +import org.onap.policy.clamp.clds.config.ClampProperties; +import org.onap.policy.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParser; +import org.onap.policy.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParserWithDictionarySupport; +import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateManager; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.loop.service.Service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * This is the main class that must be used to convert a tosca to a json schema. + * This class adds feature to support the dictionary mechanism that enables json possible values extracted + * from the dictionary DB table. + * + * @see org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport#convertToscaToJsonSchemaObject + */ +@Component +public class ToscaConverterWithDictionarySupport { + + private static final EELFLogger logger = + EELFManager.getInstance().getLogger(ToscaConverterWithDictionarySupport.class); + + private ClampProperties clampProperties; + private ToscaMetadataParser metadataParser; + + /** + * Constructor with Spring support. + * + * @param clampProperties Clamp Spring properties + * @param metadataParser Metadata parser + */ + @Autowired + public ToscaConverterWithDictionarySupport(ClampProperties clampProperties, + ToscaMetadataParserWithDictionarySupport metadataParser) { + this.clampProperties = clampProperties; + this.metadataParser = metadataParser; + } + + /** + * This method converts a tosca file to a json schema. + * It uses some parameters specified in the application.properties. + * + * @param toscaFile The tosca file as String + * @param policyTypeToDecode The policy type to decode + * @param serviceModel The service model associated so that the clamp enrichment could be done if required by + * the tosca model + * @return A json object being a json schema + */ + public JsonObject convertToscaToJsonSchemaObject(String toscaFile, String policyTypeToDecode, + Service serviceModel) { + try { + return new JsonTemplateManager(toscaFile, + clampProperties.getFileContent("tosca.converter.default.datatypes"), + clampProperties.getFileContent("tosca.converter.json.schema.templates")) + .getJsonSchemaForPolicyType(policyTypeToDecode, Boolean.parseBoolean(clampProperties.getStringValue( + "tosca.converter.dictionary.support.enabled")) ? metadataParser : null, serviceModel); + } catch (IOException | UnknownComponentException e) { + logger.error("Unable to convert the tosca properly, exception caught during the decoding", + e); + return new JsonObject(); + } + } + + /** + * This method converts a tosca file to a json schema. + * It uses some parameters specified in the application.properties. + * + * @param toscaFile The tosca file as String + * @param policyTypeToDecode The policy type to decode + * @param serviceModel The service Model so that clamp enrichment could be done if required by tosca model + * @return A String containing the json schema + */ + public String convertToscaToJsonSchemaString(String toscaFile, String policyTypeToDecode, Service serviceModel) { + return JsonUtils.GSON.toJson(this.convertToscaToJsonSchemaObject(toscaFile, policyTypeToDecode, serviceModel)); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/UnknownComponentException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/UnknownComponentException.java new file mode 100644 index 000000000..fb684b57b --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/UnknownComponentException.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update; + +public class UnknownComponentException extends Exception { + public UnknownComponentException(String nameEntry) { + this.getWrongName(nameEntry); + } + + public String getWrongName(String nameEntry) { + return "Unknown Component: " + nameEntry; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ArrayField.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ArrayField.java new file mode 100644 index 000000000..fb9d66752 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ArrayField.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.elements; + +import com.google.gson.JsonArray; +import java.util.ArrayList; + +public class ArrayField { + + private ArrayList<Object> complexFields; + + /** + * Constructor from arraryList. + * + * @param arrayProperties the array properties + */ + public ArrayField(ArrayList<Object> arrayProperties) { + this.complexFields = arrayProperties; + } + + /** + * Each LinkedHashMap is parsed to extract the Array and each of its value. They are casted for the JsonObject. + * + * @return JsonArray + */ + public JsonArray deploy() { + + JsonArray subPropertyValuesArray = new JsonArray(); + for (Object arrayElement : complexFields) { + //Cast for each Primitive Type + String typeValue = arrayElement.getClass().getSimpleName(); + switch (typeValue) { + case "String": + subPropertyValuesArray.add((String) arrayElement); + break; + case "Boolean": + subPropertyValuesArray.add((Boolean) arrayElement); + break; + case "Double": + subPropertyValuesArray.add((Number) arrayElement); + break; + case "Integer": + subPropertyValuesArray.add((Number) arrayElement); + break; + default: + break; + } + } + return subPropertyValuesArray; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/Constraint.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/Constraint.java new file mode 100644 index 000000000..651456ca6 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/Constraint.java @@ -0,0 +1,222 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.elements; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map.Entry; +import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate; + +public class Constraint { + + private LinkedHashMap<String, Object> constraints; + private JsonTemplate jsonTemplate; + + public Constraint(LinkedHashMap<String, Object> constraints, JsonTemplate jsonTemplate) { + this.jsonTemplate = jsonTemplate; + this.constraints = constraints; + } + + /** + * Deploy the linkedhashmap which contains the constraints, to extract them one to one. + * + * @param jsonSchema The json Schema + * @param typeProperty The ype property + * @return the json object + */ + public JsonObject deployConstraints(JsonObject jsonSchema, String typeProperty) { + for (Entry<String, Object> constraint : constraints.entrySet()) { + this.parseConstraint(jsonSchema, constraint.getKey(), constraint.getValue(), typeProperty); + } + return jsonSchema; + } + + /** + * Each case of Tosca constraints below parse specifically the field in the JsonObject. + * + * @param jsonSchema Json Schema + * @param nameConstraint Name constraint + * @param valueConstraint value constraint + * @param typeProperty Type Property + */ + @SuppressWarnings("unchecked") + public void parseConstraint(JsonObject jsonSchema, String nameConstraint, Object valueConstraint, + String typeProperty) { + switch (nameConstraint) { + case "equal": + checkTemplateField("const", jsonSchema, valueConstraint); + break; + case "greater_than": + checkTemplateField("exclusiveMinimum", jsonSchema, valueConstraint); + break; + case "greater_or_equal": + checkTemplateField("minimum", jsonSchema, valueConstraint); + break; + case "less_than": + checkTemplateField("exclusiveMaximum", jsonSchema, valueConstraint); + break; + case "less_or_equal": + checkTemplateField("maximum", jsonSchema, valueConstraint); + break; + case "in_range": + ArrayList<Integer> limitValues = (ArrayList<Integer>) valueConstraint; + checkTemplateField("minimum", jsonSchema, limitValues.get(0)); + checkTemplateField("maximum", jsonSchema, limitValues.get(1)); + break; + case "pattern": + jsonSchema.addProperty(nameConstraint, (String) valueConstraint); + break; + case "length": + this.getSpecificLength(jsonSchema, valueConstraint, typeProperty); + break; + case "min_length": + String[] prefixValues = nameConstraint.split("_"); + this.getLimitValue(jsonSchema, valueConstraint, typeProperty, prefixValues[0]); + break; + case "max_length": + String[] maxtab = nameConstraint.split("_"); + this.getLimitValue(jsonSchema, valueConstraint, typeProperty, maxtab[0]); + break; + default://valid_value + this.getValueArray(jsonSchema, valueConstraint, typeProperty); + break; + } + + } + + /** + * To be done. + * + * @param jsonSchema json schema + * @param fieldValue field value + * @param typeProperty For the complex components, get a specific number of items/properties + */ + public void getSpecificLength(JsonObject jsonSchema, Object fieldValue, String typeProperty) { + switch (typeProperty.toLowerCase()) { + case "string": + checkTemplateField("minLength", jsonSchema, fieldValue); + checkTemplateField("maxLength", jsonSchema, fieldValue); + break; + case "array": + if (fieldValue.equals(1) && jsonTemplate.hasFields("uniqueItems")) { + jsonSchema.addProperty("uniqueItems", true); + } else { + checkTemplateField("minItems", jsonSchema, fieldValue); + checkTemplateField("maxItems", jsonSchema, fieldValue); + } + break; + default:// Map && List + checkTemplateField("minProperties", jsonSchema, fieldValue); + checkTemplateField("maxProperties", jsonSchema, fieldValue); + break; + } + + } + + /** + * To be done. + * + * @param jsonSchema json schema + * @param fieldValue field value + * @param typeProperty type property + * @param side Get the limits fieldValue for the properties : depend of the type of the component + */ + public void getLimitValue(JsonObject jsonSchema, Object fieldValue, String typeProperty, String side) { + switch (typeProperty) { + case "string": + if (side.equals("min")) { + checkTemplateField("minLength", jsonSchema, fieldValue); + } else { + checkTemplateField("maxLength", jsonSchema, fieldValue); + } + break; + default:// Array + if (side.equals("min")) { + checkTemplateField("minItems", jsonSchema, fieldValue); + } else { + checkTemplateField("maxItems", jsonSchema, fieldValue); + } + break; + } + + } + + /** + * To be done. + * + * @param jsonSchema Json schema + * @param fieldValue field value + * @param typeProperty Get as Enum the valid values for the property + */ + public void getValueArray(JsonObject jsonSchema, Object fieldValue, String typeProperty) { + if (jsonTemplate.hasFields("enum")) { + JsonArray enumeration = new JsonArray(); + if (typeProperty.equals("string") || typeProperty.equals("String")) { + ArrayList<String> arrayValues = (ArrayList<String>) fieldValue; + for (String arrayItem : arrayValues) { + enumeration.add(arrayItem); + } + jsonSchema.add("enum", enumeration); + } else { + ArrayList<Number> arrayValues = (ArrayList<Number>) fieldValue; + for (Number arrayItem : arrayValues) { + enumeration.add(arrayItem); + } + jsonSchema.add("enum", enumeration); + } + } + } + + /** + * To be done. + * + * @param field Field + * @param jsonSchema Json schema + * @param fieldValue Simple way to avoid code duplication + */ + public void checkTemplateField(String field, JsonObject jsonSchema, Object fieldValue) { + if (jsonTemplate.hasFields(field)) { + String typeField = fieldValue.getClass().getSimpleName(); + switch (typeField) { + case "String": + jsonSchema.addProperty(field, (String) fieldValue); + break; + case "Integer": + jsonSchema.addProperty(field, (Integer) fieldValue); + break; + case "Number": + jsonSchema.addProperty(field, (Number) fieldValue); + break; + case "Boolean": + jsonSchema.addProperty(field, (Boolean) fieldValue); + break; + default: + break; + } + } + } + +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElement.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElement.java new file mode 100644 index 000000000..0c531e9d0 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElement.java @@ -0,0 +1,121 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.elements; + +import java.util.ArrayList; +import java.util.LinkedHashMap; + +public class ToscaElement { + + /** + * name parameter is used as "key", in the LinkedHashMap of Components. + */ + private String name; + private String derivedFrom; + private String version; + private String typeVersion; + private String description; + private LinkedHashMap<String, ToscaElementProperty> properties; + + public ToscaElement() { + } + + /** + * Constructor. + * + * @param name name + * @param derivedFrom derivedFrom + * @param description description + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public ToscaElement(String name, String derivedFrom, String description) { + super(); + this.name = name; + this.derivedFrom = derivedFrom; + this.description = description; + this.properties = new LinkedHashMap(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDerivedFrom() { + return derivedFrom; + } + + public void setDerivedFrom(String derivedFrom) { + this.derivedFrom = derivedFrom; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getTypeVersion() { + return typeVersion; + } + + public void setTypeVersion(String typeVersion) { + this.typeVersion = typeVersion; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LinkedHashMap<String, ToscaElementProperty> getProperties() { + return properties; + } + + public void setProperties(LinkedHashMap<String, ToscaElementProperty> properties) { + this.properties = properties; + } + + public void addProperties(ToscaElementProperty toscaElementProperty) { + this.properties.put(toscaElementProperty.getName(), toscaElementProperty); + } + + public ArrayList<String> propertiesNames() { + return new ArrayList<>(properties.keySet()); + } + + @Override + public String toString() { + return name + ": " + description + ", version: " + version + ", nb de properties: " + properties.size() + + System.getProperty("line.separator") + propertiesNames(); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElementProperty.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElementProperty.java new file mode 100644 index 000000000..4db8b0356 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElementProperty.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.elements; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate; + +public class ToscaElementProperty { + + /** + * name parameter is used as "key", in the LinkedHashMap of Components. + */ + private String name; + private LinkedHashMap<String, Object> items; + + /** + * Constructor. + * + * @param name the name + * @param items the items + */ + public ToscaElementProperty(String name, LinkedHashMap<String, Object> items) { + super(); + this.name = name; + this.items = items; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LinkedHashMap<String, Object> getItems() { + return items; + } + + public void setItems(LinkedHashMap<String, Object> items) { + this.items = items; + } + + /** + * For each primitive value, requires to get each field Value and cast it and add it in a Json. + * + * @param fieldsContent field + * @param fieldName field + * @param value value + */ + public void addFieldToJson(JsonObject fieldsContent, String fieldName, Object value) { + if (value != null) { + String typeValue = value.getClass().getSimpleName(); + switch (typeValue) { + case "String": + fieldsContent.addProperty(fieldName, (String) value); + break; + case "Boolean": + fieldsContent.addProperty(fieldName, (Boolean) value); + break; + case "Double": + fieldsContent.addProperty(fieldName, (Number) value); + break; + case "Integer": + fieldsContent.addProperty(fieldName, (Integer) value); + break; + default: + fieldsContent.add(fieldName, parseArray((ArrayList) value)); + break; + } + } + } + + /** + * If a field value is an Array, create an Instance of ArrayField to insert if in the JsonObject. + * + * @param arrayProperties array pro + * @return a json array + */ + public JsonArray parseArray(ArrayList<Object> arrayProperties) { + JsonArray arrayContent = new JsonArray(); + ArrayList<Object> arrayComponent = new ArrayList<>(); + for (Object itemArray : arrayProperties) { + arrayComponent.add(itemArray); + } + ArrayField af = new ArrayField(arrayComponent); + arrayContent = af.deploy(); + return arrayContent; + } + + /** + * Create an instance of Constraint, to extract the values and add it to the Json (according to the type + * * of the current property). + * + * @param json a json + * @param constraints constraints + * @param jsonTemplate template + */ + @SuppressWarnings("unchecked") + public void addConstraintsAsJson(JsonObject json, ArrayList<Object> constraints, JsonTemplate jsonTemplate) { + for (Object constraint : constraints) { + if (constraint instanceof LinkedHashMap) { + LinkedHashMap<String, Object> valueConstraint = (LinkedHashMap<String, Object>) constraint; + Constraint constraintParser = new Constraint(valueConstraint, jsonTemplate); + constraintParser.deployConstraints(json, (String) getItems().get("type")); + } + } + + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java new file mode 100644 index 000000000..5fac9a213 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020-2021 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.clamp.clds.tosca.update.execution; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.onap.policy.clamp.clds.tosca.update.execution.cds.ToscaMetadataCdsProcess; +import org.onap.policy.clamp.loop.service.Service; +import org.onap.policy.clamp.tosca.DictionaryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * This class is used to execute a code based on a key found in the metadata section. + */ +@Component +public class ToscaMetadataExecutor { + + private static final EELFLogger logger = + EELFManager.getInstance().getLogger(ToscaMetadataExecutor.class); + + @Autowired + private DictionaryService dictionaryService; + + private Map<String, ToscaMetadataProcess> mapOfProcesses = new HashMap<>(); + + /** + * This method executes the required process specified in processInfo. + * + * @param processInfo A String containing the process to execute, like "cds/param1:value1/param2:value2" + * @param childObject The jsonObject + * @param serviceModel The service model associated to do clamp enrichment + */ + public void executeTheProcess(String processInfo, JsonObject childObject, Service serviceModel) { + String[] processParameters = (processInfo + "/ ").split("/"); + logger.info("Executing the Tosca clamp process " + processParameters[0] + " with parameters " + + processParameters[1].trim()); + mapOfProcesses.get(processParameters[0].trim()) + .executeProcess(processParameters[1].trim(), childObject, serviceModel); + } + + /** + * Init method. + */ + @PostConstruct + public void init() { + mapOfProcesses.put("CDS", new ToscaMetadataCdsProcess()); + mapOfProcesses.put("CSAR_RESOURCES", new ToscaMetadataTargetProcess()); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java new file mode 100644 index 000000000..a1275229d --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.execution; + +import com.google.gson.JsonObject; +import org.onap.policy.clamp.loop.service.Service; + +/** + * This code is the interface that must be implemented to have a tosca process. + */ +public abstract class ToscaMetadataProcess { + + /** + * This method add some elements to the JsonObject childObject passed in argument. + * The process can take multiple parameters in arguments. + * + * @param parameters The parameters required by the process + * @param childObject The Json Object modified by the current process + * @param serviceModel The service model associated to do clamp enrichment + */ + public abstract void executeProcess(String parameters, JsonObject childObject, Service serviceModel); +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataTargetProcess.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataTargetProcess.java new file mode 100644 index 000000000..0ffd86f47 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataTargetProcess.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020-2021 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.clamp.clds.tosca.update.execution; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import org.onap.policy.clamp.loop.service.Service; +import org.onap.policy.clamp.policy.operational.OperationalPolicyRepresentationBuilder; + +/** + * This class is there to add the JsonObject for CDS in the json Schema according to what is found in the Tosca model. + */ +public class ToscaMetadataTargetProcess extends ToscaMetadataProcess { + + + private static final EELFLogger logger = + EELFManager.getInstance().getLogger(ToscaMetadataTargetProcess.class); + + @Override + public void executeProcess(String parameters, JsonObject childObject, Service serviceModel) { + if (serviceModel == null) { + logger.info("serviceModel is null, therefore the ToscaMetadataTargetProcess is skipped"); + return; + } + childObject.add("anyOf", OperationalPolicyRepresentationBuilder.createAnyOfArray(serviceModel, false)); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java new file mode 100644 index 000000000..c80c91170 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java @@ -0,0 +1,229 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020-2021 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.clamp.clds.tosca.update.execution.cds; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.util.Map; +import java.util.Set; +import org.onap.policy.clamp.clds.tosca.ToscaSchemaConstants; +import org.onap.policy.clamp.clds.tosca.update.execution.ToscaMetadataProcess; +import org.onap.policy.clamp.loop.service.Service; + + +/** + * This class is there to add the JsonObject for CDS in the json Schema according to what is found in the Tosca model. + */ +public class ToscaMetadataCdsProcess extends ToscaMetadataProcess { + + private static final EELFLogger logger = + EELFManager.getInstance().getLogger(ToscaMetadataCdsProcess.class); + + @Override + public void executeProcess(String parameters, JsonObject childObject, Service serviceModel) { + if (serviceModel == null) { + logger.info("serviceModel is null, therefore the ToscaMetadataCdsProcess is skipped"); + return; + } + switch (parameters) { + case "actor": + JsonArray jsonArray = new JsonArray(); + jsonArray.add("CDS"); + addToJsonArray(childObject, "enum", jsonArray); + break; + case "payload": + generatePayload(childObject, serviceModel); + break; + case "operation": + generateOperation(childObject, serviceModel); + break; + default: + } + } + + private static void generatePayload(JsonObject childObject, Service serviceModel) { + JsonArray schemaAnyOf = new JsonArray(); + schemaAnyOf.addAll(createBlankEntry()); + schemaAnyOf.addAll(generatePayloadPerResource("VF", serviceModel)); + schemaAnyOf.addAll(generatePayloadPerResource("PNF", serviceModel)); + addToJsonArray(childObject, "anyOf", schemaAnyOf); + } + + private static void generateOperation(JsonObject childObject, Service serviceModel) { + generateOperationPerResource(childObject, "VF", serviceModel); + generateOperationPerResource(childObject, "PNF", serviceModel); + } + + private static void generateOperationPerResource(JsonObject childObject, String resourceName, + Service serviceModel) { + JsonArray schemaEnum = new JsonArray(); + JsonArray schemaTitle = new JsonArray(); + for (Map.Entry<String, JsonElement> entry : serviceModel.getResourceDetails().getAsJsonObject(resourceName) + .entrySet()) { + JsonObject controllerProperties = entry.getValue().getAsJsonObject() + .getAsJsonObject("controllerProperties"); + if (controllerProperties != null && controllerProperties.getAsJsonObject("workflows") != null) { + for (String workflowsEntry : controllerProperties.getAsJsonObject("workflows").keySet()) { + schemaEnum.add(workflowsEntry); + schemaTitle.add(workflowsEntry + " (CDS operation)"); + } + } + } + addToJsonArray(childObject, "enum", schemaEnum); + if (childObject.get("options") == null) { + JsonObject optionsSection = new JsonObject(); + childObject.add("options", optionsSection); + } + addToJsonArray(childObject.getAsJsonObject("options"), "enum_titles", schemaTitle); + + } + + private static JsonArray generatePayloadPerResource(String resourceName, + Service serviceModel) { + JsonArray schemaAnyOf = new JsonArray(); + + for (Map.Entry<String, JsonElement> entry : serviceModel.getResourceDetails().getAsJsonObject(resourceName) + .entrySet()) { + JsonObject controllerProperties = entry.getValue().getAsJsonObject() + .getAsJsonObject("controllerProperties"); + if (controllerProperties != null && controllerProperties.getAsJsonObject("workflows") != null) { + for (Map.Entry<String, JsonElement> workflowsEntry : controllerProperties.getAsJsonObject("workflows") + .entrySet()) { + JsonObject obj = new JsonObject(); + obj.addProperty("title", workflowsEntry.getKey()); + obj.add("properties", + createInputPropertiesForPayload(workflowsEntry.getValue().getAsJsonObject(), + controllerProperties, + workflowsEntry.getKey())); + schemaAnyOf.add(obj); + } + } + } + return schemaAnyOf; + } + + private static JsonArray createBlankEntry() { + JsonArray result = new JsonArray(); + JsonObject blankObject = new JsonObject(); + blankObject.addProperty("title", "User defined"); + blankObject.add("properties", new JsonObject()); + result.add(blankObject); + return result; + } + + private static JsonObject createAnyOfJsonProperty(String name, + String defaultValue, + boolean readOnlyFlag) { + JsonObject result = new JsonObject(); + result.addProperty("title", name); + result.addProperty("type", "string"); + result.addProperty("default", defaultValue); + result.addProperty("readOnly", readOnlyFlag); + return result; + } + + private static void addToJsonArray(JsonObject childObject, String section, JsonArray value) { + if (childObject.getAsJsonArray(section) != null) { + childObject.getAsJsonArray(section).addAll(value); + } else { + childObject.add(section, value); + } + } + + /** + * Returns the properties of payload based on the cds work flows. + * + * @param workFlow cds work flows to update payload + * @param controllerProperties cds properties to get blueprint name and + * version + * @param workFlowName work flow name + * @return returns the properties of payload + */ + public static JsonObject createInputPropertiesForPayload(JsonObject workFlow, + JsonObject controllerProperties, + String workFlowName) { + String artifactName = controllerProperties.get("sdnc_model_name").getAsString(); + String artifactVersion = controllerProperties.get("sdnc_model_version").getAsString(); + JsonObject inputs = workFlow.getAsJsonObject("inputs"); + JsonObject jsonObject = new JsonObject(); + jsonObject.add("artifact_name", createAnyOfJsonProperty( + "artifact name", artifactName, true)); + jsonObject.add("artifact_version", createAnyOfJsonProperty( + "artifact version", artifactVersion, true)); + jsonObject.add("mode", createAnyOfJsonProperty( + "mode", "async", false)); + jsonObject.add("data", createDataProperty(inputs, workFlowName)); + return jsonObject; + } + + private static JsonObject createDataProperty(JsonObject inputs, String workFlowName) { + JsonObject data = new JsonObject(); + data.addProperty("title", "data"); + data.addProperty("type", "string"); + data.addProperty("format", "textarea"); + JsonObject defaultValue = new JsonObject(); + addDefaultValueForData(inputs, defaultValue, workFlowName); + data.addProperty("default", defaultValue.toString()); + return data; + } + + private static void addDefaultValueForData(JsonObject inputs, + JsonObject defaultValue, + String workFlowName) { + Set<Map.Entry<String, JsonElement>> entrySet = inputs.entrySet(); + for (Map.Entry<String, JsonElement> entry : entrySet) { + String key = entry.getKey(); + JsonObject inputProperty = inputs.getAsJsonObject(key); + if (key.equalsIgnoreCase(workFlowName + "-properties")) { + addDefaultValueForData(entry.getValue().getAsJsonObject().get("properties") + .getAsJsonObject(), defaultValue, workFlowName); + } else if ("object".equalsIgnoreCase(inputProperty.get(ToscaSchemaConstants.TYPE).getAsString())) { + JsonObject object = new JsonObject(); + addDefaultValueForData(entry.getValue().getAsJsonObject().get("properties") + .getAsJsonObject(), object, workFlowName); + defaultValue.add(entry.getKey(), object); + } else if (ToscaSchemaConstants.TYPE_LIST.equalsIgnoreCase(inputProperty.get(ToscaSchemaConstants.TYPE) + .getAsString())) { + defaultValue.add(entry.getKey(), handleListType(entry.getValue().getAsJsonObject(), workFlowName)); + } else { + defaultValue.addProperty(entry.getKey(), ""); + } + } + } + + private static JsonArray handleListType(JsonObject inputs, + String workFlowName) { + + JsonObject object = new JsonObject(); + if (inputs.get("properties") != null) { + addDefaultValueForData(inputs.get("properties").getAsJsonObject(), object, workFlowName); + } + JsonArray arr = new JsonArray(); + arr.add(object); + return arr; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java new file mode 100644 index 000000000..74fd8e5fd --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java @@ -0,0 +1,353 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020-2021 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.clamp.clds.tosca.update.parser; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map.Entry; +import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement; +import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty; +import org.onap.policy.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParser; +import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate; +import org.onap.policy.clamp.loop.service.Service; + +/** + * This class can be used to convert a tosca to a json schema. + * This class is not supposed to be used directly because it requires the json Schema templates + * (template conversion tosca type to json schema entry) but also the supported Tosca main type file. + * The class ToscaConverterWithDictionarySupport is more complete for the end user to be used (in the clamp context). + * + * @see org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport#convertToscaToJsonSchemaObject + * @see org.onap.policy.clamp.clds.tosca.update.parser.ToscaConverterToJsonSchema#getJsonSchemaOfToscaElement + */ +public class ToscaConverterToJsonSchema { + private LinkedHashMap<String, ToscaElement> components; + private LinkedHashMap<String, JsonTemplate> templates; + + private ToscaMetadataParser metadataParser; + + private Service serviceModel; + + /** + * Constructor. + * + * @param toscaElementsMap All the tosca elements found (policy type + data types + native tosca datatypes) + * @param jsonSchemaTemplates All Json schema templates to use + * @param metadataParser The metadata parser to use for metadata section + * @param serviceModel The service model for clamp enrichment + */ + public ToscaConverterToJsonSchema(LinkedHashMap<String, ToscaElement> toscaElementsMap, + LinkedHashMap<String, JsonTemplate> jsonSchemaTemplates, + ToscaMetadataParser metadataParser, Service serviceModel) { + this.components = toscaElementsMap; + this.templates = jsonSchemaTemplates; + this.metadataParser = metadataParser; + this.serviceModel = serviceModel; + } + + /** + * For a given component, launch process to parse it in Json. + * + * @param toscaElementKey name components + * @return return + */ + public JsonObject getJsonSchemaOfToscaElement(String toscaElementKey) { + return this.getFieldAsObject(getToscaElement(toscaElementKey)); + } + + /** + * Return the classical/general fields of the component, & launch the properties deployment. + * + * @param toscaElement the compo + * @return a json object + */ + public JsonObject getFieldAsObject(ToscaElement toscaElement) { + + JsonObject globalFields = new JsonObject(); + if (templates.get("object").hasFields("title")) { + globalFields.addProperty("title", toscaElement.getName()); + } + if (templates.get("object").hasFields("type")) { + globalFields.addProperty("type", "object"); + } + if (templates.get("object").hasFields("description")) { + if (toscaElement.getDescription() != null) { + globalFields.addProperty("description", toscaElement.getDescription()); + } + } + if (templates.get("object").hasFields("required")) { + globalFields.add("required", this.getRequirements(toscaElement.getName())); + } + if (templates.get("object").hasFields("properties")) { + globalFields.add("properties", this.deploy(toscaElement.getName())); + } + return globalFields; + } + + /** + * Get the required properties of the Component, including the parents properties requirements. + * + * @param nameComponent name component + * @return a json array + */ + public JsonArray getRequirements(String nameComponent) { + JsonArray requirements = new JsonArray(); + ToscaElement toParse = components.get(nameComponent); + //Check for a father component, and launch the same process + if (!"tosca.datatypes.Root".equals(toParse.getDerivedFrom()) + && !"tosca.policies.Root".equals(toParse.getDerivedFrom())) { + requirements.addAll(getRequirements(toParse.getDerivedFrom())); + } + //Each property is checked, and add to the requirement array if it's required + Collection<ToscaElementProperty> properties = toParse.getProperties().values(); + for (ToscaElementProperty toscaElementProperty : properties) { + if (toscaElementProperty.getItems().containsKey("required") + && toscaElementProperty.getItems().get("required").equals(true)) { + requirements.add(toscaElementProperty.getName()); + } + } + return requirements; + } + + /** + * The beginning of the recursive process. Get the parents (or not) to launch the same process, and otherwise + * deploy and parse the properties. + * + * @param nameComponent name component + * @return a json object + */ + public JsonObject deploy(String nameComponent) { + JsonObject jsonSchema = new JsonObject(); + ToscaElement toParse = components.get(nameComponent); + //Check for a father component, and launch the same process + if (!toParse.getDerivedFrom().equals("tosca.datatypes.Root") + && !toParse.getDerivedFrom().equals("tosca.policies.Root")) { + jsonSchema = this.getParent(toParse.getDerivedFrom()); + } + //For each component property, check if its a complex properties (a component) or not. In that case, + //launch the analyse of the property. + for (Entry<String, ToscaElementProperty> property : toParse.getProperties().entrySet()) { + if (getToscaElement((String) property.getValue().getItems().get("type")) != null) { + jsonSchema.add(property.getValue().getName(), + this.getJsonSchemaOfToscaElement((String) property.getValue().getItems().get("type"))); + } else { + jsonSchema.add(property.getValue().getName(), this.complexParse(property.getValue())); + } + } + return jsonSchema; + } + + /** + * If a component has a parent, it is deploy in the same way. + * + * @param nameComponent name component + * @return a json object + */ + public JsonObject getParent(String nameComponent) { + return deploy(nameComponent); + } + + /** + * to be done. + * + * @param toscaElementProperty property + * @return a json object + */ + @SuppressWarnings("unchecked") + public JsonObject complexParse(ToscaElementProperty toscaElementProperty) { + JsonObject propertiesInJson = new JsonObject(); + JsonTemplate currentPropertyJsonTemplate; + String typeProperty = (String) toscaElementProperty.getItems().get("type"); + if (typeProperty.toLowerCase().equals("list") || typeProperty.toLowerCase().equals("map")) { + currentPropertyJsonTemplate = templates.get("object"); + } else { + String propertyType = (String) toscaElementProperty.getItems().get("type"); + currentPropertyJsonTemplate = templates.get(propertyType.toLowerCase()); + } + //Each "special" field is analysed, and has a specific treatment + for (String propertyField : toscaElementProperty.getItems().keySet()) { + switch (propertyField) { + case "type": + if (currentPropertyJsonTemplate.hasFields(propertyField)) { + String fieldtype = (String) toscaElementProperty.getItems().get(propertyField); + switch (fieldtype.toLowerCase()) { + case "list": + propertiesInJson.addProperty("type", "array"); + break; + case "map": + propertiesInJson.addProperty("type", "object"); + break; + case "scalar-unit.time": + case "scalar-unit.frequency": + case "scalar-unit.size": + propertiesInJson.addProperty("type", "string"); + break; + case "timestamp": + propertiesInJson.addProperty("type", "string"); + propertiesInJson.addProperty("format", "date-time"); + break; + case "float": + propertiesInJson.addProperty("type", "number"); + break; + case "range": + propertiesInJson.addProperty("type", "integer"); + if (!checkConstraintPresence(toscaElementProperty, "greater_than") + && currentPropertyJsonTemplate.hasFields("exclusiveMinimum")) { + propertiesInJson.addProperty("exclusiveMinimum", false); + } + if (!checkConstraintPresence(toscaElementProperty, "less_than") + && currentPropertyJsonTemplate.hasFields("exclusiveMaximum")) { + propertiesInJson.addProperty("exclusiveMaximum", false); + } + break; + default: + propertiesInJson.addProperty("type", currentPropertyJsonTemplate.getName()); + break; + } + } + break; + case "metadata": + if (metadataParser != null) { + metadataParser.processAllMetadataElement(toscaElementProperty, serviceModel).entrySet() + .forEach((jsonEntry) -> { + propertiesInJson.add(jsonEntry.getKey(), + jsonEntry.getValue()); + + }); + } + break; + case "constraints": + toscaElementProperty.addConstraintsAsJson(propertiesInJson, + (ArrayList<Object>) toscaElementProperty.getItems().get("constraints"), + currentPropertyJsonTemplate); + break; + case "entry_schema": + //Here, a way to check if entry is a component (datatype) or a simple string + if (getToscaElement(this.extractSpecificFieldFromMap(toscaElementProperty, "entry_schema")) + != null) { + String nameComponent = this.extractSpecificFieldFromMap(toscaElementProperty, "entry_schema"); + ToscaConverterToJsonSchema child = new ToscaConverterToJsonSchema(components, templates, + metadataParser, serviceModel); + JsonObject propertiesContainer = new JsonObject(); + + switch ((String) toscaElementProperty.getItems().get("type")) { + case "map": // Get it as an object + JsonObject componentAsProperty = child.getJsonSchemaOfToscaElement(nameComponent); + propertiesContainer.add(nameComponent, componentAsProperty); + if (currentPropertyJsonTemplate.hasFields("properties")) { + propertiesInJson.add("properties", propertiesContainer); + } + break; + default://list : get it as an Array + JsonObject componentAsItem = child.getJsonSchemaOfToscaElement(nameComponent); + if (currentPropertyJsonTemplate.hasFields("properties")) { + propertiesInJson.add("items", componentAsItem); + propertiesInJson.addProperty("format", "tabs-top"); + } + break; + } + + } else if (toscaElementProperty.getItems().get("type").equals("list")) { + // Native cases + JsonObject itemContainer = new JsonObject(); + String valueInEntrySchema = + this.extractSpecificFieldFromMap(toscaElementProperty, "entry_schema"); + itemContainer.addProperty("type", valueInEntrySchema); + propertiesInJson.add("items", itemContainer); + propertiesInJson.addProperty("format", "tabs-top"); + } + + // MAP Case, for now nothing + + break; + default: + //Each classical field : type, description, default.. + if (currentPropertyJsonTemplate.hasFields(propertyField) && !propertyField.equals("required")) { + toscaElementProperty.addFieldToJson(propertiesInJson, propertyField, + toscaElementProperty.getItems().get(propertyField)); + } + break; + } + } + return propertiesInJson; + } + + /** + * Look for a matching Component for the name parameter, in the components list. + * + * @param name the tosca element name to search for + * @return a tosca element + */ + public ToscaElement getToscaElement(String name) { + ToscaElement correspondingToscaElement = null; + if (components == null) { + return null; + } + for (ToscaElement toscaElement : components.values()) { + if (toscaElement.getName().equals(name)) { + correspondingToscaElement = toscaElement; + } + } + return correspondingToscaElement; + } + + /** + * Simple method to extract quickly a type field from particular property item. + * + * @param toscaElementProperty the property + * @param fieldName the fieldname + * @return a string + */ + @SuppressWarnings("unchecked") + public String extractSpecificFieldFromMap(ToscaElementProperty toscaElementProperty, String fieldName) { + LinkedHashMap<String, String> entrySchemaFields = + (LinkedHashMap<String, String>) toscaElementProperty.getItems().get(fieldName); + return entrySchemaFields.get("type"); + } + + /** + * Check if a constraint, for a specific property, is there. + * + * @param toscaElementProperty property + * @param nameConstraint name constraint + * @return a flag boolean + */ + public boolean checkConstraintPresence(ToscaElementProperty toscaElementProperty, String nameConstraint) { + boolean presentConstraint = false; + if (toscaElementProperty.getItems().containsKey("constraints")) { + ArrayList<Object> constraints = (ArrayList) toscaElementProperty.getItems().get("constraints"); + for (Object constraint : constraints) { + if (constraint instanceof LinkedHashMap) { + if (((LinkedHashMap) constraint).containsKey(nameConstraint)) { + presentConstraint = true; + } + } + } + } + return presentConstraint; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaElementParser.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaElementParser.java new file mode 100644 index 000000000..a3dd9c3e1 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaElementParser.java @@ -0,0 +1,103 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.parser; + +import java.util.LinkedHashMap; +import java.util.Map.Entry; +import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement; +import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty; +import org.yaml.snakeyaml.Yaml; + +public class ToscaElementParser { + /** + * Constructor. + */ + private ToscaElementParser() { + } + + private static LinkedHashMap<String, Object> searchAllDataTypesAndPolicyTypes(String toscaYaml) { + LinkedHashMap<String, LinkedHashMap<String, Object>> file = + (LinkedHashMap<String, LinkedHashMap<String, Object>>) new Yaml().load(toscaYaml); + LinkedHashMap<String, Object> allDataTypesFound = file.get("data_types"); + LinkedHashMap<String, Object> allPolicyTypesFound = file.get("policy_types"); + LinkedHashMap<String, Object> allItemsFound = new LinkedHashMap<>(); + // Put the policies and datatypes in the same collection + allItemsFound = (allDataTypesFound == null) ? (new LinkedHashMap<>()) : allDataTypesFound; + allItemsFound.putAll(allPolicyTypesFound == null ? new LinkedHashMap<>() : allPolicyTypesFound); + return allItemsFound; + } + + private static LinkedHashMap<String, Object> searchAllNativeToscaDataTypes(String toscaNativeYaml) { + return ((LinkedHashMap<String, LinkedHashMap<String, Object>>) new Yaml().load(toscaNativeYaml)) + .get("data_types"); + } + + /** + * Yaml Parse gets raw policies and datatypes, in different sections : necessary to extract + * all entities and put them at the same level. + * + * @param toscaYaml the tosca model content + * @param nativeToscaYaml the tosca native datatype content + * @return a map of Tosca Element containing all tosca elements found (policy types and datatypes) + */ + public static LinkedHashMap<String, ToscaElement> searchAllToscaElements(String toscaYaml, + String nativeToscaYaml) { + LinkedHashMap<String, Object> allItemsFound = searchAllDataTypesAndPolicyTypes(toscaYaml); + allItemsFound.putAll(searchAllNativeToscaDataTypes(nativeToscaYaml)); + return parseAllItemsFound(allItemsFound); + } + + /** + * With all the component, get as Map, Components and Components properties are created. + * + * @param allMaps maps + */ + private static LinkedHashMap<String, ToscaElement> parseAllItemsFound(LinkedHashMap<String, Object> allMaps) { + LinkedHashMap<String, ToscaElement> allItemsFound = new LinkedHashMap<String, ToscaElement>(); + //Component creations, from the file maps + for (Entry<String, Object> itemToParse : allMaps.entrySet()) { + LinkedHashMap<String, Object> componentBody = (LinkedHashMap<String, Object>) itemToParse.getValue(); + ToscaElement toscaElement = + new ToscaElement(itemToParse.getKey(), (String) componentBody.get("derived_from"), + (String) componentBody.get("description")); + //If policy, version and type_version : + if (componentBody.get("type_version") != null) { + toscaElement.setVersion((String) componentBody.get("type_version")); + toscaElement.setTypeVersion((String) componentBody.get("type_version")); + } + //Properties creation, from the map + if (componentBody.get("properties") != null) { + LinkedHashMap<String, Object> properties = + (LinkedHashMap<String, Object>) componentBody.get("properties"); + for (Entry<String, Object> itemToProperty : properties.entrySet()) { + ToscaElementProperty toscaElementProperty = new ToscaElementProperty(itemToProperty.getKey(), + (LinkedHashMap<String, Object>) itemToProperty.getValue()); + toscaElement.addProperties(toscaElementProperty); + } + } + allItemsFound.put(toscaElement.getName(), toscaElement); + } + return allItemsFound; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java new file mode 100644 index 000000000..b2568b79f --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.parser.metadata; + +import com.google.gson.JsonObject; +import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty; +import org.onap.policy.clamp.loop.service.Service; + +public interface ToscaMetadataParser { + JsonObject processAllMetadataElement(ToscaElementProperty toscaElementProperty, Service serviceModel); +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java new file mode 100644 index 000000000..4e55263fb --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java @@ -0,0 +1,211 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.parser.metadata; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Optional; +import org.onap.policy.clamp.clds.tosca.JsonEditorSchemaConstants; +import org.onap.policy.clamp.clds.tosca.ToscaSchemaConstants; +import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty; +import org.onap.policy.clamp.clds.tosca.update.execution.ToscaMetadataExecutor; +import org.onap.policy.clamp.loop.service.Service; +import org.onap.policy.clamp.tosca.DictionaryElement; +import org.onap.policy.clamp.tosca.DictionaryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ToscaMetadataParserWithDictionarySupport implements ToscaMetadataParser { + + @Autowired + private ToscaMetadataExecutor toscaMetadataExecutor; + + @Autowired + private DictionaryService dictionaryService; + + /** + * This method is used to start the processing of the metadata field. + * + * @param toscaElementProperty The property metadata as Json Object + * @return The jsonObject structure that must be added to the json schema + */ + public JsonObject processAllMetadataElement(ToscaElementProperty toscaElementProperty, Service serviceModel) { + if (dictionaryService != null) { + return parseMetadataPossibleValues(toscaElementProperty.getItems(), dictionaryService, serviceModel, + toscaMetadataExecutor); + } else { + return null; + } + } + + private static JsonObject parseMetadataPossibleValues(LinkedHashMap<String, Object> childNodeMap, + DictionaryService dictionaryService, Service serviceModel, + ToscaMetadataExecutor toscaMetadataExecutor) { + JsonObject childObject = new JsonObject(); + if (childNodeMap.containsKey(ToscaSchemaConstants.METADATA) + && childNodeMap.get(ToscaSchemaConstants.METADATA) != null) { + ((LinkedHashMap<String, Object>) childNodeMap.get(ToscaSchemaConstants.METADATA)).forEach((key, + value) -> { + if (key.equalsIgnoreCase(ToscaSchemaConstants.METADATA_CLAMP_POSSIBLE_VALUES)) { + String[] multipleValues = ((String) value).split(","); + for (String multipleValue : multipleValues) { + if (multipleValue.contains(ToscaSchemaConstants.DICTIONARY)) { + processDictionaryElements(multipleValue, childObject, dictionaryService); + } + if (multipleValue.contains("ClampExecution:")) { + executeClampProcess(multipleValue.replaceFirst("ClampExecution:", ""), childObject, + serviceModel, toscaMetadataExecutor); + } + } + + } + }); + } + return childObject; + } + + private static void executeClampProcess(String processInfo, JsonObject childObject, Service serviceModel, + ToscaMetadataExecutor toscaMetadataExecutor) { + toscaMetadataExecutor.executeTheProcess(processInfo, childObject, serviceModel); + } + + /** + * For dictionary with multiple levels (defined by #). + * + * @param dictionaryKeyArray the array containing the different elements + * @param childObject the structure getting the new entries + * @param dictionaryService the dictionary service bean + */ + private static void processComplexDictionaryElements(String[] dictionaryKeyArray, JsonObject childObject, + DictionaryService dictionaryService) { + // We support only one # as of now. + List<DictionaryElement> dictionaryElements = null; + if (dictionaryKeyArray.length == 2) { + dictionaryElements = new ArrayList<>(dictionaryService.getDictionary(dictionaryKeyArray[0]) + .getDictionaryElements()); + JsonArray subDictionaryNames = new JsonArray(); + new ArrayList<DictionaryElement>(dictionaryService.getDictionary(dictionaryKeyArray[1]) + .getDictionaryElements()).forEach(elem -> subDictionaryNames.add(elem.getShortName())); + + JsonArray jsonArray = new JsonArray(); + + Optional.of(dictionaryElements).get().forEach(c -> { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty(JsonEditorSchemaConstants.TYPE, getJsonType(c.getType())); + if (c.getType() != null + && c.getType().equalsIgnoreCase(ToscaSchemaConstants.TYPE_STRING)) { + jsonObject.addProperty(JsonEditorSchemaConstants.MIN_LENGTH, 1); + + } + jsonObject.addProperty(JsonEditorSchemaConstants.ID, c.getName()); + jsonObject.addProperty(JsonEditorSchemaConstants.LABEL, c.getShortName()); + jsonObject.add(JsonEditorSchemaConstants.OPERATORS, subDictionaryNames); + jsonArray.add(jsonObject); + }); + + JsonObject filterObject = new JsonObject(); + filterObject.add(JsonEditorSchemaConstants.FILTERS, jsonArray); + + childObject.addProperty(JsonEditorSchemaConstants.TYPE, + JsonEditorSchemaConstants.TYPE_QBLDR); + // TO invoke validation on such parameters + childObject.addProperty(JsonEditorSchemaConstants.MIN_LENGTH, 1); + childObject.add(JsonEditorSchemaConstants.QSSCHEMA, filterObject); + + } + } + + /** + * For dictionary with single entry. + * + * @param dictionaryKeyArray the array containing the different elements + * @param childObject the structure getting the new entries + * @param dictionaryService the dictionary service bean + */ + private static void processSimpleDictionaryElements(String[] dictionaryKeyArray, JsonObject childObject, + DictionaryService dictionaryService) { + JsonArray dictionaryNames = new JsonArray(); + JsonArray dictionaryFullNames = new JsonArray(); + dictionaryService.getDictionary(dictionaryKeyArray[0]).getDictionaryElements().forEach(c -> { + // Json type will be translated before Policy creation + if (c.getType() != null && !c.getType().equalsIgnoreCase("json")) { + dictionaryFullNames.add(c.getName()); + } + dictionaryNames.add(c.getShortName()); + }); + + if (dictionaryFullNames.size() > 0) { + if (childObject.get(JsonEditorSchemaConstants.ENUM) != null) { + childObject.get(JsonEditorSchemaConstants.ENUM).getAsJsonArray().add(dictionaryFullNames); + } else { + childObject.add(JsonEditorSchemaConstants.ENUM, dictionaryFullNames); + } + // Add Enum titles for generated translated values during JSON instance + // generation + JsonObject enumTitles = new JsonObject(); + enumTitles.add(JsonEditorSchemaConstants.ENUM_TITLES, dictionaryNames); + if (childObject.get(JsonEditorSchemaConstants.OPTIONS) != null) { + childObject.get(JsonEditorSchemaConstants.OPTIONS).getAsJsonArray().add(enumTitles); + } else { + childObject.add(JsonEditorSchemaConstants.OPTIONS, enumTitles); + } + + } else { + if (childObject.get(JsonEditorSchemaConstants.ENUM) != null) { + childObject.get(JsonEditorSchemaConstants.ENUM).getAsJsonArray().add(dictionaryNames); + } else { + childObject.add(JsonEditorSchemaConstants.ENUM, dictionaryNames); + } + } + } + + private static void processDictionaryElements(String dictionaryReference, JsonObject childObject, + DictionaryService dictionaryService) { + String[] dictionaryKeyArray = + dictionaryReference.substring(dictionaryReference.indexOf(ToscaSchemaConstants.DICTIONARY) + 11, + dictionaryReference.length()).split("#"); + if (dictionaryKeyArray.length > 1) { + processComplexDictionaryElements(dictionaryKeyArray, childObject, dictionaryService); + } else { + processSimpleDictionaryElements(dictionaryKeyArray, childObject, dictionaryService); + } + } + + private static String getJsonType(String toscaType) { + String jsonType = null; + if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_INTEGER)) { + jsonType = JsonEditorSchemaConstants.TYPE_INTEGER; + } else if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_LIST)) { + jsonType = JsonEditorSchemaConstants.TYPE_ARRAY; + } else { + jsonType = JsonEditorSchemaConstants.TYPE_STRING; + } + return jsonType; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplate.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplate.java new file mode 100644 index 000000000..5c96f2c4a --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplate.java @@ -0,0 +1,223 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.templates; + +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.List; + +public class JsonTemplate { + + /** + * name parameter is used as "key", in the LinkedHashMap of Templates. + */ + private String name; + private List<JsonTemplateField> jsonTemplateFields; + + public JsonTemplate(String name) { + this.name = name; + this.jsonTemplateFields = new ArrayList<>(); + } + + public JsonTemplate(String name, List<JsonTemplateField> jsonTemplateFields) { + this.name = name; + this.jsonTemplateFields = jsonTemplateFields; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List<JsonTemplateField> getJsonTemplateFields() { + return jsonTemplateFields; + } + + public void setJsonTemplateFields(List<JsonTemplateField> jsonTemplateFields) { + this.jsonTemplateFields = jsonTemplateFields; + } + + /** + * Search in fields if fieldName exists. + * + * @param fieldName The field name + * @return Ture if it exists, false otherwise + */ + public boolean hasFields(String fieldName) { + for (JsonTemplateField jsonTemplateField : this.getJsonTemplateFields()) { + if (jsonTemplateField.getTitle().equals(fieldName)) { + return true; + } + } + return false; + } + + /** + * Get a specific Field. + * + * @param fieldName The field name + * @return THe Field found + */ + public JsonTemplateField getSpecificField(String fieldName) { + for (JsonTemplateField jsonTemplateField : this.getJsonTemplateFields()) { + if (jsonTemplateField.getTitle().equals(fieldName)) { + return jsonTemplateField; + } + } + return null; + } + + public void addField(JsonTemplateField jsonTemplateField) { + jsonTemplateFields.add(jsonTemplateField); + } + + public void removeField(JsonTemplateField jsonTemplateField) { + jsonTemplateFields.remove(jsonTemplateField); + } + + /** + * Enable or disable the visibility. + * + * @param nameField THe field name + * @param state True or false + */ + public void setVisibility(String nameField, boolean state) { + for (JsonTemplateField jsonTemplateField : this.jsonTemplateFields) { + if (jsonTemplateField.getTitle().equals(nameField)) { + jsonTemplateField.setVisible(state); + } + } + } + + /** + * This method defines if a field is static or not. + * + * @param nameField The name of the field + * @param state true or false + */ + public void setStatic(String nameField, boolean state) { + for (JsonTemplateField jsonTemplateField : this.jsonTemplateFields) { + if (jsonTemplateField.getTitle().equals(nameField)) { + jsonTemplateField.setStaticValue(state); + } + } + } + + /** + * This method updates the value of a specfic field. + * + * @param nameField The name of the field + * @param newValue The new value as Object + */ + public void updateValueField(String nameField, Object newValue) { + for (JsonTemplateField jsonTemplateField : this.jsonTemplateFields) { + if (jsonTemplateField.getTitle().equals(nameField)) { + jsonTemplateField.setValue(newValue); + } + } + } + + /** + * Compare two templates : size and their contents. + * + * @param jsonTemplate the template + * @return a boolean + */ + public boolean checkFields(JsonTemplate jsonTemplate) { + boolean duplicateFields = false; + if (jsonTemplate.getJsonTemplateFields().size() == this.getJsonTemplateFields().size()) { + int countMatchingFields = 0; + //loop each component of first + for (JsonTemplateField jsonTemplateFieldToCheck : jsonTemplate.getJsonTemplateFields()) { + for (JsonTemplateField jsonTemplateField : this.getJsonTemplateFields()) { + if (jsonTemplateFieldToCheck.compareWithField(jsonTemplateField)) { + countMatchingFields++; + } + } + } + + if (jsonTemplate.getJsonTemplateFields().size() == countMatchingFields) { + duplicateFields = true; + } + } + return duplicateFields; + } + + /** + * This method gets the specific field status. + * + * @param field The field name + * @return true or false + */ + public boolean fieldStaticStatus(String field) { + if (this.hasFields(field) && this.getSpecificField(field).getStaticValue().equals(true) + && this.getSpecificField(field).getValue() != null) { + return true; + } + return false; + } + + public boolean isVisible(String field) { + return this.getSpecificField(field).getVisible(); + } + + /** + * Set the value of a property of the Field in the json. + * + * @param jsonSchema The Json schema + * @param fieldName The Field name + * @param value The value + */ + public void setValue(JsonObject jsonSchema, String fieldName, String value) { + if (isVisible(fieldName)) { + if (fieldStaticStatus(fieldName)) { + String defaultValue = (String) this.getSpecificField(fieldName).getValue(); + jsonSchema.addProperty(fieldName, defaultValue); + } else { + jsonSchema.addProperty(fieldName, value); + } + } + } + + /** + * Inject a static value in the json. + * + * @param jsonSchema The json schema object + * @param fieldName The field name + */ + public void injectStaticValue(JsonObject jsonSchema, String fieldName) { + if (isVisible(fieldName)) { + JsonTemplateField toInject = this.getSpecificField(fieldName); + jsonSchema.addProperty(fieldName, (String) toInject.getValue()); + } + } + + @Override + public String toString() { + return " templateFields : " + jsonTemplateFields; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateField.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateField.java new file mode 100644 index 000000000..d9fd11de2 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateField.java @@ -0,0 +1,149 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.templates; + +public class JsonTemplateField { + private String title; + private Object value; + private Boolean visible; + private Boolean staticValue; + + public JsonTemplateField(String title) { + this.title = title; + } + + /** + * Constructor. + * + * @param title The title + * @param value The value + * @param visible visible or not + * @param staticValue The static value + */ + public JsonTemplateField(String title, Object value, Boolean visible, Boolean staticValue) { + this.title = title; + this.value = value; + this.visible = visible; + this.staticValue = staticValue; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public Boolean getVisible() { + return visible; + } + + public void setVisible(Boolean visible) { + this.visible = visible; + } + + public Boolean getStaticValue() { + return staticValue; + } + + public void setStaticValue(Boolean staticValue) { + this.staticValue = staticValue; + } + + public String toString() { + return title + " " + value + " " + visible + " " + staticValue; + } + + /** + * This method compares two fields. + * + * @param otherField Compare the current object with the one specified + * @return true if they are totally equals, false otherwise + */ + public boolean compareWithField(Object otherField) { + if (this == otherField) { + return true; + } + if (otherField == null || getClass() != otherField.getClass()) { + return false; + } + + JsonTemplateField jsonTemplateField = (JsonTemplateField) otherField; + + if (title != null ? !title.equals(jsonTemplateField.title) : jsonTemplateField.title != null) { + return false; + } + if (value != null ? !value.equals(jsonTemplateField.value) : jsonTemplateField.value != null) { + return false; + } + if (visible != null ? !visible.equals(jsonTemplateField.visible) : jsonTemplateField.visible != null) { + return false; + } + return staticValue != null ? staticValue.equals(jsonTemplateField.staticValue) : + jsonTemplateField.staticValue == null; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + + JsonTemplateField jsonTemplateField = (JsonTemplateField) object; + + return title != null ? title.equals(jsonTemplateField.title) : jsonTemplateField.title == null; + } + + @Override + public int hashCode() { + return title != null ? title.hashCode() : 0; + } + + /** + * This method test the entire equality. + * + * @param jsonTemplateField1 object one + * @param jsonTemplateField2 object two + * @return true if they are totally equals (all attributes, false otherwise + */ + public static boolean fieldsEquals(JsonTemplateField jsonTemplateField1, JsonTemplateField jsonTemplateField2) { + return (jsonTemplateField2.getTitle().equals(jsonTemplateField1.getTitle()) + && jsonTemplateField2.getValue().equals(jsonTemplateField1.getValue()) + && jsonTemplateField2.getVisible().equals(jsonTemplateField1.getVisible()) + && jsonTemplateField2.getStaticValue().equals(jsonTemplateField1.getStaticValue())); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateManager.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateManager.java new file mode 100644 index 000000000..1813d0786 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateManager.java @@ -0,0 +1,185 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.clds.tosca.update.templates; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.onap.policy.clamp.clds.tosca.update.UnknownComponentException; +import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement; +import org.onap.policy.clamp.clds.tosca.update.parser.ToscaConverterToJsonSchema; +import org.onap.policy.clamp.clds.tosca.update.parser.ToscaElementParser; +import org.onap.policy.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParser; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.loop.service.Service; + +public class JsonTemplateManager { + private LinkedHashMap<String, JsonTemplate> jsonSchemaTemplates; + private LinkedHashMap<String, ToscaElement> toscaElements; + + /** + * Constructor. + * + * @param toscaYamlContent Policy Tosca Yaml content as string + * @param nativeToscaDatatypes The tosca yaml with tosca native datatypes + * @param jsonSchemaTemplates template properties as string + */ + public JsonTemplateManager(String toscaYamlContent, String nativeToscaDatatypes, String jsonSchemaTemplates) { + if (toscaYamlContent != null && !toscaYamlContent.isEmpty()) { + this.toscaElements = ToscaElementParser.searchAllToscaElements(toscaYamlContent, nativeToscaDatatypes); + this.jsonSchemaTemplates = initializeTemplates(jsonSchemaTemplates); + } else { + toscaElements = null; + } + } + + //GETTERS & SETTERS + public LinkedHashMap<String, ToscaElement> getToscaElements() { + return toscaElements; + } + + public void setToscaElements(LinkedHashMap<String, ToscaElement> toscaElements) { + this.toscaElements = toscaElements; + } + + public LinkedHashMap<String, JsonTemplate> getJsonSchemaTemplates() { + return jsonSchemaTemplates; + } + + public void setJsonSchemaTemplates(LinkedHashMap<String, JsonTemplate> jsonSchemaTemplates) { + this.jsonSchemaTemplates = jsonSchemaTemplates; + } + + /** + * Add a template. + * + * @param name name + * @param jsonTemplateFields fields + */ + public void addTemplate(String name, List<JsonTemplateField> jsonTemplateFields) { + JsonTemplate jsonTemplate = new JsonTemplate(name, jsonTemplateFields); + //If it is true, the operation does not have any interest : + // replace OR put two different object with the same body + if (!jsonSchemaTemplates.containsKey(jsonTemplate.getName()) || !this.hasTemplate(jsonTemplate)) { + this.jsonSchemaTemplates.put(jsonTemplate.getName(), jsonTemplate); + } + } + + /** + * By name, find and remove a given template. + * + * @param nameTemplate name template + */ + public void removeTemplate(String nameTemplate) { + this.jsonSchemaTemplates.remove(nameTemplate); + } + + /** + * Update Template : adding with true flag, removing with false. + * + * @param nameTemplate name template + * @param jsonTemplateField field name + * @param operation operation + */ + public void updateTemplate(String nameTemplate, JsonTemplateField jsonTemplateField, Boolean operation) { + // Operation = true && field is not present => add Field + if (operation + && !this.jsonSchemaTemplates.get(nameTemplate).getJsonTemplateFields().contains(jsonTemplateField)) { + this.jsonSchemaTemplates.get(nameTemplate).addField(jsonTemplateField); + } else if (!operation + && this.jsonSchemaTemplates.get(nameTemplate).getJsonTemplateFields().contains(jsonTemplateField)) { + // Operation = false && field is present => remove Field + this.jsonSchemaTemplates.get(nameTemplate).removeField(jsonTemplateField); + } + } + + /** + * Check if the JSONTemplates have the same bodies. + * + * @param jsonTemplate template + * @return a boolean + */ + public boolean hasTemplate(JsonTemplate jsonTemplate) { + boolean duplicateTemplate = false; + Collection<String> templatesName = jsonSchemaTemplates.keySet(); + if (templatesName.contains(jsonTemplate.getName())) { + JsonTemplate existingJsonTemplate = jsonSchemaTemplates.get(jsonTemplate.getName()); + duplicateTemplate = existingJsonTemplate.checkFields(jsonTemplate); + } + return duplicateTemplate; + } + + /** + * For a given policy type, get a corresponding JsonObject from the tosca model. + * + * @param policyType The policy type in the tosca + * @param toscaMetadataParser The MetadataParser class that must be used if metadata section are encountered, + * if null they will be skipped + * @return an json object defining the equivalent json schema from the tosca for a given policy type + */ + public JsonObject getJsonSchemaForPolicyType(String policyType, ToscaMetadataParser toscaMetadataParser, + Service serviceModel) + throws UnknownComponentException { + ToscaConverterToJsonSchema + toscaConverterToJsonSchema = new ToscaConverterToJsonSchema(toscaElements, jsonSchemaTemplates, + toscaMetadataParser, serviceModel); + if (toscaConverterToJsonSchema.getToscaElement(policyType) == null) { + throw new UnknownComponentException(policyType); + } + return toscaConverterToJsonSchema.getJsonSchemaOfToscaElement(policyType); + } + + /** + * Create and complete several Templates from file.properties. + * + * @param jsonTemplates The template properties as String + * @return a map + */ + @SuppressWarnings("unused") + private LinkedHashMap<String, JsonTemplate> initializeTemplates(String jsonTemplates) { + + LinkedHashMap<String, JsonTemplate> generatedTemplates = new LinkedHashMap<>(); + JsonObject templates = JsonUtils.GSON.fromJson(jsonTemplates, JsonObject.class); + + for (Map.Entry<String, JsonElement> templateAsJson : templates.entrySet()) { + JsonTemplate jsonTemplate = new JsonTemplate(templateAsJson.getKey()); + JsonObject templateBody = (JsonObject) templateAsJson.getValue(); + for (Map.Entry<String, JsonElement> field : templateBody.entrySet()) { + String fieldName = field.getKey(); + JsonObject bodyFieldAsJson = (JsonObject) field.getValue(); + Object fieldValue = bodyFieldAsJson.get("defaultValue").getAsString(); + Boolean fieldVisible = bodyFieldAsJson.get("visible").getAsBoolean(); + Boolean fieldStatic = bodyFieldAsJson.get("static").getAsBoolean(); + JsonTemplateField + bodyJsonTemplateField = new JsonTemplateField(fieldName, fieldValue, fieldVisible, fieldStatic); + jsonTemplate.getJsonTemplateFields().add(bodyJsonTemplateField); + } + generatedTemplates.put(jsonTemplate.getName(), jsonTemplate); + } + return generatedTemplates; + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/ClampVersioning.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/ClampVersioning.java new file mode 100644 index 000000000..0890615d9 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/ClampVersioning.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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============================================ + * Modifications copyright (c) 2018 Nokia + * =================================================================== + * + */ + +package org.onap.policy.clamp.clds.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.InputStream; +import java.util.Properties; + +/** + * This class give a way to know the Clamp version easily, the version in that + * file is set by maven at build time. + * + */ +public class ClampVersioning { + private static final String RESOURCE_NAME = "clds-version.properties"; + private static final String CLDS_VERSION_PROPERTY = "clds.version"; + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ClampVersioning.class); + + private ClampVersioning() { + } + + /** + * Returns Clds version from properties. + * + * @return Clds version from properties + */ + public static String getCldsVersionFromProps() { + String cldsVersion = ""; + Properties props = new Properties(); + try (InputStream resourceStream = ResourceFileUtils.getResourceAsStream(RESOURCE_NAME)) { + props.load(resourceStream); + cldsVersion = props.getProperty(CLDS_VERSION_PROPERTY); + } catch (Exception ex) { + LOGGER.error("Exception caught during the " + CLDS_VERSION_PROPERTY + " property reading", ex); + } + return cldsVersion; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/JsonUtils.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/JsonUtils.java new file mode 100644 index 000000000..fd5079c47 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/JsonUtils.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018-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.policy.clamp.clds.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.time.Instant; +import org.onap.policy.clamp.authorization.SecureServicePermission; +import org.onap.policy.clamp.authorization.SecureServicePermissionDeserializer; +import org.onap.policy.clamp.dao.model.gson.converter.InstantDeserializer; +import org.onap.policy.clamp.dao.model.gson.converter.InstantSerializer; + +/** + * This class is used to access the GSON with restricted type access. + */ +public class JsonUtils { + + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(JsonUtils.class); + + public static final Gson GSON = new GsonBuilder().setPrettyPrinting() + .registerTypeAdapter(SecureServicePermission.class, new SecureServicePermissionDeserializer()).create(); + + public static final Gson GSON_JPA_MODEL = new GsonBuilder().setPrettyPrinting() + .registerTypeAdapter(Instant.class, new InstantSerializer()) + .registerTypeAdapter(Instant.class, new InstantDeserializer()).setPrettyPrinting() + .excludeFieldsWithoutExposeAnnotation().create(); + + private JsonUtils() { + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/LogMessages.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/LogMessages.java new file mode 100644 index 000000000..676206e0f --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/LogMessages.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.clamp.clds.util; + +import com.att.eelf.i18n.EELFResolvableErrorEnum; +import com.att.eelf.i18n.EELFResourceManager; + +public enum LogMessages implements EELFResolvableErrorEnum { + LOGSERVICE_HELLO_MESSAGE, LOGSERVICE_EMAIL_ERROR, LOGSERVICE_EMAIL_CLASS, LOGSERVICE_EMAIL_CLASS_NULL, + PROCESS_INSTANCE_ID; + + static { + EELFResourceManager.loadMessageBundle("logmessages"); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/LoggingUtils.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/LoggingUtils.java new file mode 100644 index 000000000..4145844a2 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/LoggingUtils.java @@ -0,0 +1,418 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2017-2018, 2021 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.clamp.clds.util; + +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.TimeZone; +import java.util.UUID; +import javax.net.ssl.HttpsURLConnection; +import javax.servlet.http.HttpServletRequest; +import javax.validation.constraints.NotNull; +import org.onap.policy.clamp.authorization.AuthorizationController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.slf4j.event.Level; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * This class handles the special info that appear in the log, like RequestID, + * time context, ... + */ +public class LoggingUtils { + + protected static final Logger logger = LoggerFactory.getLogger(LoggingUtils.class); + + private static final DateFormat DATE_FORMAT = createDateFormat(); + + private static final String DATE_FORMATTER_ISO = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + + /** + * String constant for messages <tt>ENTERING</tt>, <tt>EXITING</tt>, etc. + */ + private static final String EMPTY_MESSAGE = ""; + + /** + * Logger delegate. + */ + private final Logger mlogger; + + /** + * Automatic UUID, overrideable per adapter or per invocation. + */ + private static final UUID sInstanceUUID = UUID.randomUUID(); + + /** + * Constructor. + */ + public LoggingUtils(final Logger loggerP) { + this.mlogger = checkNotNull(loggerP); + } + + /** + * Set request related logging variables in thread local data via MDC. + * + * @param service Service Name of API (ex. "PUT template") + * @param partner Partner name (client or user invoking API) + */ + public static void setRequestContext(String service, String partner) { + MDC.put("RequestId", UUID.randomUUID().toString()); + MDC.put("ServiceName", service); + MDC.put("PartnerName", partner); + // Defaulting to HTTP/1.1 protocol + MDC.put("Protocol", "HTTP/1.1"); + try { + MDC.put("ServerFQDN", InetAddress.getLocalHost().getCanonicalHostName()); + MDC.put("ServerIPAddress", InetAddress.getLocalHost().getHostAddress()); + } catch (UnknownHostException e) { + logger.error("Failed to initiate setRequestContext", e); + } + } + + /** + * Set time related logging variables in thread local data via MDC. + * + * @param beginTimeStamp Start time + * @param endTimeStamp End time + */ + public static void setTimeContext(@NotNull Date beginTimeStamp, @NotNull Date endTimeStamp) { + MDC.put("EntryTimestamp", generateTimestampStr(beginTimeStamp)); + MDC.put("EndTimestamp", generateTimestampStr(endTimeStamp)); + MDC.put("ElapsedTime", String.valueOf(endTimeStamp.getTime() - beginTimeStamp.getTime())); + } + + /** + * Set response related logging variables in thread local data via MDC. + * + * @param code Response code ("0" indicates success) + * @param description Response description + * @param className class name of invoking class + */ + public static void setResponseContext(String code, String description, String className) { + MDC.put("ResponseCode", code); + MDC.put("StatusCode", "0".equals(code) ? "COMPLETE" : "ERROR"); + MDC.put("ResponseDescription", description != null ? description : ""); + MDC.put("ClassName", className != null ? className : ""); + } + + /** + * Set target related logging variables in thread local data via MDC. + * + * @param targetEntity Target entity (an external/sub component, for ex. "sdc") + * @param targetServiceName Target service name (name of API invoked on target) + */ + public static void setTargetContext(String targetEntity, String targetServiceName) { + MDC.put("TargetEntity", targetEntity != null ? targetEntity : ""); + MDC.put("TargetServiceName", targetServiceName != null ? targetServiceName : ""); + } + + /** + * Set error related logging variables in thread local data via MDC. + * + * @param code Error code + * @param description Error description + */ + public static void setErrorContext(String code, String description) { + MDC.put("ErrorCode", code); + MDC.put("ErrorDescription", description != null ? description : ""); + } + + private static String generateTimestampStr(Date timeStamp) { + return DATE_FORMAT.format(timeStamp); + } + + /** + * Get a previously stored RequestID for the thread local data via MDC. If + * one was not previously stored, generate one, store it, and return that + * one. + * + * @return A string with the request ID + */ + public static String getRequestId() { + String requestId = MDC.get(OnapLogConstants.Mdcs.REQUEST_ID); + if (requestId == null || requestId.isEmpty()) { + requestId = UUID.randomUUID().toString(); + MDC.put(OnapLogConstants.Mdcs.REQUEST_ID, requestId); + } + return requestId; + } + + private static DateFormat createDateFormat() { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return dateFormat; + } + + /* ******************************************************************************************* + * Method for ONAP Application Logging Specification v1.2 + * *******************************************************************************************/ + + /** + * Report <tt>ENTERING</tt> marker. + * + * @param request non-null incoming request (wrapper) + * @param serviceName service name + */ + public void entering(HttpServletRequest request, String serviceName) { + // MDC.clear(); + checkNotNull(request); + // Extract MDC values from standard HTTP headers. + final String requestId = + defaultToUuid(request.getHeader(OnapLogConstants.Headers.REQUEST_ID)); + final String invocationId = + defaultToUuid(request.getHeader(OnapLogConstants.Headers.INVOCATION_ID)); + final String partnerName = + defaultToEmpty(request.getHeader(OnapLogConstants.Headers.PARTNER_NAME)); + + // Default the partner name to the user name used to login to clamp + if (partnerName.equalsIgnoreCase(EMPTY_MESSAGE)) { + MDC.put(OnapLogConstants.Mdcs.PARTNER_NAME, + AuthorizationController.getPrincipalName(SecurityContextHolder.getContext())); + } + + // Set standard MDCs. Override this entire method if you want to set + // others, OR set them BEFORE or AFTER the invocation of #entering, + // depending on where you need them to appear, OR extend the + // ServiceDescriptor to add them. + MDC.put(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP, ZonedDateTime.now(ZoneOffset.UTC) + .format(DateTimeFormatter.ofPattern(DATE_FORMATTER_ISO))); + MDC.put(OnapLogConstants.Mdcs.REQUEST_ID, requestId); + MDC.put(OnapLogConstants.Mdcs.INVOCATION_ID, invocationId); + MDC.put(OnapLogConstants.Mdcs.CLIENT_IP_ADDRESS, defaultToEmpty(request.getRemoteAddr())); + MDC.put(OnapLogConstants.Mdcs.SERVER_FQDN, defaultToEmpty(request.getServerName())); + MDC.put(OnapLogConstants.Mdcs.INSTANCE_UUID, defaultToEmpty(sInstanceUUID)); + + // Default the service name to the requestURI, in the event that + // no value has been provided. + if (serviceName == null || serviceName.equalsIgnoreCase(EMPTY_MESSAGE)) { + MDC.put(OnapLogConstants.Mdcs.SERVICE_NAME, request.getRequestURI()); + } else { + MDC.put(OnapLogConstants.Mdcs.SERVICE_NAME, serviceName); + } + + // Set the Response Status code to in progress + MDC.put(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE, + OnapLogConstants.ResponseStatus.INPROGRESS.toString()); + setElapsedTime(); + + this.mlogger.info(OnapLogConstants.Markers.ENTRY, "Entering"); + } + + /** + * Report <tt>EXITING</tt> marker. + * + * @param code response code + * @param description response description + * @param severity response severity + * @param status response status code + */ + public void exiting(int code, String description, Level severity, + OnapLogConstants.ResponseStatus status) { + try { + + MDC.put(OnapLogConstants.Mdcs.RESPONSE_CODE, defaultToEmpty(code)); + MDC.put(OnapLogConstants.Mdcs.RESPONSE_DESCRIPTION, defaultToEmpty(description)); + MDC.put(OnapLogConstants.Mdcs.RESPONSE_SEVERITY, defaultToEmpty(severity)); + MDC.put(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE, defaultToEmpty(status)); + + setElapsedTime(); + this.mlogger.info(OnapLogConstants.Markers.EXIT, "Exiting"); + } finally { + MDC.clear(); + } + } + + private void setElapsedTime() { + String entryTimestamp = MDC.get(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP); + MDC.put(OnapLogConstants.Mdcs.ELAPSED_TIME, String.valueOf(ChronoUnit.MILLIS + .between(ZonedDateTime.parse(entryTimestamp != null ? entryTimestamp : ZonedDateTime.now(ZoneOffset.UTC) + .format(DateTimeFormatter.ofPattern(DATE_FORMATTER_ISO)), + DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneOffset.UTC)), ZonedDateTime.now(ZoneOffset.UTC)))); + } + + /** + * Get the property value. + * + * @param name The name of the property + * @return The value of the property + */ + public String getProperties(String name) { + return MDC.get(name); + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker, + * setting standard ONAP logging headers automatically. + * + * @param con The HTTP url connection + * @param targetEntity The target entity + * @param targetServiceName The target service name + * @return The HTTP url connection + */ + public HttpURLConnection invoke(final HttpURLConnection con, String targetEntity, + String targetServiceName) { + return this.invokeGeneric(con, targetEntity, targetServiceName); + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker, + * setting standard ONAP logging headers automatically. + * + * @param targetEntity The target entity + * @param targetServiceName The target service name + */ + public void invoke(String targetEntity, String targetServiceName) { + final String invocationId = UUID.randomUUID().toString(); + + invokeContext(targetEntity, targetServiceName, invocationId); + + // Log INVOKE*, with the invocationID as the message body. + // (We didn't really want this kind of behavior in the standard, + // but is it worse than new, single-message MDC?) + this.mlogger.info(OnapLogConstants.Markers.INVOKE, "INVOKE"); + this.mlogger.info(OnapLogConstants.Markers.INVOKE_SYNCHRONOUS + "{" + invocationId + "}"); + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker, + * setting standard ONAP logging headers automatically. + * + * @param con The HTTPS url connection + * @param targetEntity The target entity + * @param targetServiceName The target service name + * @return The HTTPS url connection + */ + public HttpsURLConnection invokeHttps(final HttpsURLConnection con, String targetEntity, + String targetServiceName) { + return this.invokeGeneric(con, targetEntity, targetServiceName); + } + + /** + * Report pending invocation with <tt>INVOKE-RETURN</tt> marker. + */ + public void invokeReturn() { + MDC.put(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE, + OnapLogConstants.ResponseStatus.COMPLETE.toString()); + // Add the Invoke-return marker and clear the needed MDC + this.mlogger.info(OnapLogConstants.Markers.INVOKE_RETURN, "INVOKE-RETURN"); + invokeReturnContext(); + } + + /** + * Dependency-free nullcheck. + * + * @param in to be checked + * @param <T> argument (and return) type + * @return input arg + */ + private static <T> T checkNotNull(final T in) { + if (in == null) { + throw new NullPointerException(); + } + return in; + } + + /** + * Dependency-free string default. + * + * @param in to be filtered + * @return input string or null + */ + private static String defaultToEmpty(final Object in) { + if (in == null) { + return ""; + } + return in.toString(); + } + + /** + * Dependency-free string default. + * + * @param in to be filtered + * @return input string or null + */ + private static String defaultToUuid(final String in) { + if (in == null) { + return UUID.randomUUID().toString(); + } + return in; + } + + /** + * Set target related logging variables in thread local data via MDC. + * + * @param targetEntity Target entity (an external/sub component, for ex. "sdc") + * @param targetServiceName Target service name (name of API invoked on target) + * @param invocationId The invocation ID + */ + private void invokeContext(String targetEntity, String targetServiceName, String invocationId) { + MDC.put(OnapLogConstants.Mdcs.TARGET_ENTITY, defaultToEmpty(targetEntity)); + MDC.put(OnapLogConstants.Mdcs.TARGET_SERVICE_NAME, defaultToEmpty(targetServiceName)); + MDC.put(OnapLogConstants.Mdcs.INVOCATIONID_OUT, invocationId); + MDC.put(OnapLogConstants.Mdcs.INVOKE_TIMESTAMP, ZonedDateTime.now(ZoneOffset.UTC) + .format(DateTimeFormatter.ofPattern(DATE_FORMATTER_ISO))); + } + + /** + * Clear target related logging variables in thread local data via MDC. + */ + private void invokeReturnContext() { + MDC.remove(OnapLogConstants.Mdcs.TARGET_ENTITY); + MDC.remove(OnapLogConstants.Mdcs.TARGET_SERVICE_NAME); + MDC.remove(OnapLogConstants.Mdcs.INVOCATIONID_OUT); + MDC.remove(OnapLogConstants.Mdcs.INVOKE_TIMESTAMP); + MDC.remove(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE); + } + + private <T extends URLConnection> T invokeGeneric(final T con, String targetEntity, + String targetServiceName) { + final String invocationId = UUID.randomUUID().toString(); + + // Set standard HTTP headers on (southbound request) builder. + con.setRequestProperty(OnapLogConstants.Headers.REQUEST_ID, + defaultToEmpty(MDC.get(OnapLogConstants.Mdcs.REQUEST_ID))); + con.setRequestProperty(OnapLogConstants.Headers.INVOCATION_ID, invocationId); + con.setRequestProperty(OnapLogConstants.Headers.PARTNER_NAME, + defaultToEmpty(MDC.get(OnapLogConstants.Mdcs.PARTNER_NAME))); + + invokeContext(targetEntity, targetServiceName, invocationId); + + // Log INVOKE*, with the invocationID as the message body. + // (We didn't really want this kind of behavior in the standard, + // but is it worse than new, single-message MDC?) + this.mlogger.info(OnapLogConstants.Markers.INVOKE, ""); + this.mlogger.info(OnapLogConstants.Markers.INVOKE_SYNCHRONOUS + "{" + invocationId + "}"); + return con; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/OnapLogConstants.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/OnapLogConstants.java new file mode 100644 index 000000000..78b16f1a0 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/OnapLogConstants.java @@ -0,0 +1,304 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.clds.util; + +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +/** + * Constants for standard ONAP headers, MDCs, etc. + */ +public final class OnapLogConstants { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constructors. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private OnapLogConstants() { + throw new UnsupportedOperationException(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Inner classes. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Marker constants. + */ + public static final class Markers { + + /** Marker reporting invocation. */ + public static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); + + /** Marker reporting invocation return. */ + public static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN"); + + /** Marker reporting synchronous invocation. */ + public static final Marker INVOKE_SYNCHRONOUS = build("INVOKE", "SYNCHRONOUS"); + + /** Marker reporting asynchronous invocation. */ + public static final Marker INVOKE_ASYNCHRONOUS = build("INVOKE", "ASYNCHRONOUS"); + + /** Marker reporting entry into a component. */ + public static final Marker ENTRY = MarkerFactory.getMarker("ENTRY"); + + /** Marker reporting exit from a component. */ + public static final Marker EXIT = MarkerFactory.getMarker("EXIT"); + + /** + * Build nested, detached marker. + * + * @param m1 top token. + * @param m2 sub-token. + * @return detached Marker. + */ + private static Marker build(final String m1, final String m2) { + final Marker marker = MarkerFactory.getDetachedMarker(m1); + marker.add(MarkerFactory.getDetachedMarker(m2)); + return marker; + } + + /** + * Hide and forbid construction. + */ + private Markers() { + throw new UnsupportedOperationException(); + } + } + + /** + * MDC name constants. + */ + public static final class Mdcs { + + // Tracing. //////////////////////////////////////////////////////////// + + /** MDC correlating messages for an invocation. */ + public static final String INVOCATION_ID = "InvocationID"; + + public static final String SERVER_INVOCATION_ID = "ServerInvocationId"; + + public static final String CLIENT_INVOCATION_ID = "ClientInvocationId"; + + /** MDC correlating messages for a logical transaction. */ + public static final String REQUEST_ID = "RequestID"; + + /** MDC recording calling partner name. */ + public static final String PARTNER_NAME = "PartnerName"; + + /** MDC recording current service. */ + public static final String SERVICE_NAME = "ServiceName"; + + /** MDC recording target service. */ + public static final String TARGET_SERVICE_NAME = "TargetServiceName"; + + /** MDC recording InvocationID Out. */ + public static final String INVOCATIONID_OUT = "InvocationIDOut"; + + /** MDC recording target entity. */ + public static final String TARGET_ENTITY = "TargetEntity"; + + /** MDC recording target element. */ + public static final String TARGET_ELEMENT = "TargetElement"; + + /** MDC recording current service instance id. */ + public static final String SERVICE_INSTANCE_ID = "ServiceInstanceID"; + + /** MDC recording current instance id. */ + public static final String INSTANCE_UUID = "InstanceID"; + + // Network. //////////////////////////////////////////////////////////// + + /** MDC recording caller address. */ + public static final String CLIENT_IP_ADDRESS = "ClientIPAddress"; + + /** MDC recording server IP address. */ + public static final String SERVER_IP_ADDRESS = "ServerIPAddress"; + + /** MDC recording server FQDN. */ + public static final String SERVER_FQDN = "ServerFQDN"; + + /** MDC recording virtual server name. */ + public static final String VIRTUAL_SERVER_NAME = "VirtualServerName"; + + /** MDC recording context name. */ + public static final String CONTEXT_NAME = "ContextName"; + + /** + * MDC recording timestamp at the start of the current request, + * with the same scope as {@link #REQUEST_ID}. + * + * <p> + * Open issues: + * <ul> + * <ul> + * Easily confused with {@link #INVOKE_TIMESTAMP}. + * </ul> + * <ul> + * No mechanism for propagation between components, e.g. via HTTP headers. + * </ul> + * <ul> + * Whatever mechanism we define, it's going to be costly. + * </ul> + * </ul> + * </p> + */ + public static final String ENTRY_TIMESTAMP = "EntryTimestamp"; + + /** MDC recording timestamp at the start of the current invocation. */ + public static final String INVOKE_TIMESTAMP = "InvokeTimestamp"; + + /** MDC recording elapsed time. */ + public static final String ELAPSED_TIME = "ElapsedTime"; + + /** MDC recording log timestamp. */ + public static final String LOG_TIMESTAMP = "LogTimestamp"; + + // Outcomes. /////////////////////////////////////////////////////////// + + /** MDC reporting outcome code. */ + public static final String RESPONSE_CODE = "ResponseCode"; + + /** MDC reporting outcome description. */ + public static final String RESPONSE_DESCRIPTION = "ResponseDesc"; + + /** MDC reporting severity. */ + public static final String RESPONSE_SEVERITY = "Severity"; + + /** MDC reporting response status code. */ + public static final String RESPONSE_STATUS_CODE = "StatusCode"; + + /** MDC recording error code. */ + public static final String ERROR_CODE = "ErrorCode"; + + /** MDC recording error description. */ + public static final String ERROR_DESC = "ErrorDesc"; + + // Unsorted. /////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private Mdcs() { + throw new UnsupportedOperationException(); + } + } + + /** + * Header name constants. + */ + public static final class Headers { + + /** HTTP <tt>X-ONAP-RequestID</tt> header. */ + public static final String REQUEST_ID = "X-ONAP-RequestID"; + + /** HTTP <tt>X-InvocationID</tt> header. */ + public static final String INVOCATION_ID = "X-ONAP-InvocationID"; + + /** HTTP <tt>X-ONAP-PartnerName</tt> header. */ + public static final String PARTNER_NAME = "X-ONAP-PartnerName"; + + /** + * Hide and forbid construction. + */ + private Headers() { + throw new UnsupportedOperationException(); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Enums. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Response success or not, for setting <tt>StatusCode</tt>. + */ + public enum ResponseStatus { + + /** Success. */ + COMPLETE, + + /** Not. */ + ERROR, + + /** In Progress. */ + INPROGRESS + } + + /** + * Synchronous or asynchronous execution, for setting invocation marker. + */ + public enum InvocationMode { + + /** Synchronous, blocking. */ + SYNCHRONOUS("SYNCHRONOUS", Markers.INVOKE_SYNCHRONOUS), + + /** Asynchronous, non-blocking. */ + ASYNCHRONOUS("ASYNCHRONOUS", Markers.INVOKE_ASYNCHRONOUS); + + /** Enum value. */ + private String enumValue; + + /** Corresponding marker. */ + private Marker marker; + + /** + * Construct enum. + * + * @param enumValue enum value. + * @param marker corresponding Marker. + */ + InvocationMode(final String enumValue, final Marker marker) { + this.enumValue = enumValue; + this.marker = marker; + } + + /** + * Get Marker for enum. + * + * @return Marker. + */ + public Marker getMarker() { + return this.marker; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return this.enumValue; + } + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/ResourceFileUtils.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/ResourceFileUtils.java new file mode 100644 index 000000000..d6184c656 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/ResourceFileUtils.java @@ -0,0 +1,89 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2017, 2021 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.clamp.clds.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Scanner; + +/** + * Utility methods supporting resources accesses. + */ +public final class ResourceFileUtils { + + /** + * getResourceAsStram supports the "file:" prefix as they use URL. + * So here we want to eliminate classpath: prefix, so that this class can get + * files from jar resource or file system. + */ + + private static final String CLASSPATH_PREFIX = "classpath:"; + + /** + * Private constructor to avoid creating instances of util class. + */ + private ResourceFileUtils() { + } + + /** + * Method to access a file from the jar resource folder or file system. + * Give the prefix "classpath:" so that it accesses the jar resource folder (default case) + * or the prefix "file:" so that it accesses the file system. + * + * @param fileName The path of the resource (no prefix it will be a classpath access, + * "classpath:/myfilename" or "file:/myfilename") + * @return The file as inputStream + */ + public static InputStream getResourceAsStream(String fileName) { + InputStream is = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(fileName.replaceFirst("^" + CLASSPATH_PREFIX, "")); + if (is == null) { + throw new IllegalArgumentException("Unable to find resource: " + fileName); + } + return is; + } + + /** + * Method to access a resource file as a string. + * Give the prefix "classpath:" so that it accesses the jar resource folder (default case) + * or the prefix "file:" so that it accesses the file system. + * + * @param fileName The path of the resource (no prefix it will be a classpath access, + * "classpath:/myfilename" or "file:/myfilename") + * @return The file as String + * @throws IOException In case of failure to find the file. + */ + public static String getResourceAsString(String fileName) throws IOException { + try (InputStream is = getResourceAsStream(fileName)) { + return streamToString(is); + } + } + + private static String streamToString(InputStream inputStream) { + try (Scanner scanner = new Scanner(inputStream)) { + Scanner delimitedScanner = scanner.useDelimiter("\\A"); + return delimitedScanner.hasNext() ? delimitedScanner.next() : ""; + } + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/configuration/ClampGsonDataFormat.java b/runtime/src/main/java/org/onap/policy/clamp/configuration/ClampGsonDataFormat.java new file mode 100644 index 000000000..6479cf767 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/configuration/ClampGsonDataFormat.java @@ -0,0 +1,173 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019, 2021 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.clamp.configuration; + +import com.google.gson.Gson; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import org.apache.camel.Exchange; +import org.apache.camel.spi.DataFormat; +import org.apache.camel.spi.DataFormatName; +import org.apache.camel.support.service.ServiceSupport; +import org.apache.camel.util.IOHelper; +import org.apache.commons.io.IOUtils; +import org.onap.policy.clamp.clds.util.JsonUtils; + +public class ClampGsonDataFormat extends ServiceSupport implements DataFormat, DataFormatName { + private Gson gson; + private Class<?> unmarshalType; + private Type unmarshalGenericType; + private boolean contentTypeHeader = true; + + public ClampGsonDataFormat() { + this(Object.class); + } + + /** + * Use the default Gson {@link Gson} and with a custom unmarshal type. + * + * @param unmarshalType the custom unmarshal type + */ + public ClampGsonDataFormat(Class<?> unmarshalType) { + this(null, unmarshalType); + } + + /** + * Use a custom Gson mapper and and unmarshal type. + * + * @param gson the custom mapper + * @param unmarshalType the custom unmarshal type + */ + public ClampGsonDataFormat(Gson gson, Class<?> unmarshalType) { + this.gson = gson; + this.unmarshalType = unmarshalType; + } + + /** + * Use the default Gson {@link Gson} and with a custom unmarshal generic type. + * + * @param unmarshalGenericType the custom unmarshal generic type + */ + public ClampGsonDataFormat(Type unmarshalGenericType) { + this(null, unmarshalGenericType); + } + + /** + * Use a custom Gson mapper and and unmarshal token type. + * + * @param gson the custom mapper + * @param unmarshalGenericType the custom unmarshal generic type + */ + public ClampGsonDataFormat(Gson gson, Type unmarshalGenericType) { + this.gson = gson; + this.unmarshalGenericType = unmarshalGenericType; + } + + @Override + public String getDataFormatName() { + return "clamp-gson"; + } + + @Override + public void marshal(final Exchange exchange, final Object graph, final OutputStream stream) throws Exception { + try (final OutputStreamWriter osw = new OutputStreamWriter(stream, StandardCharsets.UTF_8); + final BufferedWriter writer = IOHelper.buffered(osw)) { + gson.toJson(graph, writer); + } + + if (contentTypeHeader) { + if (exchange.hasOut()) { + exchange.getOut().setHeader(Exchange.CONTENT_TYPE, "application/json"); + } else { + exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json"); + } + } + } + + @Override + public Object unmarshal(final Exchange exchange, final InputStream stream) throws Exception { + try (final InputStreamReader isr = new InputStreamReader(stream, StandardCharsets.UTF_8); + final BufferedReader reader = IOHelper.buffered(isr)) { + if (unmarshalType.equals(String.class)) { + return IOUtils.toString(reader); + } else if (unmarshalGenericType == null) { + return gson.fromJson(reader, unmarshalType); + } else { + return gson.fromJson(reader, unmarshalGenericType); + } + } + } + + @Override + protected void doStart() throws Exception { + if (gson == null) { + gson = JsonUtils.GSON_JPA_MODEL; + } + } + + @Override + protected void doStop() throws Exception { + // noop + } + + // Properties + // ------------------------------------------------------------------------- + + public Class<?> getUnmarshalType() { + return this.unmarshalType; + } + + public void setUnmarshalType(Class<?> unmarshalType) { + this.unmarshalType = unmarshalType; + } + + public Type getUnmarshalGenericType() { + return this.unmarshalGenericType; + } + + public void setUnmarshalGenericType(Type unmarshalGenericType) { + this.unmarshalGenericType = unmarshalGenericType; + } + + public boolean isContentTypeHeader() { + return contentTypeHeader; + } + + /** + * If enabled then Gson will set the Content-Type header to + * <tt>application/json</tt> when marshalling. + */ + public void setContentTypeHeader(boolean contentTypeHeader) { + this.contentTypeHeader = contentTypeHeader; + } + + public Gson getGson() { + return this.gson; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantDeserializer.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantDeserializer.java new file mode 100644 index 000000000..db024e07a --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantDeserializer.java @@ -0,0 +1,46 @@ +/*- + * ============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.policy.clamp.dao.model.gson.converter; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import java.lang.reflect.Type; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Locale; + +public class InstantDeserializer implements JsonDeserializer<Instant> { + + DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.US) + .withZone(ZoneId.systemDefault()); + + @Override + public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { + return Instant.parse(json.getAsString()); + + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantSerializer.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantSerializer.java new file mode 100644 index 000000000..7208a472c --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantSerializer.java @@ -0,0 +1,40 @@ +/*- + * ============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.policy.clamp.dao.model.gson.converter; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; +import java.time.Instant; +import java.time.format.DateTimeFormatter; + +public class InstantSerializer implements JsonSerializer<Instant> { + + @Override + public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(DateTimeFormatter.ISO_INSTANT.format(src)); + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java new file mode 100644 index 000000000..d3aaa32a9 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java @@ -0,0 +1,108 @@ +/*- + * ============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.policy.clamp.dao.model.jsontype; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.BasicBinder; +import org.hibernate.type.descriptor.sql.BasicExtractor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +public class JsonStringSqlTypeDescriptor implements SqlTypeDescriptor { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = 1103168570216921981L; + + public static final JsonStringSqlTypeDescriptor INSTANCE = new JsonStringSqlTypeDescriptor(); + + @Override + public int getSqlType() { + return Types.OTHER; + } + + @Override + public boolean canBeRemapped() { + return true; + } + + @Override + public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) { + return new BasicBinder<X>(javaTypeDescriptor, this) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + st.setString(index, javaTypeDescriptor.unwrap(value, String.class, options)); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + st.setString(name, javaTypeDescriptor.unwrap(value, String.class, options)); + } + }; + } + + @Override + public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) { + return new BasicExtractor<X>(javaTypeDescriptor, this) { + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return javaTypeDescriptor.wrap(extractJson(rs, name), options); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return javaTypeDescriptor.wrap(extractJson(statement, index), options); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap(extractJson(statement, name), options); + } + }; + } + + protected Object extractJson(ResultSet rs, String name) throws SQLException { + return rs.getObject(name); + } + + protected Object extractJson(CallableStatement statement, int index) throws SQLException { + return statement.getObject(index); + } + + protected Object extractJson(CallableStatement statement, String name) throws SQLException { + return statement.getObject(name); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonTypeDescriptor.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonTypeDescriptor.java new file mode 100644 index 000000000..ed8464b14 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonTypeDescriptor.java @@ -0,0 +1,105 @@ +/*- + * ============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.policy.clamp.dao.model.jsontype; + +import com.google.gson.JsonObject; +import java.io.Serializable; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; +import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan; +import org.onap.policy.clamp.clds.util.JsonUtils; + +public class JsonTypeDescriptor extends AbstractTypeDescriptor<JsonObject> { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -3439698221196089003L; + + public static final JsonTypeDescriptor INSTANCE = new JsonTypeDescriptor(); + + /** + * Creates an instance of JsonTypeDescriptor. + */ + public JsonTypeDescriptor() { + super(JsonObject.class, new ImmutableMutabilityPlan<JsonObject>() { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = 1169396106518110214L; + + @Override + public Serializable disassemble(JsonObject value) { + return JsonUtils.GSON_JPA_MODEL.toJson(value); + } + + @Override + public JsonObject assemble(Serializable cached) { + return JsonUtils.GSON_JPA_MODEL.fromJson((String) cached, JsonObject.class); + } + + }); + } + + @Override + public String toString(JsonObject value) { + return JsonUtils.GSON_JPA_MODEL.toJson(value); + } + + @Override + public JsonObject fromString(String string) { + return JsonUtils.GSON_JPA_MODEL.fromJson(string, JsonObject.class); + } + + @Override + public <X> X unwrap(JsonObject value, Class<X> type, WrapperOptions options) { + if (value == null) { + return null; + } + + if (String.class.isAssignableFrom(type)) { + return (X) toString(value); + } + + if (JsonObject.class.isAssignableFrom(type)) { + return (X) JsonUtils.GSON_JPA_MODEL.toJson(toString(value)); + } + throw unknownUnwrap(type); + } + + @Override + public <X> JsonObject wrap(X value, WrapperOptions options) { + if (value == null) { + return null; + } + + if (String.class.isInstance(value)) { + return JsonUtils.GSON_JPA_MODEL.fromJson((String) value, JsonObject.class); + } + + throw unknownWrap(value.getClass()); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/StringJsonUserType.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/StringJsonUserType.java new file mode 100644 index 000000000..4a7b65bb4 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/StringJsonUserType.java @@ -0,0 +1,51 @@ +/*- + * ============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.policy.clamp.dao.model.jsontype; + +import com.google.gson.JsonObject; +import org.hibernate.type.AbstractSingleColumnStandardBasicType; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +public class StringJsonUserType extends AbstractSingleColumnStandardBasicType<JsonObject> { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -7929809808079327767L; + + public StringJsonUserType() { + super(JsonStringSqlTypeDescriptor.INSTANCE, JsonTypeDescriptor.INSTANCE); + } + + public StringJsonUserType(SqlTypeDescriptor sqlTypeDescriptor, JavaTypeDescriptor<JsonObject> javaTypeDescriptor) { + super(sqlTypeDescriptor, javaTypeDescriptor); + } + + @Override + public String getName() { + return "json"; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/flow/log/FlowLogOperation.java b/runtime/src/main/java/org/onap/policy/clamp/flow/log/FlowLogOperation.java new file mode 100644 index 000000000..d54b23b21 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/flow/log/FlowLogOperation.java @@ -0,0 +1,101 @@ +/*- + * ============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.policy.clamp.flow.log; + +import javax.servlet.http.HttpServletRequest; +import org.apache.camel.Exchange; +import org.onap.policy.clamp.clds.util.LoggingUtils; +import org.onap.policy.clamp.clds.util.OnapLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * The Flow log operations. + */ +@Component +public class FlowLogOperation { + + protected static final Logger logger = LoggerFactory.getLogger(FlowLogOperation.class); + private LoggingUtils util = new LoggingUtils(logger); + + @Autowired + private HttpServletRequest request; + + /** + * Generate the entry log. + * + * @param serviceDesc + * The service description the loop name + */ + public void startLog(Exchange exchange, String serviceDesc) { + util.entering(request, serviceDesc); + exchange.setProperty(OnapLogConstants.Headers.REQUEST_ID, + util.getProperties(OnapLogConstants.Mdcs.REQUEST_ID)); + exchange.setProperty(OnapLogConstants.Headers.INVOCATION_ID, + util.getProperties(OnapLogConstants.Mdcs.INVOCATION_ID)); + exchange.setProperty(OnapLogConstants.Headers.PARTNER_NAME, + util.getProperties(OnapLogConstants.Mdcs.PARTNER_NAME)); + } + + /** + * Generate the exiting log. + */ + public void endLog() { + util.exiting(HttpStatus.OK.value(), "Successful", Level.INFO, + OnapLogConstants.ResponseStatus.COMPLETE); + } + + /** + * Generate the error exiting log. + */ + public void errorLog() { + util.exiting(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Failed", Level.INFO, + OnapLogConstants.ResponseStatus.ERROR); + } + + /** + * Generate the error exiting log. + */ + public void httpErrorLog() { + + } + + /** + * Generate the invoke log. + */ + public void invokeLog(String targetEntity, String targetServiceName) { + util.invoke(targetEntity, targetServiceName); + } + + /** + * Generate the invoke return marker. + */ + public void invokeReturnLog() { + util.invokeReturn(); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/CsarInstaller.java b/runtime/src/main/java/org/onap/policy/clamp/loop/CsarInstaller.java new file mode 100644 index 000000000..f46f4227b --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/CsarInstaller.java @@ -0,0 +1,209 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019, 2021 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.clamp.loop; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import org.json.simple.parser.ParseException; +import org.onap.policy.clamp.clds.client.DcaeInventoryServices; +import org.onap.policy.clamp.clds.exception.sdc.controller.BlueprintParserException; +import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException; +import org.onap.policy.clamp.clds.model.dcae.DcaeInventoryResponse; +import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintArtifact; +import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintMicroService; +import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintParser; +import org.onap.policy.clamp.clds.sdc.controller.installer.ChainGenerator; +import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler; +import org.onap.policy.clamp.loop.cds.CdsDataInstaller; +import org.onap.policy.clamp.loop.service.CsarServiceInstaller; +import org.onap.policy.clamp.loop.service.Service; +import org.onap.policy.clamp.loop.template.LoopElementModel; +import org.onap.policy.clamp.loop.template.LoopTemplate; +import org.onap.policy.clamp.loop.template.LoopTemplatesRepository; +import org.onap.policy.clamp.loop.template.PolicyModel; +import org.onap.policy.clamp.loop.template.PolicyModelsRepository; +import org.onap.policy.clamp.policy.PolicyEngineServices; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +/** + * This class will be instantiated by spring config, and used by Sdc Controller. + * There is no state kept by the bean. It's used to deploy the csar/notification + * received from SDC in DB. + */ +@Component +@Qualifier("csarInstaller") +public class CsarInstaller { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(CsarInstaller.class); + + @Autowired + private PolicyModelsRepository policyModelsRepository; + + @Autowired + private LoopTemplatesRepository loopTemplatesRepository; + + @Autowired + private ChainGenerator chainGenerator; + + @Autowired + private DcaeInventoryServices dcaeInventoryService; + + @Autowired + private CsarServiceInstaller csarServiceInstaller; + + @Autowired + private CdsDataInstaller cdsDataInstaller; + + @Autowired + private PolicyEngineServices policyEngineServices; + + /** + * Verify whether Csar is deployed. + * + * @param csar The Csar Handler + * @return The flag indicating whether Csar is deployed + * @throws SdcArtifactInstallerException The SdcArtifactInstallerException + */ + public boolean isCsarAlreadyDeployed(CsarHandler csar) throws SdcArtifactInstallerException { + boolean alreadyInstalled = csarServiceInstaller.isServiceAlreadyDeployed(csar); + + for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) { + alreadyInstalled = alreadyInstalled + && loopTemplatesRepository.existsById(LoopTemplate.generateLoopTemplateName( + csar.getSdcNotification().getServiceName(), csar.getSdcNotification().getServiceVersion(), + blueprint.getValue().getResourceAttached().getResourceInstanceName(), + blueprint.getValue().getBlueprintArtifactName())); + } + return alreadyInstalled; + } + + /** + * Install the service and loop templates from the csar. + * + * @param csar The Csar Handler + * @throws SdcArtifactInstallerException The SdcArtifactInstallerException + * @throws InterruptedException The InterruptedException + * @throws BlueprintParserException In case of issues with the blueprint + * parsing + */ + public void installTheCsar(CsarHandler csar) + throws SdcArtifactInstallerException, InterruptedException, BlueprintParserException { + logger.info("Installing the CSAR " + csar.getFilePath()); + Service associatedService = csarServiceInstaller.installTheService(csar); + cdsDataInstaller.installCdsServiceProperties(csar, associatedService); + + installTheLoopTemplates(csar, associatedService); + logger.info("Successfully installed the CSAR " + csar.getFilePath()); + } + + /** + * Install the loop templates from the csar. + * + * @param csar The Csar Handler + * @param service The service object that is related to the loop + * @throws SdcArtifactInstallerException The SdcArtifactInstallerException + * @throws InterruptedException The InterruptedException + * @throws BlueprintParserException In case of issues with the blueprint + * parsing + */ + public void installTheLoopTemplates(CsarHandler csar, Service service) + throws SdcArtifactInstallerException, InterruptedException, BlueprintParserException { + try { + logger.info("Installing the Loops"); + for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) { + logger.info("Processing blueprint " + blueprint.getValue().getBlueprintArtifactName()); + loopTemplatesRepository.save(createLoopTemplateFromBlueprint(csar, blueprint.getValue(), service)); + } + logger.info("Successfully installed the Loops "); + } catch (IOException e) { + throw new SdcArtifactInstallerException("Exception caught during the Loop installation in database", e); + } catch (ParseException e) { + throw new SdcArtifactInstallerException("Exception caught during the Dcae query to get ServiceTypeId", e); + } + } + + private LoopTemplate createLoopTemplateFromBlueprint(CsarHandler csar, BlueprintArtifact blueprintArtifact, + Service service) + throws IOException, ParseException, InterruptedException, BlueprintParserException, + SdcArtifactInstallerException { + LoopTemplate newLoopTemplate = new LoopTemplate(); + newLoopTemplate.setBlueprint(blueprintArtifact.getDcaeBlueprint()); + newLoopTemplate.setName(LoopTemplate.generateLoopTemplateName(csar.getSdcNotification().getServiceName(), + csar.getSdcNotification().getServiceVersion(), + blueprintArtifact.getResourceAttached().getResourceInstanceName(), + blueprintArtifact.getBlueprintArtifactName())); + List<BlueprintMicroService> microServicesChain = chainGenerator + .getChainOfMicroServices(BlueprintParser.getMicroServices(blueprintArtifact.getDcaeBlueprint())); + if (microServicesChain.isEmpty()) { + microServicesChain = BlueprintParser.fallbackToOneMicroService(); + } + newLoopTemplate.setModelService(service); + newLoopTemplate.addLoopElementModels(createMicroServiceModels(blueprintArtifact, microServicesChain)); + newLoopTemplate.setMaximumInstancesAllowed(0); + DcaeInventoryResponse dcaeResponse = queryDcaeToGetServiceTypeId(blueprintArtifact); + newLoopTemplate.setDcaeBlueprintId(dcaeResponse.getTypeId()); + return newLoopTemplate; + } + + private HashSet<LoopElementModel> createMicroServiceModels(BlueprintArtifact blueprintArtifact, + List<BlueprintMicroService> microServicesChain) + throws SdcArtifactInstallerException { + HashSet<LoopElementModel> newSet = new HashSet<>(); + for (BlueprintMicroService microService : microServicesChain) { + LoopElementModel loopElementModel = + new LoopElementModel(microService.getModelType(), LoopElementModel.MICRO_SERVICE_TYPE, + null); + newSet.add(loopElementModel); + PolicyModel newPolicyModel = policyEngineServices.createPolicyModelFromPolicyEngine(microService); + if (newPolicyModel != null) { + loopElementModel.addPolicyModel(newPolicyModel); + } else { + throw new SdcArtifactInstallerException( + "Unable to find the policy specified in the blueprint " + blueprintArtifact + .getBlueprintArtifactName() + ") on the Policy Engine:" + + microService.getModelType() + "/" + microService.getModelVersion()); + } + } + return newSet; + } + + /** + * Get the service blueprint Id in the Dcae inventory using the SDC UUID. + * + * @return The DcaeInventoryResponse object containing the dcae values + */ + private DcaeInventoryResponse queryDcaeToGetServiceTypeId(BlueprintArtifact blueprintArtifact) + throws IOException, ParseException, InterruptedException { + return dcaeInventoryService.getDcaeInformation(blueprintArtifact.getBlueprintArtifactName(), + blueprintArtifact.getBlueprintInvariantServiceUuid(), + blueprintArtifact.getResourceAttached().getResourceInvariantUUID()); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/Loop.java b/runtime/src/main/java/org/onap/policy/clamp/loop/Loop.java new file mode 100644 index 000000000..99d8d1e69 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/Loop.java @@ -0,0 +1,389 @@ +/*- + * ============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.policy.clamp.loop; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Transient; +import org.hibernate.annotations.SortNatural; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.policy.clamp.loop.common.AuditEntity; +import org.onap.policy.clamp.loop.components.external.DcaeComponent; +import org.onap.policy.clamp.loop.components.external.ExternalComponent; +import org.onap.policy.clamp.loop.components.external.PolicyComponent; +import org.onap.policy.clamp.loop.deploy.DcaeDeployParameters; +import org.onap.policy.clamp.loop.log.LoopLog; +import org.onap.policy.clamp.loop.service.Service; +import org.onap.policy.clamp.loop.template.LoopElementModel; +import org.onap.policy.clamp.loop.template.LoopTemplate; +import org.onap.policy.clamp.policy.microservice.MicroServicePolicy; +import org.onap.policy.clamp.policy.operational.OperationalPolicy; + +@Entity +@Table(name = "loops") +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class Loop extends AuditEntity implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701388642L; + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "dcae_deployment_id") + private String dcaeDeploymentId; + + @Expose + @Column(name = "dcae_deployment_status_url") + private String dcaeDeploymentStatusUrl; + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "global_properties_json") + private JsonObject globalPropertiesJson; + + @Expose + @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}) + @JoinColumn(name = "service_uuid") + private Service modelService; + + @Expose + @Column(nullable = false, name = "last_computed_state") + @Enumerated(EnumType.STRING) + private LoopState lastComputedState; + + @Expose + @Transient + private final Map<String, ExternalComponent> components = new HashMap<>(); + + @Expose + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "loop", orphanRemoval = true) + private Set<OperationalPolicy> operationalPolicies = new HashSet<>(); + + @Expose + @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER) + @JoinTable(name = "loops_to_microservicepolicies", joinColumns = @JoinColumn(name = "loop_name"), + inverseJoinColumns = @JoinColumn(name = "microservicepolicy_name")) + private Set<MicroServicePolicy> microServicePolicies = new HashSet<>(); + + @Expose + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "loop", orphanRemoval = true) + @SortNatural + private SortedSet<LoopLog> loopLogs = new TreeSet<>(); + + @Expose + @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER) + @JoinColumn(name = "loop_template_name", nullable = false) + private LoopTemplate loopTemplate; + + private void initializeExternalComponents() { + this.addComponent(new PolicyComponent()); + this.addComponent(new DcaeComponent()); + } + + /** + * Public constructor. + */ + public Loop() { + initializeExternalComponents(); + } + + /** + * Constructor. + */ + public Loop(String name) { + this.name = name; + this.lastComputedState = LoopState.DESIGN; + this.globalPropertiesJson = new JsonObject(); + initializeExternalComponents(); + } + + /** + * This constructor creates a loop from a loop template. + * + * @param name The loop name + * @param loopTemplate The loop template from which a new loop instance must be created + */ + public Loop(String name, LoopTemplate loopTemplate, ToscaConverterWithDictionarySupport toscaConverter) { + this(name); + this.setLoopTemplate(loopTemplate); + this.setModelService(loopTemplate.getModelService()); + loopTemplate.getLoopElementModelsUsed().forEach(element -> { + if (LoopElementModel.MICRO_SERVICE_TYPE.equals(element.getLoopElementModel().getLoopElementType())) { + this.addMicroServicePolicy((MicroServicePolicy) element.getLoopElementModel() + .createPolicyInstance(this, toscaConverter)); + } else if (LoopElementModel.OPERATIONAL_POLICY_TYPE + .equals(element.getLoopElementModel().getLoopElementType())) { + this.addOperationalPolicy((OperationalPolicy) element.getLoopElementModel() + .createPolicyInstance(this, toscaConverter)); + } + }); + this.setGlobalPropertiesJson(DcaeDeployParameters.getDcaeDeploymentParametersInJson(this)); + } + + public String getName() { + return name; + } + + void setName(String name) { + this.name = name; + } + + public String getDcaeDeploymentId() { + return dcaeDeploymentId; + } + + void setDcaeDeploymentId(String dcaeDeploymentId) { + this.dcaeDeploymentId = dcaeDeploymentId; + } + + public String getDcaeDeploymentStatusUrl() { + return dcaeDeploymentStatusUrl; + } + + void setDcaeDeploymentStatusUrl(String dcaeDeploymentStatusUrl) { + this.dcaeDeploymentStatusUrl = dcaeDeploymentStatusUrl; + } + + public LoopState getLastComputedState() { + return lastComputedState; + } + + void setLastComputedState(LoopState lastComputedState) { + this.lastComputedState = lastComputedState; + } + + public Set<OperationalPolicy> getOperationalPolicies() { + return operationalPolicies; + } + + void setOperationalPolicies(Set<OperationalPolicy> operationalPolicies) { + this.operationalPolicies = operationalPolicies; + } + + public Set<MicroServicePolicy> getMicroServicePolicies() { + return microServicePolicies; + } + + void setMicroServicePolicies(Set<MicroServicePolicy> microServicePolicies) { + this.microServicePolicies = microServicePolicies; + } + + public JsonObject getGlobalPropertiesJson() { + return globalPropertiesJson; + } + + void setGlobalPropertiesJson(JsonObject globalPropertiesJson) { + this.globalPropertiesJson = globalPropertiesJson; + } + + public Set<LoopLog> getLoopLogs() { + return loopLogs; + } + + void setLoopLogs(SortedSet<LoopLog> loopLogs) { + this.loopLogs = loopLogs; + } + + /** + * This method adds an operational policy to the loop. + * + * @param opPolicy the operationalPolicy to add + */ + public void addOperationalPolicy(OperationalPolicy opPolicy) { + operationalPolicies.add(opPolicy); + opPolicy.setLoop(this); + } + + /** + * This method removes an operational policy to the loop. + * + * @param opPolicy the operationalPolicy to add + */ + public void removeOperationalPolicy(OperationalPolicy opPolicy) { + operationalPolicies.remove(opPolicy); + } + + /** + * This method adds an micro service policy to the loop. + * + * @param microServicePolicy the micro service to add + */ + public void addMicroServicePolicy(MicroServicePolicy microServicePolicy) { + microServicePolicies.add(microServicePolicy); + microServicePolicy.getUsedByLoops().add(this); + } + + public void addLog(LoopLog log) { + log.setLoop(this); + this.loopLogs.add(log); + } + + public Service getModelService() { + return modelService; + } + + void setModelService(Service modelService) { + this.modelService = modelService; + } + + public Map<String, ExternalComponent> getComponents() { + refreshDcaeComponents(); + return components; + } + + public ExternalComponent getComponent(String componentName) { + refreshDcaeComponents(); + return this.components.get(componentName); + } + + public void addComponent(ExternalComponent component) { + this.components.put(component.getComponentName(), component); + } + + public LoopTemplate getLoopTemplate() { + return loopTemplate; + } + + public void setLoopTemplate(LoopTemplate loopTemplate) { + this.loopTemplate = loopTemplate; + } + + private void refreshDcaeComponents() { + if (!this.loopTemplate.getUniqueBlueprint()) { + this.components.remove("DCAE"); + for (MicroServicePolicy policy : this.microServicePolicies) { + if (!this.components.containsKey("DCAE_" + policy.getName())) { + this.addComponent(new DcaeComponent(policy.getName())); + } + } + } + } + + /** + * Return the operationalPolicy object with the opPolicyName. + * + * @param opPolicyName The operationalPolicy name + * @return The OperationalPolicy object found in loop object + */ + public OperationalPolicy getOperationalPolicy(String opPolicyName) { + for (OperationalPolicy operationalPolicy : this.getOperationalPolicies()) { + if (operationalPolicy.getName().equals(opPolicyName)) { + return operationalPolicy; + } + } + return null; + } + + /** + * Return the microServicePolicy object with the msPolicyName. + * + * @param msPolicyName The microServicePolicy name + * @return The MicroServicePolicy object found in loop object + */ + public MicroServicePolicy getMicroServicePolicy(String msPolicyName) { + for (MicroServicePolicy microServicePolicy : this.getMicroServicePolicies()) { + if (microServicePolicy.getName().equals(msPolicyName)) { + return microServicePolicy; + } + } + return null; + } + + /** + * 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 + * @return The generated loop name + */ + public static String generateLoopName(String serviceName, String serviceVersion, String resourceName, + String blueprintFileName) { + StringBuilder buffer = new StringBuilder("LOOP_").append(serviceName).append("_v").append(serviceVersion) + .append("_").append(resourceName).append("_").append(blueprintFileName.replaceAll(".yaml", "")); + return buffer.toString().replace('.', '_').replaceAll(" ", ""); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Loop other = (Loop) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/LoopController.java b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopController.java new file mode 100644 index 000000000..98459c909 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopController.java @@ -0,0 +1,204 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.clamp.loop; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.List; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.policy.microservice.MicroServicePolicy; +import org.onap.policy.clamp.policy.microservice.MicroServicePolicyService; +import org.onap.policy.clamp.policy.operational.OperationalPolicy; +import org.onap.policy.clamp.policy.operational.OperationalPolicyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; + +@Controller +public class LoopController { + + private final LoopService loopService; + + private final ToscaConverterWithDictionarySupport toscaConverter; + + private final OperationalPolicyService operationalPolicyService; + + private final MicroServicePolicyService microServicePolicyService; + + private static final Type OPERATIONAL_POLICY_TYPE = new TypeToken<List<OperationalPolicy>>() { + }.getType(); + + private static final Type MICROSERVICE_POLICY_TYPE = new TypeToken<List<MicroServicePolicy>>() { + }.getType(); + + + /** + * Constructor. + * + * @param loopService loopService + * @param operationalPolicyService operationalPolicyService + * @param microServicePolicyService microServicePolicyService + * @param toscaConverter toscaConverter + */ + @Autowired + public LoopController(LoopService loopService, OperationalPolicyService operationalPolicyService, + MicroServicePolicyService microServicePolicyService, + ToscaConverterWithDictionarySupport toscaConverter) { + this.loopService = loopService; + this.toscaConverter = toscaConverter; + this.operationalPolicyService = operationalPolicyService; + this.microServicePolicyService = microServicePolicyService; + } + + public Loop createLoop(String loopName, String templateName) { + return loopService.createLoopFromTemplate(loopName, templateName); + } + + public List<String> getLoopNames() { + return loopService.getClosedLoopNames(); + } + + public Loop getLoop(String loopName) { + return loopService.getLoop(loopName); + } + + /** + * Update the Operational Policy properties. + * + * @param loopName The loop name + * @param operationalPoliciesJson The new Operational Policy properties + * @return The updated loop + */ + public Loop updateOperationalPolicies(String loopName, JsonArray operationalPoliciesJson) { + List<OperationalPolicy> operationalPolicies = JsonUtils.GSON_JPA_MODEL.fromJson(operationalPoliciesJson, + OPERATIONAL_POLICY_TYPE); + return loopService.updateAndSaveOperationalPolicies(loopName, operationalPolicies); + } + + /** + * Update the whole array of MicroService policies properties. + * + * @param loopName The loop name + * @param microServicePoliciesJson The array of all MicroService policies + * properties + * @return The updated loop + */ + public Loop updateMicroservicePolicies(String loopName, JsonArray microServicePoliciesJson) { + List<MicroServicePolicy> microservicePolicies = JsonUtils.GSON_JPA_MODEL.fromJson(microServicePoliciesJson, + MICROSERVICE_POLICY_TYPE); + return loopService.updateAndSaveMicroservicePolicies(loopName, microservicePolicies); + } + + /** + * Update the global properties. + * + * @param loopName The loop name + * @param globalProperties The updated global properties + * @return The updated loop + */ + public Loop updateGlobalPropertiesJson(String loopName, JsonObject globalProperties) { + return loopService.updateAndSaveGlobalPropertiesJson(loopName, globalProperties); + } + + /** + * This method add an operational policy to a loop instance. + * + * @param loopName The loop name + * @param policyType The policy model type + * @param policyVersion The policy model version + * @return The loop modified + */ + public Loop addOperationalPolicy(String loopName, String policyType, String policyVersion) throws IOException { + return loopService.addOperationalPolicy(loopName, policyType, policyVersion); + } + + /** + * This method removes an operational policy from a loop instance. + * + * @param loopName The loop name + * @param policyType The policy model type + * @param policyVersion The policy model version + * @return The loop modified + */ + public Loop removeOperationalPolicy(String loopName, String policyType, String policyVersion) { + return loopService.removeOperationalPolicy(loopName, policyType, policyVersion); + } + + /** + * This method deletes the loop. + * + * @param loopName The loop Name + */ + public void deleteLoop(String loopName) { + loopService.deleteLoop(loopName); + } + + /** + * Update one MicroService policy properties. + * + * @param loopName The loop name + * @param newMicroservicePolicy The new MicroService policy properties + * @return The updated MicroService policy + */ + public MicroServicePolicy updateMicroservicePolicy(String loopName, MicroServicePolicy newMicroservicePolicy) { + return loopService.updateMicroservicePolicy(loopName, newMicroservicePolicy); + } + + /** + * Refresh the Operational Policy Json representation of the loop. + * + * @param loop The loop + * @param operationalPolicyName The operational policy name that needs a refresh + * @return The loop object + */ + public Loop refreshOperationalPolicyJsonRepresentation(Loop loop, String operationalPolicyName) { + for (OperationalPolicy operationalPolicy : loop.getOperationalPolicies()) { + if (operationalPolicy.getName().equals(operationalPolicyName)) { + this.operationalPolicyService + .refreshOperationalPolicyJsonRepresentation(operationalPolicy, toscaConverter); + } + } + return loop; + } + + /** + * Refresh the Config Policy Json representation of the loop. + * + * @param loop The loop + * @param microServicePolicyName The microservice policy name that needs a refresh + * @return The loop object + */ + public Loop refreshMicroServicePolicyJsonRepresentation(Loop loop, String microServicePolicyName) { + for (MicroServicePolicy microServicePolicy : loop.getMicroServicePolicies()) { + if (microServicePolicy.getName().equals(microServicePolicyName)) { + this.microServicePolicyService + .refreshMicroServicePolicyJsonRepresentation(microServicePolicy, toscaConverter, loop); + } + } + return loop; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/LoopService.java b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopService.java new file mode 100644 index 000000000..975011669 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopService.java @@ -0,0 +1,190 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.clamp.loop; + +import com.google.gson.JsonObject; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import javax.persistence.EntityNotFoundException; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.loop.template.LoopTemplatesService; +import org.onap.policy.clamp.loop.template.PolicyModel; +import org.onap.policy.clamp.loop.template.PolicyModelsService; +import org.onap.policy.clamp.policy.microservice.MicroServicePolicy; +import org.onap.policy.clamp.policy.microservice.MicroServicePolicyService; +import org.onap.policy.clamp.policy.operational.OperationalPolicy; +import org.onap.policy.clamp.policy.operational.OperationalPolicyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class LoopService { + + @Autowired + private LoopsRepository loopsRepository; + + @Autowired + private MicroServicePolicyService microservicePolicyService; + + @Autowired + private OperationalPolicyService operationalPolicyService; + + @Autowired + private PolicyModelsService policyModelsService; + + @Autowired + private LoopTemplatesService loopTemplateService; + + @Autowired + private ToscaConverterWithDictionarySupport toscaConverter; + + Loop saveOrUpdateLoop(Loop loop) { + return loopsRepository.save(loop); + } + + List<String> getClosedLoopNames() { + return loopsRepository.getAllLoopNames(); + } + + public Loop getLoop(String loopName) { + return loopsRepository.findById(loopName).orElse(null); + } + + public void deleteLoop(String loopName) { + loopsRepository.deleteById(loopName); + } + + /** + * Creates a Loop Instance from Loop Template Name. + * + * @param loopName Name of the Loop to be created + * @param templateName Loop Template to used for Loop + * @return Loop Instance + */ + public Loop createLoopFromTemplate(String loopName, String templateName) { + return loopsRepository + .save(new Loop(loopName, loopTemplateService.getLoopTemplate(templateName), toscaConverter)); + } + + /** + * This method is used to refresh the DCAE deployment status fields. + * + * @param loop The loop instance to be modified + * @param deploymentId The deployment ID as returned by DCAE + * @param deploymentUrl The Deployment URL as returned by DCAE + */ + public void updateDcaeDeploymentFields(Loop loop, String deploymentId, String deploymentUrl) { + loop.setDcaeDeploymentId(deploymentId); + loop.setDcaeDeploymentStatusUrl(deploymentUrl); + loopsRepository.saveAndFlush(loop); + } + + public void updateLoopState(Loop loop, String newState) { + loop.setLastComputedState(LoopState.valueOf(newState)); + loopsRepository.save(loop); + } + + /** + * This method add an operational policy to a loop instance. + * This creates an operational policy from the policy model info and not the loop element model + * + * @param loopName The loop name + * @param policyType The policy model type + * @param policyVersion The policy model version + * @return The loop modified + */ + Loop addOperationalPolicy(String loopName, String policyType, String policyVersion) throws IOException { + Loop loop = getLoop(loopName); + PolicyModel policyModel = policyModelsService.getPolicyModel(policyType, policyVersion); + Set<OperationalPolicy> opPolicySet = loop.getOperationalPolicies(); + for (OperationalPolicy opPolicy : opPolicySet) { + if (opPolicy.getPolicyModel().equals(policyModel)) { + throw new IllegalArgumentException( + "This type of Operational Policy is already added to the loop. Please choose another one."); + } + } + if (policyModel == null) { + return null; + } + loop.addOperationalPolicy( + new OperationalPolicy(loop, loop.getModelService(), policyModel, toscaConverter)); + return loopsRepository.saveAndFlush(loop); + } + + /** + * This method remove an operational policy to a loop instance. + * + * @param loopName The loop name + * @param policyType The policy model type + * @param policyVersion The policy model version + * @return The loop modified + */ + Loop removeOperationalPolicy(String loopName, String policyType, String policyVersion) { + Loop loop = getLoop(loopName); + PolicyModel policyModel = policyModelsService.getPolicyModel(policyType, policyVersion); + if (policyModel == null) { + return null; + } + for (OperationalPolicy opPolicy : loop.getOperationalPolicies()) { + if (opPolicy.getPolicyModel().getPolicyModelType().equals(policyType) + && opPolicy.getPolicyModel().getVersion().equals(policyVersion)) { + loop.removeOperationalPolicy(opPolicy); + break; + } + } + return loopsRepository.saveAndFlush(loop); + } + + Loop updateAndSaveOperationalPolicies(String loopName, List<OperationalPolicy> newOperationalPolicies) { + Loop loop = findClosedLoopByName(loopName); + Set<OperationalPolicy> newPolicies = operationalPolicyService.updatePolicies(loop, newOperationalPolicies); + loop.setOperationalPolicies(newPolicies); + return loopsRepository.save(loop); + } + + Loop updateAndSaveMicroservicePolicies(String loopName, List<MicroServicePolicy> newMicroservicePolicies) { + Loop loop = findClosedLoopByName(loopName); + Set<MicroServicePolicy> newPolicies = microservicePolicyService.updatePolicies(loop, newMicroservicePolicies); + loop.setMicroServicePolicies(newPolicies); + return loopsRepository.save(loop); + } + + Loop updateAndSaveGlobalPropertiesJson(String loopName, JsonObject newGlobalPropertiesJson) { + Loop loop = findClosedLoopByName(loopName); + loop.setGlobalPropertiesJson(newGlobalPropertiesJson); + return loopsRepository.save(loop); + } + + MicroServicePolicy updateMicroservicePolicy(String loopName, MicroServicePolicy newMicroservicePolicy) { + Loop loop = findClosedLoopByName(loopName); + return microservicePolicyService.getAndUpdateMicroServicePolicy(loop, newMicroservicePolicy); + } + + private Loop findClosedLoopByName(String loopName) { + return loopsRepository.findById(loopName) + .orElseThrow(() -> new EntityNotFoundException("Couldn't find closed loop named: " + loopName)); + } +} + diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/LoopState.java b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopState.java new file mode 100644 index 000000000..48d4487f0 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopState.java @@ -0,0 +1,28 @@ +/*- + * ============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.policy.clamp.loop; + +public enum LoopState { + DESIGN, SUBMITTED, DEPLOYED, RUNNING, STOPPED, IN_ERROR, WAITING; +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/LoopsRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopsRepository.java new file mode 100644 index 000000000..7b92ed584 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopsRepository.java @@ -0,0 +1,36 @@ +/*- + * ============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.policy.clamp.loop; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface LoopsRepository extends JpaRepository<Loop, String> { + + @Query("SELECT loop.name FROM Loop as loop") + List<String> getAllLoopNames(); +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/cds/CdsDataInstaller.java b/runtime/src/main/java/org/onap/policy/clamp/loop/cds/CdsDataInstaller.java new file mode 100644 index 000000000..68adb3887 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/cds/CdsDataInstaller.java @@ -0,0 +1,172 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights + * reserved. + * * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.clamp.loop.cds; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import org.onap.policy.clamp.clds.client.CdsServices; +import org.onap.policy.clamp.clds.model.cds.CdsBpWorkFlowListResponse; +import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler; +import org.onap.policy.clamp.loop.service.Service; +import org.onap.policy.clamp.loop.service.ServicesRepository; +import org.onap.sdc.tosca.parser.enums.SdcTypes; +import org.onap.sdc.toscaparser.api.NodeTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +/** + * This class installs the cds data in the service model properties. + * This can be refreshed later on by clicking on the button refresh, when recomputing the json schema. + */ +@Component +public class CdsDataInstaller { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(CdsDataInstaller.class); + + @Autowired + CdsServices cdsServices; + + @Autowired + ServicesRepository serviceRepository; + + public static final String CONTROLLER_PROPERTIES = "controllerProperties"; + public static final String SDNC_MODEL_NAME = "sdnc_model_name"; + public static final String SDNC_MODEL_VERSION = "sdnc_model_version"; + + /** + * This method installs the service model properties for CDS in the service object given in input. + * + * @param csar The csar from sdc + * @param service the service object already provisioned with csar data + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public Service installCdsServiceProperties(CsarHandler csar, Service service) { + // Iterate on all types defined in the tosca lib + for (SdcTypes type : SdcTypes.values()) { + JsonObject resourcesPropByType = service.getResourceByType(type.getValue()); + // For each type, get the metadata of each nodetemplate + for (NodeTemplate nodeTemplate : csar.getSdcCsarHelper().getServiceNodeTemplateBySdcType(type)) { + // get cds artifact information and save in resources Prop + if (SdcTypes.PNF == type || SdcTypes.VF == type) { + JsonObject controllerProperties = createCdsArtifactProperties( + String.valueOf(nodeTemplate.getPropertyValue(SDNC_MODEL_NAME)), + String.valueOf(nodeTemplate.getPropertyValue(SDNC_MODEL_VERSION))); + if (controllerProperties != null) { + resourcesPropByType.getAsJsonObject(nodeTemplate.getName()) + .add(CONTROLLER_PROPERTIES, controllerProperties); + logger.info("Successfully installed the CDS data in Service"); + } else { + logger.warn("Skipping CDS data installation in Service, as sdnc_model_name and " + + "sdnc_model_version are not provided in the CSAR"); + } + } + } + } + serviceRepository.save(service); + + return service; + } + + /** + * This method updates the service model properties for CDS in the service object given in input. + * + * @param service the service object already provisioned with csar data + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public Service updateCdsServiceProperties(Service service) { + // Iterate on all types defined in the tosca lib + for (SdcTypes type : SdcTypes.values()) { + JsonObject resourcesPropByType = service.getResourceByType(type.getValue()); + for (String resourceName : resourcesPropByType.keySet()) { + // get cds artifact information and save in resources Prop + if ((SdcTypes.PNF == type || SdcTypes.VF == type) && resourcesPropByType.getAsJsonObject(resourceName) + .getAsJsonObject(CONTROLLER_PROPERTIES) != null) { + JsonObject controllerProperties = + createCdsArtifactProperties(resourcesPropByType.getAsJsonObject(resourceName) + .getAsJsonObject(CONTROLLER_PROPERTIES).get(SDNC_MODEL_NAME) + .getAsString(), + resourcesPropByType.getAsJsonObject(resourceName) + .getAsJsonObject(CONTROLLER_PROPERTIES).get(SDNC_MODEL_VERSION) + .getAsString()); + if (controllerProperties != null) { + resourcesPropByType.getAsJsonObject(resourceName) + .add(CONTROLLER_PROPERTIES, controllerProperties); + } + } + } + } + serviceRepository.save(service); + logger.info("Successfully updated the CDS data in Service"); + return service; + } + + /** + * Retrieve CDS artifacts information from node template and save in resource object. + * + * @param sdncModelName sdnc model name + * @param sdncModelVersion sdnc model version + * @return Returns CDS artifacts information + */ + private JsonObject createCdsArtifactProperties(String sdncModelName, String sdncModelVersion) { + if (sdncModelName != null && !"null".equals(sdncModelName) + && sdncModelVersion != null && !"null".equals(sdncModelVersion)) { + JsonObject controllerProperties = new JsonObject(); + controllerProperties.addProperty(SDNC_MODEL_NAME, sdncModelName); + controllerProperties.addProperty(SDNC_MODEL_VERSION, sdncModelVersion); + + CdsBpWorkFlowListResponse response = + queryCdsToGetWorkFlowList(sdncModelName, sdncModelVersion); + if (response == null) { + return controllerProperties; + } + + JsonObject workFlowProps = new JsonObject(); + for (String workFlow : response.getWorkflows()) { + logger.info("Found CDS workflow " + workFlow + " for model name " + sdncModelName + " and version " + + sdncModelVersion); + JsonObject inputs = queryCdsToGetWorkFlowInputProperties(response.getBlueprintName(), + response.getVersion(), workFlow); + workFlowProps.add(workFlow, inputs); + } + + controllerProperties.add("workflows", workFlowProps); + return controllerProperties; + } + return null; + } + + + private CdsBpWorkFlowListResponse queryCdsToGetWorkFlowList(String artifactName, String artifactVersion) { + return cdsServices.getBlueprintWorkflowList(artifactName, artifactVersion); + } + + private JsonObject queryCdsToGetWorkFlowInputProperties(String artifactName, String artifactVersion, + String workFlow) { + return cdsServices.getWorkflowInputProperties(artifactName, artifactVersion, workFlow); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/common/AuditEntity.java b/runtime/src/main/java/org/onap/policy/clamp/loop/common/AuditEntity.java new file mode 100644 index 000000000..92c795e90 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/common/AuditEntity.java @@ -0,0 +1,146 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.loop.common; + +import com.google.gson.annotations.Expose; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +/** + * This class is the parent of the hibernate entities requiring to be audited. + */ +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public class AuditEntity { + + @Expose + @CreatedDate + @Column(name = "created_timestamp", nullable = false, updatable = false) + private Instant createdDate; + + @Expose + @LastModifiedDate + @Column(name = "updated_timestamp", nullable = false) + private Instant updatedDate; + + @Expose + @LastModifiedBy + @Column(name = "updated_by") + private String updatedBy; + + @Expose + @CreatedBy + @Column(name = "created_by") + private String createdBy; + + public Instant getCreatedDate() { + return createdDate; + } + + /** + * createdDate setter. + * + * @param createdDate The created Date object + */ + public void setCreatedDate(Instant createdDate) { + if (createdDate != null) { + this.createdDate = createdDate.truncatedTo(ChronoUnit.SECONDS); + } else { + this.createdDate = null; + } + } + + /** + * updatedDate getter. + * + * @return the updatedDate + */ + public Instant getUpdatedDate() { + return updatedDate; + } + + /** + * updatedDate setter. + * + * @param updatedDate updatedDate to set + */ + public void setUpdatedDate(Instant updatedDate) { + if (updatedDate != null) { + this.updatedDate = updatedDate.truncatedTo(ChronoUnit.SECONDS); + } else { + this.updatedDate = null; + } + } + + /** + * updatedBy getter. + * + * @return the updatedBy + */ + public String getUpdatedBy() { + return updatedBy; + } + + /** + * updatedBy setter. + * + * @param updatedBy the updatedBy + */ + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + /** + * createdBy getter. + * + * @return the createdBy + */ + public String getCreatedBy() { + return createdBy; + } + + /** + * createdBy setter. + * + * @param createdBy the createdBy to set + */ + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + /** + * Empty constructor. + */ + public AuditEntity() { + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/DcaeComponent.java b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/DcaeComponent.java new file mode 100644 index 000000000..6a935d011 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/DcaeComponent.java @@ -0,0 +1,266 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2019, 2021 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.clamp.loop.components.external; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import javax.persistence.Transient; +import org.apache.camel.Exchange; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.onap.policy.clamp.clds.model.dcae.DcaeInventoryResponse; +import org.onap.policy.clamp.clds.model.dcae.DcaeOperationStatusResponse; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.loop.Loop; +import org.onap.policy.clamp.policy.microservice.MicroServicePolicy; + +public class DcaeComponent extends ExternalComponent { + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(DcaeComponent.class); + + private static final String DCAE_DEPLOYMENT_PREFIX = "CLAMP_"; + private static final String DEPLOYMENT_PARAMETER = "dcaeDeployParameters"; + private static final String DCAE_SERVICETYPE_ID = "serviceTypeId"; + private static final String DCAE_INPUTS = "inputs"; + public static final String UNIQUE_BLUEPRINT_PARAMETERS = "uniqueBlueprintParameters"; + + private String name; + + public static final ExternalComponentState BLUEPRINT_DEPLOYED = new ExternalComponentState("BLUEPRINT_DEPLOYED", + "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop"); + public static final ExternalComponentState PROCESSING_MICROSERVICE_INSTALLATION = new ExternalComponentState( + "PROCESSING_MICROSERVICE_INSTALLATION", "Clamp has requested DCAE to install the microservices " + + "defined in the DCAE blueprint and it's currently processing the request"); + public static final ExternalComponentState MICROSERVICE_INSTALLATION_FAILED = new ExternalComponentState( + "MICROSERVICE_INSTALLATION_FAILED", + "Clamp has requested DCAE to install the microservices defined in the DCAE blueprint and it failed"); + public static final ExternalComponentState MICROSERVICE_INSTALLED_SUCCESSFULLY = new ExternalComponentState( + "MICROSERVICE_INSTALLED_SUCCESSFULLY", + "Clamp has requested DCAE to install the DCAE blueprint and it has been installed successfully"); + public static final ExternalComponentState PROCESSING_MICROSERVICE_UNINSTALLATION = new ExternalComponentState( + "PROCESSING_MICROSERVICE_UNINSTALLATION", "Clamp has requested DCAE to uninstall the microservices " + + "defined in the DCAE blueprint and it's currently processing the request"); + public static final ExternalComponentState MICROSERVICE_UNINSTALLATION_FAILED = new ExternalComponentState( + "MICROSERVICE_UNINSTALLATION_FAILED", + "Clamp has requested DCAE to uninstall the microservices defined in the DCAE blueprint and it failed"); + public static final ExternalComponentState MICROSERVICE_UNINSTALLED_SUCCESSFULLY = new ExternalComponentState( + "MICROSERVICE_UNINSTALLED_SUCCESSFULLY", + "Clamp has requested DCAE to uninstall the DCAE blueprint and it has been uninstalled successfully"); + public static final ExternalComponentState IN_ERROR = new ExternalComponentState("IN_ERROR", + "There was an error during the request done to DCAE, look at the logs or try again"); + + public DcaeComponent() { + super(BLUEPRINT_DEPLOYED); + this.name = "DCAE"; + } + + public DcaeComponent(String name) { + super(BLUEPRINT_DEPLOYED); + this.name = "DCAE_" + name; + } + + @Override + public String getComponentName() { + return name; + } + + + /** + * Convert the json response to a DcaeOperationStatusResponse. + * + * @param responseBody The DCAE response Json paylaod + * @return The dcae object provisioned + */ + public static DcaeOperationStatusResponse convertDcaeResponse(String responseBody) { + if (responseBody != null && !responseBody.isEmpty()) { + return JsonUtils.GSON_JPA_MODEL.fromJson(responseBody, DcaeOperationStatusResponse.class); + } else { + return null; + } + } + + /** + * Generate the deployment id, it's random. + * + * @return The deployment id + */ + public static String generateDeploymentId() { + return DCAE_DEPLOYMENT_PREFIX + UUID.randomUUID(); + } + + /** + * This method prepare the url returned by DCAE to check the status if fine. It + * extracts it from the dcaeResponse. + * + * @param dcaeResponse The dcae response object + * @return the Right Url modified if needed + */ + public static String getStatusUrl(DcaeOperationStatusResponse dcaeResponse) { + return dcaeResponse.getLinks().getStatus(); + } + + /** + * Return the deploy payload for DCAE. + * + * @param loop The loop object + * @return The payload used to send deploy closed loop request + */ + public static String getDeployPayload(Loop loop) { + JsonObject globalProp = loop.getGlobalPropertiesJson(); + JsonObject deploymentProp = globalProp.getAsJsonObject(DEPLOYMENT_PARAMETER).getAsJsonObject( + UNIQUE_BLUEPRINT_PARAMETERS); + + String serviceTypeId = loop.getLoopTemplate().getDcaeBlueprintId(); + + JsonObject rootObject = new JsonObject(); + rootObject.addProperty(DCAE_SERVICETYPE_ID, serviceTypeId); + if (deploymentProp != null) { + rootObject.add(DCAE_INPUTS, deploymentProp); + } + logger.info("DCAE Deploy payload for unique blueprint: " + rootObject.toString()); + return rootObject.toString(); + } + + /** + * Return the deploy payload for DCAE. + * + * @param loop The loop object + * @param microServicePolicy The micro service policy + * @return The payload used to send deploy closed loop request + */ + public static String getDeployPayload(Loop loop, MicroServicePolicy microServicePolicy) { + JsonObject globalProp = loop.getGlobalPropertiesJson(); + JsonObject deploymentProp = + globalProp.getAsJsonObject(DEPLOYMENT_PARAMETER).getAsJsonObject(microServicePolicy.getName()); + + String serviceTypeId = microServicePolicy.getDcaeBlueprintId(); + + JsonObject rootObject = new JsonObject(); + rootObject.addProperty(DCAE_SERVICETYPE_ID, serviceTypeId); + if (deploymentProp != null) { + rootObject.add(DCAE_INPUTS, deploymentProp); + } + logger.info("DCAE Deploy payload for multiple blueprints: " + rootObject.toString()); + return rootObject.toString(); + } + + /** + * Return the uninstallation payload for DCAE. + * + * @param loop The loop object + * @return The payload in string (json) + */ + public static String getUndeployPayload(Loop loop) { + JsonObject rootObject = new JsonObject(); + rootObject.addProperty(DCAE_SERVICETYPE_ID, loop.getLoopTemplate().getDcaeBlueprintId()); + logger.info("DCAE Undeploy payload for unique blueprint: " + rootObject.toString()); + return rootObject.toString(); + } + + /** + * Return the uninstallation payload for DCAE. + * + * @param policy The microServicePolicy object + * @return The payload in string (json) + */ + public static String getUndeployPayload(MicroServicePolicy policy) { + JsonObject rootObject = new JsonObject(); + rootObject.addProperty(DCAE_SERVICETYPE_ID, policy.getDcaeBlueprintId()); + logger.info("DCAE Undeploy payload for multiple blueprints: " + rootObject.toString()); + return rootObject.toString(); + } + + @Override + public ExternalComponentState computeState(Exchange camelExchange) { + + DcaeOperationStatusResponse dcaeResponse = (DcaeOperationStatusResponse) camelExchange.getIn().getExchange() + .getProperty("dcaeResponse"); + + if (dcaeResponse == null) { + setState(BLUEPRINT_DEPLOYED); + } else { + if (dcaeResponse.getOperationType().equals("install") && dcaeResponse.getStatus().equals("succeeded")) { + setState(MICROSERVICE_INSTALLED_SUCCESSFULLY); + } else { + if (dcaeResponse.getOperationType().equals("install") && dcaeResponse.getStatus() + .equals("processing")) { + setState(PROCESSING_MICROSERVICE_INSTALLATION); + } else { + if (dcaeResponse.getOperationType().equals("install") && dcaeResponse.getStatus() + .equals("failed")) { + setState(MICROSERVICE_INSTALLATION_FAILED); + } else { + if (dcaeResponse.getOperationType().equals("uninstall") + && dcaeResponse.getStatus().equals("succeeded")) { + setState(MICROSERVICE_UNINSTALLED_SUCCESSFULLY); + } else { + if (dcaeResponse.getOperationType().equals("uninstall") + && dcaeResponse.getStatus().equals("processing")) { + setState(PROCESSING_MICROSERVICE_UNINSTALLATION); + } else { + if (dcaeResponse.getOperationType().equals("uninstall") && dcaeResponse.getStatus() + .equals("failed")) { + setState(MICROSERVICE_UNINSTALLATION_FAILED); + } else { + setState(IN_ERROR); + } + } + } + } + } + } + } + return this.getState(); + } + + /** + * Convert the json response to a DcaeInventoryResponse. + * + * @param responseBody The DCAE response Json paylaod + * @return list of DcaeInventoryResponse + * @throws ParseException In case of issues with the Json parsing + */ + public static List<DcaeInventoryResponse> convertToDcaeInventoryResponse(String responseBody) + throws ParseException { + JSONParser parser = new JSONParser(); + JSONObject jsonObj = (JSONObject) parser.parse(responseBody); + JSONArray itemsArray = (JSONArray) jsonObj.get("items"); + Iterator it = itemsArray.iterator(); + List<DcaeInventoryResponse> inventoryResponseList = new LinkedList<>(); + while (it.hasNext()) { + JSONObject item = (JSONObject) it.next(); + DcaeInventoryResponse response = JsonUtils.GSON.fromJson(item.toString(), DcaeInventoryResponse.class); + inventoryResponseList.add(response); + } + return inventoryResponseList; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponent.java b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponent.java new file mode 100644 index 000000000..ce7efe494 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponent.java @@ -0,0 +1,58 @@ +/*- + * ============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.policy.clamp.loop.components.external; + +import com.google.gson.annotations.Expose; +import org.apache.camel.Exchange; + +/** + * Should be abstract but Gson can't instantiate it if it's an abstract. + */ +public class ExternalComponent { + @Expose + private ExternalComponentState componentState; + + public void setState(ExternalComponentState newState) { + this.componentState = newState; + } + + public ExternalComponentState getState() { + return this.componentState; + } + + public String getComponentName() { + return null; + } + + public ExternalComponentState computeState(Exchange camelExchange) { + return new ExternalComponentState("INIT", "no desc", 0); + } + + public ExternalComponent(ExternalComponentState initialState) { + setState(initialState); + } + + public ExternalComponent() { + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponentState.java b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponentState.java new file mode 100644 index 000000000..a57800025 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponentState.java @@ -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============================================ + * =================================================================== + * + */ + +package org.onap.policy.clamp.loop.components.external; + +import com.google.gson.annotations.Expose; + +/** + * This is a transient state reflecting the deployment status of a component. It + * can be Policy, DCAE, or whatever... This is object is generic. Clamp is now + * stateless, so it triggers the different components at runtime, the status per + * component is stored here. The state level is used to re-compute the global + * state when multiple sub states are required for that computation (generally + * provided sequentially to the method computeState from the camel routes. + * + */ +public class ExternalComponentState implements Comparable<ExternalComponentState> { + @Expose + private String stateName; + @Expose + private String description; + private int stateLevel; + + /** + * Constructor taking stateName, description and its level. + * + * @param stateName The stateName in string + * @param description The description in string + * @param level The level, higher value has higher priority and can't be + * down-graded + */ + public ExternalComponentState(String stateName, String description, int level) { + this.stateName = stateName; + this.description = description; + this.stateLevel = level; + } + + public ExternalComponentState(String stateName, String description) { + this(stateName, description, 0); + } + + public ExternalComponentState() { + } + + public String getStateName() { + return stateName; + } + + public String getDescription() { + return description; + } + + @Override + public String toString() { + return stateName; + } + + public int getLevel() { + return stateLevel; + } + + public void setLevel(int priority) { + this.stateLevel = priority; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((stateName == null) ? 0 : stateName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ExternalComponentState other = (ExternalComponentState) obj; + if (stateName == null) { + if (other.stateName != null) { + return false; + } + } else if (!stateName.equals(other.stateName)) { + return false; + } + return true; + } + + /** + * This method compares this object by using the level of them. + * + * @param stateToCompare The state to compare to the current object + * @return If the one given in input has a higher level than the current object + * it returns -1, 1 otherwise and 0 if equals. + */ + @Override + public int compareTo(ExternalComponentState stateToCompare) { + return Integer.compare(this.getLevel(), stateToCompare.getLevel()); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/PolicyComponent.java b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/PolicyComponent.java new file mode 100644 index 000000000..27e8e1a13 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/PolicyComponent.java @@ -0,0 +1,128 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2019, 2021 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.clamp.loop.components.external; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import javax.persistence.Transient; +import org.apache.camel.Exchange; +import org.onap.policy.clamp.loop.Loop; +import org.onap.policy.clamp.policy.pdpgroup.PdpGroupPayload; + +/** + * This class represents the policy state according to all policies involved in the control loop. + * It can compute it with all policy queries result. + * It contains also the method to generate the PDP payload used for the policies deployment. + */ +public class PolicyComponent extends ExternalComponent { + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyComponent.class); + + public static final ExternalComponentState IN_ERROR = new ExternalComponentState("IN_ERROR", + "There was an error during the sending to policy, the policy engine may be corrupted or inconsistent", 100); + public static final ExternalComponentState NOT_SENT = new ExternalComponentState("NOT_SENT", + "The policies defined have NOT yet been created on the policy engine", 90); + public static final ExternalComponentState SENT = new ExternalComponentState("SENT", + "The policies defined have been created but NOT deployed on the policy engine", 50); + public static final ExternalComponentState SENT_AND_DEPLOYED = new ExternalComponentState("SENT_AND_DEPLOYED", + "The policies defined have been created and deployed on the policy engine", 10); + public static final ExternalComponentState UNKNOWN = new ExternalComponentState("UNKNOWN", + "The current status is not clear. Need to refresh the status to get the current status.", 0); + + /** + * Default constructor. + */ + public PolicyComponent() { + /* + * We assume it's good by default as we will receive the state for each policy + * on by one, each time we increase the level we can't decrease it anymore. + * That's why it starts with the lowest one SENT_AND_DEPLOYED. + */ + super(UNKNOWN); + } + + @Override + public String getComponentName() { + return "POLICY"; + } + + /** + * Generates the Json that must be sent to policy to add all policies to Active + * PDP group. + * + * @param loop the loop object + * @param action POST (to add policy to group) or DELETE (to delete policy from group) + * @return The json, payload to send + */ + public static String createPoliciesPayloadPdpGroup(Loop loop, String action) { + PdpGroupPayload pdpGroupPayload = new PdpGroupPayload(); + loop.getOperationalPolicies().stream().forEach(opPolicy -> pdpGroupPayload + .updatePdpGroupMap(opPolicy.getPdpGroup(), opPolicy.getPdpSubgroup(), opPolicy.getName(), "1.0.0", + action)); + + loop.getMicroServicePolicies().stream().forEach(msPolicy -> pdpGroupPayload + .updatePdpGroupMap(msPolicy.getPdpGroup(), msPolicy.getPdpSubgroup(), msPolicy.getName(), "1.0.0", + action)); + return pdpGroupPayload.generatePdpGroupPayload(); + } + + private static ExternalComponentState findNewState(boolean found, boolean deployed) { + + ExternalComponentState newState = NOT_SENT; + if (found && deployed) { + newState = SENT_AND_DEPLOYED; + } else { + if (found) { + newState = SENT; + } else { + if (deployed) { + newState = IN_ERROR; + } + } + } + return newState; + } + + private static ExternalComponentState mergeStates(ExternalComponentState oldState, + ExternalComponentState newState) { + return (oldState.compareTo(newState) < 0) ? newState : oldState; + } + + /** + * This is a method that expect the results of the queries getPolicy and + * getPolicyDeployed for a unique policy (op, config, etc ...). It + * re-computes the global policy state for each policy results given. Therefore + * this method is called multiple times from the camel route and must be reset + * for a new global policy state retrieval. The state to compute the global + * policy state is stored in this class. + */ + @Override + public ExternalComponentState computeState(Exchange camelExchange) { + this.setState(mergeStates(this.getState(), + findNewState((boolean) camelExchange.getIn().getExchange().getProperty("policyFound"), + (boolean) camelExchange.getIn().getExchange().getProperty("policyDeployed")))); + return this.getState(); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/deploy/DcaeDeployParameters.java b/runtime/src/main/java/org/onap/policy/clamp/loop/deploy/DcaeDeployParameters.java new file mode 100644 index 000000000..1a1414611 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/deploy/DcaeDeployParameters.java @@ -0,0 +1,112 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2019, 2021 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.clamp.loop.deploy; + +import com.google.gson.JsonObject; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.loop.Loop; +import org.onap.policy.clamp.loop.components.external.DcaeComponent; +import org.onap.policy.clamp.policy.microservice.MicroServicePolicy; +import org.yaml.snakeyaml.Yaml; + +/** + * To decode the bluprint input parameters. + */ +public class DcaeDeployParameters { + + private static LinkedHashMap<String, JsonObject> init(Loop loop) { + LinkedHashMap<String, JsonObject> deploymentParamMap = new LinkedHashMap<>(); + Set<MicroServicePolicy> microServiceList = loop.getMicroServicePolicies(); + + for (MicroServicePolicy microService : microServiceList) { + deploymentParamMap.put(microService.getName(), + generateDcaeDeployParameter(microService)); + } + return deploymentParamMap; + } + + private static JsonObject generateDcaeDeployParameter(MicroServicePolicy microService) { + return generateDcaeDeployParameter(microService.getLoopElementModel().getBlueprint(), + microService.getName()); + } + + private static JsonObject generateDcaeDeployParameter(String blueprint, String policyId) { + JsonObject deployJsonBody = new JsonObject(); + Yaml yaml = new Yaml(); + Map<String, Object> inputsNodes = ((Map<String, Object>) ((Map<String, Object>) yaml + .load(blueprint)).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) { + addPropertyToNode(deployJsonBody, elem.getKey(), defaultValue); + } else { + deployJsonBody.addProperty(elem.getKey(), ""); + } + }); + deployJsonBody.addProperty("policy_id", policyId); + return deployJsonBody; + } + + private static void addPropertyToNode(JsonObject node, String key, Object value) { + if (value instanceof String) { + node.addProperty(key, (String) value); + } else if (value instanceof Number) { + node.addProperty(key, (Number) value); + } else if (value instanceof Boolean) { + node.addProperty(key, (Boolean) value); + } else if (value instanceof Character) { + node.addProperty(key, (Character) value); + } else { + node.addProperty(key, JsonUtils.GSON.toJson(value)); + } + } + + /** + * Convert the object in Json. + * + * @return The deploymentParameters in Json + */ + public static JsonObject getDcaeDeploymentParametersInJson(Loop loop) { + JsonObject globalProperties = new JsonObject(); + JsonObject deployParamJson = new JsonObject(); + if (loop.getLoopTemplate().getUniqueBlueprint()) { + // Normally the unique blueprint could contain multiple microservices but then we can't guess + // the policy id params that will be used, so here we expect only one by default. + deployParamJson.add(DcaeComponent.UNIQUE_BLUEPRINT_PARAMETERS, + generateDcaeDeployParameter(loop.getLoopTemplate().getBlueprint(), + ((MicroServicePolicy) loop.getMicroServicePolicies().toArray()[0]).getName())); + + } else { + LinkedHashMap<String, JsonObject> deploymentParamMap = init(loop); + for (Map.Entry<String, JsonObject> mapElement : deploymentParamMap.entrySet()) { + deployParamJson.add(mapElement.getKey(), mapElement.getValue()); + } + } + globalProperties.add("dcaeDeployParameters", deployParamJson); + return globalProperties; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/log/LogType.java b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LogType.java new file mode 100644 index 000000000..50f6571d6 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LogType.java @@ -0,0 +1,28 @@ +/*- + * ============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.policy.clamp.loop.log; + +public enum LogType { + INFO, WARNING, ERROR; +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLog.java b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLog.java new file mode 100644 index 000000000..00f7e1f41 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLog.java @@ -0,0 +1,193 @@ +/*- + * ============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.policy.clamp.loop.log; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import org.onap.policy.clamp.loop.Loop; + +/** + * This class holds the logs created by the Clamp Backend. The Instant is always + * rounded to the nearest second as the nano seconds can't be stored in the + * database. The logs can be therefore exposed to the UI or the client doing + * some GET Loop on the backend. + * + */ +@Entity +@Table(name = "loop_logs") +public class LoopLog implements Serializable, Comparable<LoopLog> { + /** + * The serial version ID. + */ + private static final long serialVersionUID = 1988276670074437631L; + + @Expose + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Expose + @Column(name = "log_type", nullable = false) + @Enumerated(EnumType.STRING) + private LogType logType; + + @Expose + @Column(name = "log_component", nullable = false) + private String logComponent; + + @Expose + @Column(name = "message", columnDefinition = "MEDIUMTEXT", nullable = false) + private String message; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "loop_id", nullable = false) + private Loop loop; + + @Expose + @Column(name = "log_instant", nullable = false) + private Instant logInstant = Instant.now().truncatedTo(ChronoUnit.SECONDS); + + public LoopLog() { + } + + /** + * Constructor For LoopLog taking message and logtype, logComponent and loop + * reference. + * + * @param message The message as string + * @param logType Type like INFO, WARN, DEBUG + * @param logComponent A String with DCAE, POLICY, CLAMP ,etc... + * @param loop The loop object that this log is about + */ + public LoopLog(String message, LogType logType, String logComponent, Loop loop) { + this.message = message; + this.logType = logType; + this.loop = loop; + this.logComponent = logComponent; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public LogType getLogType() { + return logType; + } + + public void setLogType(LogType logType) { + this.logType = logType; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Loop getLoop() { + return loop; + } + + public void setLoop(Loop loop) { + this.loop = loop; + } + + public Instant getLogInstant() { + return logInstant; + } + + public void setLogInstant(Instant logInstant) { + this.logInstant = logInstant.truncatedTo(ChronoUnit.SECONDS); + } + + public String getLogComponent() { + return logComponent; + } + + public void setLogComponent(String logComponent) { + this.logComponent = logComponent; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LoopLog other = (LoopLog) obj; + if (id == null) { + if (other.id != null) { + return false; + } + } else if (!id.equals(other.id)) { + return false; + } + return true; + } + + @Override + public int compareTo(LoopLog arg0) { + // Reverse it, so that by default we have the latest + if (getId() == null) { + return 1; + } + if (arg0.getId() == null) { + return -1; + } + return arg0.getId().compareTo(this.getId()); + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogRepository.java new file mode 100644 index 000000000..df1f3919e --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogRepository.java @@ -0,0 +1,32 @@ +/*- + * ============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.policy.clamp.loop.log; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface LoopLogRepository extends JpaRepository<LoopLog, Long> { + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogService.java b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogService.java new file mode 100644 index 000000000..a2f133f2f --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogService.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.clamp.loop.log; + +import org.onap.policy.clamp.loop.Loop; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class LoopLogService { + + private final LoopLogRepository repository; + + @Autowired + public LoopLogService(LoopLogRepository repository) { + this.repository = repository; + } + + public void addLog(String message, String logType, Loop loop) { + this.addLogForComponent(message, logType, "CLAMP", loop); + } + + public void addLogForComponent(String message, String logType, String component, Loop loop) { + loop.addLog(repository.save(new LoopLog(message, LogType.valueOf(logType), component, loop))); + } + + public boolean isExisting(Long logId) { + return repository.existsById(logId); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/service/CsarServiceInstaller.java b/runtime/src/main/java/org/onap/policy/clamp/loop/service/CsarServiceInstaller.java new file mode 100644 index 000000000..1429d73c2 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/service/CsarServiceInstaller.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.clamp.loop.service; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import java.util.Map.Entry; +import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException; +import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.sdc.tosca.parser.api.IEntityDetails; +import org.onap.sdc.tosca.parser.elements.queries.EntityQuery; +import org.onap.sdc.tosca.parser.elements.queries.TopologyTemplateQuery; +import org.onap.sdc.tosca.parser.enums.EntityTemplateType; +import org.onap.sdc.tosca.parser.enums.SdcTypes; +import org.onap.sdc.toscaparser.api.NodeTemplate; +import org.onap.sdc.toscaparser.api.Property; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Qualifier("csarInstaller") +public class CsarServiceInstaller { + private static final EELFLogger logger = EELFManager.getInstance().getLogger(CsarServiceInstaller.class); + + @Autowired + ServicesRepository serviceRepository; + + /** + * Install the Service from the csar. + * + * @param csar The Csar Handler + * @return The service object + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public Service installTheService(CsarHandler csar) { + logger.info("Start to install the Service from csar"); + JsonObject serviceDetails = JsonUtils.GSON.fromJson( + 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)); + + Service modelService = new Service(serviceDetails, resourcesProp, + csar.getSdcNotification().getServiceVersion()); + + serviceRepository.save(modelService); + logger.info("Successfully installed the Service"); + return modelService; + } + + private JsonObject createServicePropertiesByType(CsarHandler csar) { + JsonObject resourcesProp = new JsonObject(); + // Iterate on all types defined in the tosca lib + for (SdcTypes type : SdcTypes.values()) { + JsonObject resourcesPropByType = new JsonObject(); + // 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())); + } + resourcesProp.add(type.getValue(), resourcesPropByType); + } + return resourcesProp; + } + + private static JsonObject createVfModuleProperties(CsarHandler csar) { + JsonObject vfModuleProps = new JsonObject(); + // 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)) { + // Get all metadata info + JsonObject allVfProps = (JsonObject) JsonUtils.GSON.toJsonTree(entity.getMetadata().getAllProperties()); + vfModuleProps.add(entity.getMetadata().getAllProperties().get("vfModuleModelName"), allVfProps); + // now append the properties section so that we can also have isBase, + // 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())); + } + } + return vfModuleProps; + } + + /** + * Verify whether Service in Csar is deployed. + * + * @param csar The Csar Handler + * @return The flag indicating whether Service is deployed + * @throws SdcArtifactInstallerException The SdcArtifactInstallerException + */ + public boolean isServiceAlreadyDeployed(CsarHandler csar) throws SdcArtifactInstallerException { + boolean alreadyInstalled = true; + JsonObject serviceDetails = JsonUtils.GSON.fromJson( + JsonUtils.GSON.toJson(csar.getSdcCsarHelper().getServiceMetadataAllProperties()), JsonObject.class); + alreadyInstalled = serviceRepository.existsById(serviceDetails.get("UUID").getAsString()); + + return alreadyInstalled; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/service/Service.java b/runtime/src/main/java/org/onap/policy/clamp/loop/service/Service.java new file mode 100644 index 000000000..b7442abc5 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/service/Service.java @@ -0,0 +1,169 @@ +/*- + * ============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.policy.clamp.loop.service; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType; + +@Entity +@Table(name = "services") +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class Service implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = 1331119060272760758L; + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(Service.class); + + @Id + @Column(name = "service_uuid", unique = true) + private String serviceUuid; + + @Column(nullable = false, name = "name") + private String name; + + @Column(name = "version") + private String version; + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "service_details") + private JsonObject serviceDetails; + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "resource_details") + private JsonObject resourceDetails; + + /** + * Default constructor for serialization. + */ + public Service() { + } + + /** + * Constructor with string. + */ + public Service(String serviceDetails, String resourceDetails) { + JsonObject serviceDetailsJson = JsonUtils.GSON.fromJson(serviceDetails, JsonObject.class); + this.name = serviceDetailsJson.get("name").getAsString(); + this.serviceUuid = serviceDetailsJson.get("UUID").getAsString(); + this.serviceDetails = serviceDetailsJson; + this.resourceDetails = JsonUtils.GSON.fromJson(resourceDetails, JsonObject.class); + } + + /** + * Constructor with Json Object. + */ + public Service(JsonObject serviceDetails, JsonObject resourceDetails, String version) { + this.name = serviceDetails.get("name").getAsString(); + this.serviceUuid = serviceDetails.get("UUID").getAsString(); + this.serviceDetails = serviceDetails; + this.resourceDetails = resourceDetails; + this.version = version; + } + + public String getServiceUuid() { + return serviceUuid; + } + + public JsonObject getServiceDetails() { + return serviceDetails; + } + + public JsonObject getResourceDetails() { + return resourceDetails; + } + + public JsonObject getResourceByType(String type) { + return (JsonObject) resourceDetails.get(type); + } + + /** + * Name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Version getter. + * + * @return the version + */ + public String getVersion() { + return version; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((serviceUuid == null) ? 0 : serviceUuid.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Service other = (Service) obj; + if (serviceUuid == null) { + if (other.serviceUuid != null) { + return false; + } + } else { + if (!serviceUuid.equals(other.serviceUuid)) { + return false; + } + } + return true; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/service/ServicesRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/service/ServicesRepository.java new file mode 100644 index 000000000..62596a08e --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/service/ServicesRepository.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.loop.service; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ServicesRepository extends JpaRepository<Service, String> { +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModel.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModel.java new file mode 100644 index 000000000..6eb3c7195 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModel.java @@ -0,0 +1,295 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.clamp.loop.template; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import org.hibernate.annotations.SortNatural; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.loop.Loop; +import org.onap.policy.clamp.loop.common.AuditEntity; +import org.onap.policy.clamp.policy.Policy; +import org.onap.policy.clamp.policy.microservice.MicroServicePolicy; +import org.onap.policy.clamp.policy.operational.OperationalPolicy; + +/** + * This class represents a micro service/operational/... model for a loop template. + * So it's an element in the flow (a box shown in the loop). + */ + +@Entity +@Table(name = "loop_element_models") +public class LoopElementModel extends AuditEntity implements Serializable { + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701376645L; + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "dcae_blueprint_id") + private String dcaeBlueprintId; + + /** + * Here we store the blueprint coming from DCAE, it can be null if this is not a micro service model. + */ + @Column(columnDefinition = "MEDIUMTEXT", name = "blueprint_yaml") + private String blueprint; + + public static final String MICRO_SERVICE_TYPE = "MICRO_SERVICE_TYPE"; + public static final String OPERATIONAL_POLICY_TYPE = "OPERATIONAL_POLICY_TYPE"; + /** + * The type of element. + */ + @Expose + @Column(nullable = false, name = "loop_element_type") + private String loopElementType; + + /** + * This variable is used to display the micro-service name in the SVG. + */ + @Expose + @Column(name = "short_name") + private String shortName; + + /** + * This variable is used to store the type mentioned in the micro-service + * blueprint. + */ + @Expose + @ManyToMany( + fetch = FetchType.EAGER, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}) + @JoinTable( + name = "loopelementmodels_to_policymodels", + joinColumns = @JoinColumn(name = "loop_element_name", referencedColumnName = "name"), + inverseJoinColumns = { + @JoinColumn(name = "policy_model_type", referencedColumnName = "policy_model_type"), + @JoinColumn(name = "policy_model_version", referencedColumnName = "version")}) + @SortNatural + private SortedSet<PolicyModel> policyModels = new TreeSet<>(); + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "loopElementModel", orphanRemoval = true) + private Set<LoopTemplateLoopElementModel> usedByLoopTemplates = new HashSet<>(); + + /** + * policyModels getter. + * + * @return the policyModel + */ + public SortedSet<PolicyModel> getPolicyModels() { + return policyModels; + } + + /** + * Method to add a new policyModel to the list. + * + * @param policyModel The policy model + */ + public void addPolicyModel(PolicyModel policyModel) { + policyModels.add(policyModel); + policyModel.getUsedByElementModels().add(this); + } + + /** + * name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * blueprint getter. + * + * @return the blueprint + */ + public String getBlueprint() { + return blueprint; + } + + /** + * blueprint setter. + * + * @param blueprint the blueprint to set + */ + public void setBlueprint(String blueprint) { + this.blueprint = blueprint; + } + + /** + * dcaeBlueprintId getter. + * + * @return the dcaeBlueprintId + */ + public String getDcaeBlueprintId() { + return dcaeBlueprintId; + } + + /** + * dcaeBlueprintId setter. + * + * @param dcaeBlueprintId the dcaeBlueprintId to set + */ + public void setDcaeBlueprintId(String dcaeBlueprintId) { + this.dcaeBlueprintId = dcaeBlueprintId; + } + + /** + * loopElementType getter. + * + * @return the loopElementType + */ + public String getLoopElementType() { + return loopElementType; + } + + /** + * loopElementType setter. + * + * @param loopElementType the loopElementType to set + */ + public void setLoopElementType(String loopElementType) { + this.loopElementType = loopElementType; + } + + /** + * shortName getter. + * + * @return the shortName + */ + public String getShortName() { + return shortName; + } + + /** + * * @param shortName the shortName to set. + */ + public void setShortName(String shortName) { + this.shortName = shortName; + } + + /** + * usedByLoopTemplates getter. + * + * @return the usedByLoopTemplates + */ + public Set<LoopTemplateLoopElementModel> getUsedByLoopTemplates() { + return usedByLoopTemplates; + } + + /** + * Default constructor for serialization. + */ + public LoopElementModel() { + } + + /** + * Constructor. + * + * @param name The name id + * @param loopElementType The type of loop element + * @param blueprint The blueprint defined for dcae that contains the + * policy type to use + */ + public LoopElementModel(String name, String loopElementType, String blueprint) { + this.name = name; + this.loopElementType = loopElementType; + this.blueprint = blueprint; + } + + /** + * Create a policy instance from the current loop element model. + * + * @return A Policy object. + */ + public Policy createPolicyInstance(Loop loop, ToscaConverterWithDictionarySupport toscaConverter) { + if (LoopElementModel.MICRO_SERVICE_TYPE.equals(this.getLoopElementType())) { + return new MicroServicePolicy(loop, loop.getModelService(), this, toscaConverter); + } else if (LoopElementModel.OPERATIONAL_POLICY_TYPE.equals(this.getLoopElementType())) { + return new OperationalPolicy(loop, loop.getModelService(), this, toscaConverter); + } else { + return null; + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LoopElementModel other = (LoopElementModel) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModelsRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModelsRepository.java new file mode 100644 index 000000000..d9b879d0f --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModelsRepository.java @@ -0,0 +1,31 @@ +/*- + * ============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.policy.clamp.loop.template; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface LoopElementModelsRepository extends JpaRepository<LoopElementModel, String> { +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplate.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplate.java new file mode 100644 index 000000000..ab7367aaf --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplate.java @@ -0,0 +1,341 @@ +/*- + * ============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.policy.clamp.loop.template; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import org.hibernate.annotations.SortNatural; +import org.onap.policy.clamp.loop.common.AuditEntity; +import org.onap.policy.clamp.loop.service.Service; + +@Entity +@Table(name = "loop_templates") +public class LoopTemplate extends AuditEntity implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701388642L; + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "dcae_blueprint_id") + private String dcaeBlueprintId; + + /** + * This field is used when we have a blueprint defining all microservices. The + * other option would be to have independent blueprint for each microservices. + * In that case they are stored in each MicroServiceModel + */ + @Column(columnDefinition = "MEDIUMTEXT", name = "blueprint_yaml") + private String blueprint; + + @Expose + @OneToMany( + cascade = CascadeType.ALL, + fetch = FetchType.EAGER, + mappedBy = "loopTemplate", + orphanRemoval = true) + @SortNatural + private SortedSet<LoopTemplateLoopElementModel> loopElementModelsUsed = new TreeSet<>(); + + @Expose + @ManyToOne( + fetch = FetchType.EAGER, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}) + @JoinColumn(name = "service_uuid") + private Service modelService; + + @Expose + @Column(name = "maximum_instances_allowed") + private Integer maximumInstancesAllowed; + + @Expose + @Column(name = "unique_blueprint", columnDefinition = "boolean default false") + private boolean uniqueBlueprint; + + /** + * Type of Loop allowed to be created. + */ + @Expose + @Column(name = "allowed_loop_type") + @Convert(converter = LoopTypeConvertor.class) + private LoopType allowedLoopType = LoopType.CLOSED; + + /** + * name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * blueprint getter. + * + * @return the blueprint + */ + public String getBlueprint() { + return blueprint; + } + + /** + * dcaeBlueprintId getter. + * + * @return the dcaeBlueprintId + */ + public String getDcaeBlueprintId() { + return dcaeBlueprintId; + } + + /** + * dcaeBlueprintId setter. + * + * @param dcaeBlueprintId the dcaeBlueprintId to set + */ + public void setDcaeBlueprintId(String dcaeBlueprintId) { + this.dcaeBlueprintId = dcaeBlueprintId; + } + + /** + * blueprint setter. + * + * @param blueprint the blueprint to set + */ + public void setBlueprint(String blueprint) { + this.blueprint = blueprint; + if (blueprint == null) { + this.uniqueBlueprint = false; + } else { + this.uniqueBlueprint = true; + } + } + + /** + * loopElementModelsUsed getter. + * + * @return the loopElementModelsUsed + */ + public SortedSet<LoopTemplateLoopElementModel> getLoopElementModelsUsed() { + return loopElementModelsUsed; + } + + /** + * maximumInstancesAllowed getter. + * + * @return the maximumInstancesAllowed + */ + public Integer getMaximumInstancesAllowed() { + return maximumInstancesAllowed; + } + + /** + * maximumInstancesAllowed setter. + * + * @param maximumInstancesAllowed the maximumInstancesAllowed to set + */ + public void setMaximumInstancesAllowed(Integer maximumInstancesAllowed) { + this.maximumInstancesAllowed = maximumInstancesAllowed; + } + + /** + * allowedLoopType getter. + * + * @return the allowedLoopType Type of Loop allowed to be created + */ + public LoopType getAllowedLoopType() { + return allowedLoopType; + } + + /** + * allowedLoopType setter. + * + * @param allowedLoopType the allowedLoopType to set + */ + public void setAllowedLoopType(LoopType allowedLoopType) { + this.allowedLoopType = allowedLoopType; + } + + /** + * Add list of loopElements to the current template, each loopElementModel is + * added at the end of the list so the flowOrder is computed automatically. + * + * @param loopElementModels The loopElementModel set to add + */ + public void addLoopElementModels(Set<LoopElementModel> loopElementModels) { + for (LoopElementModel loopElementModel : loopElementModels) { + addLoopElementModel(loopElementModel); + } + } + + /** + * Add a loopElement to the current template, the loopElementModel is added at + * the end of the list so the flowOrder is computed automatically. + * + * @param loopElementModel The loopElementModel to add + */ + public void addLoopElementModel(LoopElementModel loopElementModel) { + this.addLoopElementModel(loopElementModel, this.loopElementModelsUsed.size()); + } + + /** + * Add a loopElement model to the current template, the flow order must be + * specified manually. + * + * @param loopElementModel The loopElementModel to add + * @param listPosition The position in the flow + */ + public void addLoopElementModel(LoopElementModel loopElementModel, Integer listPosition) { + LoopTemplateLoopElementModel jointEntry = + new LoopTemplateLoopElementModel(this, loopElementModel, listPosition); + this.loopElementModelsUsed.add(jointEntry); + loopElementModel.getUsedByLoopTemplates().add(jointEntry); + } + + /** + * modelService getter. + * + * @return the modelService + */ + public Service getModelService() { + return modelService; + } + + /** + * modelService setter. + * + * @param modelService the modelService to set + */ + public void setModelService(Service modelService) { + this.modelService = modelService; + } + + /** + * uniqueBlueprint getter. + * + * @return the uniqueBlueprint + */ + public boolean getUniqueBlueprint() { + return uniqueBlueprint; + } + + /** + * Default constructor for serialization. + */ + public LoopTemplate() { + + } + + /** + * Constructor. + * + * @param name The loop template name id + * @param blueprint The blueprint containing all microservices (legacy + * case) + * @param maxInstancesAllowed The maximum number of instances that can be + * created from that template + * @param service The service associated to that loop template + */ + public LoopTemplate(String name, String blueprint, Integer maxInstancesAllowed, Service service) { + this.name = name; + this.setBlueprint(blueprint); + + this.maximumInstancesAllowed = maxInstancesAllowed; + this.modelService = service; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LoopTemplate other = (LoopTemplate) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } + + /** + * Generate the loop template 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 template name + */ + public static String generateLoopTemplateName(String serviceName, String serviceVersion, + String resourceName, String blueprintFileName) { + StringBuilder buffer = new StringBuilder("LOOP_TEMPLATE_").append(serviceName).append("_v") + .append(serviceVersion).append("_").append(resourceName).append("_") + .append(blueprintFileName.replaceAll(".yaml", "")); + return buffer.toString().replace('.', '_').replaceAll(" ", ""); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModel.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModel.java new file mode 100644 index 000000000..c0b0c7d24 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModel.java @@ -0,0 +1,192 @@ +/*- + * ============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.policy.clamp.loop.template; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; +import javax.persistence.Table; + +@Entity +@Table(name = "looptemplates_to_loopelementmodels") +public class LoopTemplateLoopElementModel implements Serializable, Comparable<LoopTemplateLoopElementModel> { + + /** + * Serial ID. + */ + private static final long serialVersionUID = 5924989899078094245L; + + @EmbeddedId + private LoopTemplateLoopElementModelId loopTemplateLoopElementModelId; + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("loopTemplateName") + @JoinColumn(name = "loop_template_name") + private LoopTemplate loopTemplate; + + @Expose + @ManyToOne(fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }) + @MapsId("loopElementModelName") + @JoinColumn(name = "loop_element_model_name") + private LoopElementModel loopElementModel; + + @Expose + @Column(nullable = false, name = "flow_order") + private Integer flowOrder; + + /** + * Default constructor for serialization. + */ + public LoopTemplateLoopElementModel() { + + } + + /** + * Constructor. + * + * @param loopTemplate The loop template object + * @param loopElementModel The loopElementModel object + * @param flowOrder The position of the micro service in the flow + */ + public LoopTemplateLoopElementModel(LoopTemplate loopTemplate, LoopElementModel loopElementModel, + Integer flowOrder) { + this.loopTemplate = loopTemplate; + this.loopElementModel = loopElementModel; + this.flowOrder = flowOrder; + this.loopTemplateLoopElementModelId = new LoopTemplateLoopElementModelId(loopTemplate.getName(), + loopElementModel.getName()); + } + + /** + * loopTemplate getter. + * + * @return the loopTemplate + */ + public LoopTemplate getLoopTemplate() { + return loopTemplate; + } + + /** + * loopTemplate setter. + * + * @param loopTemplate the loopTemplate to set + */ + public void setLoopTemplate(LoopTemplate loopTemplate) { + this.loopTemplate = loopTemplate; + } + + /** + * loopElementModel getter. + * + * @return the loopElementModel + */ + public LoopElementModel getLoopElementModel() { + return loopElementModel; + } + + /** + * loopElementModel setter. + * + * @param loopElementModel the loopElementModel to set + */ + public void setLoopElementModel(LoopElementModel loopElementModel) { + this.loopElementModel = loopElementModel; + } + + /** + * flowOrder getter. + * + * @return the flowOrder + */ + public Integer getFlowOrder() { + return flowOrder; + } + + /** + * flowOrder setter. + * + * @param flowOrder the flowOrder to set + */ + public void setFlowOrder(Integer flowOrder) { + this.flowOrder = flowOrder; + } + + @Override + public int compareTo(LoopTemplateLoopElementModel arg0) { + // Reverse it, so that by default we have the latest + if (getFlowOrder() == null) { + return 1; + } + if (arg0.getFlowOrder() == null) { + return -1; + } + return arg0.getFlowOrder().compareTo(this.getFlowOrder()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((loopTemplate == null) ? 0 : loopTemplate.hashCode()); + result = prime * result + ((loopElementModel == null) ? 0 : loopElementModel.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LoopTemplateLoopElementModel other = (LoopTemplateLoopElementModel) obj; + if (loopTemplate == null) { + if (other.loopTemplate != null) { + return false; + } + } else if (!loopTemplate.equals(other.loopTemplate)) { + return false; + } + if (loopElementModel == null) { + if (other.loopElementModel != null) { + return false; + } + } else if (!loopElementModel.equals(other.loopElementModel)) { + return false; + } + return true; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModelId.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModelId.java new file mode 100644 index 000000000..9da8272bd --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModelId.java @@ -0,0 +1,100 @@ +/*- + * ============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.policy.clamp.loop.template; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import javax.persistence.Column; +import javax.persistence.Embeddable; + +@Embeddable +public class LoopTemplateLoopElementModelId implements Serializable { + + /** + * Serial ID. + */ + private static final long serialVersionUID = 4089888115504914773L; + + @Expose + @Column(name = "loop_template_name") + private String loopTemplateName; + + @Expose + @Column(name = "loop_element_model_name") + private String loopElementModelName; + + /** + * Default constructor for serialization. + */ + public LoopTemplateLoopElementModelId() { + + } + + /** + * Constructor. + * + * @param loopTemplateName The loop template name id + * @param microServiceModelName THe micro Service name id + */ + public LoopTemplateLoopElementModelId(String loopTemplateName, String microServiceModelName) { + this.loopTemplateName = loopTemplateName; + this.loopElementModelName = microServiceModelName; + } + + /** + * loopTemplateName getter. + * + * @return the loopTemplateName + */ + public String getLoopTemplateName() { + return loopTemplateName; + } + + /** + * loopTemplateName setter. + * + * @param loopTemplateName the loopTemplateName to set + */ + public void setLoopTemplateName(String loopTemplateName) { + this.loopTemplateName = loopTemplateName; + } + + /** + * microServiceModelName getter. + * + * @return the microServiceModelName + */ + public String getLoopElementModelName() { + return loopElementModelName; + } + + /** + * loopElementModelName setter. + * + * @param loopElementModelName the loopElementModelName to set + */ + public void setLoopElementModelName(String loopElementModelName) { + this.loopElementModelName = loopElementModelName; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesRepository.java new file mode 100644 index 000000000..3993dee34 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesRepository.java @@ -0,0 +1,36 @@ +/*- + * ============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.policy.clamp.loop.template; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface LoopTemplatesRepository extends JpaRepository<LoopTemplate, String> { + + @Query("SELECT looptemplate.name FROM LoopTemplate as looptemplate") + List<String> getAllLoopTemplateNames(); +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesService.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesService.java new file mode 100644 index 000000000..974cf3b5c --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesService.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.loop.template; + +import java.util.List; +import org.onap.policy.clamp.clds.sdc.controller.installer.ChainGenerator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class LoopTemplatesService { + + private final LoopTemplatesRepository loopTemplatesRepository; + + @Autowired + ChainGenerator chainGenerator; + + /** + * Constructor. + */ + @Autowired + public LoopTemplatesService(LoopTemplatesRepository loopTemplatesRepository) { + this.loopTemplatesRepository = loopTemplatesRepository; + + } + + public LoopTemplate saveOrUpdateLoopTemplate(LoopTemplate loopTemplate) { + return loopTemplatesRepository.save(loopTemplate); + } + + public List<String> getLoopTemplateNames() { + return loopTemplatesRepository.getAllLoopTemplateNames(); + } + + public List<LoopTemplate> getAllLoopTemplates() { + return loopTemplatesRepository.findAll(); + } + + public LoopTemplate getLoopTemplate(String name) { + return loopTemplatesRepository.findById(name).orElse(null); + } + + public void deleteLoopTemplate(String name) { + loopTemplatesRepository.deleteById(name); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopType.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopType.java new file mode 100644 index 000000000..eacfecb5e --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopType.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.loop.template; + +/** + * Enums for AllowedLoopType in LoopTemplate enity. + * + */ +public enum LoopType { + OPEN("OPEN"), CLOSED("CLOSED"), HYBRID("HYBRID"); + + private String value; + + private LoopType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTypeConvertor.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTypeConvertor.java new file mode 100644 index 000000000..81ca18d57 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTypeConvertor.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.loop.template; + +import java.util.stream.Stream; +import javax.persistence.AttributeConverter; + +/** + * Attribute Converter to allow using LoopType Enum values in DB and Java classes. + * + */ +public class LoopTypeConvertor implements AttributeConverter<LoopType, String> { + + @Override + public String convertToDatabaseColumn(LoopType loopType) { + if (loopType == null) { + return null; + } + return loopType.getValue(); + } + + @Override + public LoopType convertToEntityAttribute(String value) { + if (value == null) { + return null; + } + + return Stream.of(LoopType.values()).filter(c -> c.getValue().equals(value)).findFirst() + .orElseThrow(IllegalArgumentException::new); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModel.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModel.java new file mode 100644 index 000000000..2414377d7 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModel.java @@ -0,0 +1,282 @@ +/*- + * ============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.policy.clamp.loop.template; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.policy.clamp.loop.common.AuditEntity; +import org.onap.policy.clamp.util.SemanticVersioning; + +/** + * This class represents the policy model tosca revision that we can have to a + * specific microservice. + */ +@Entity +@Table(name = "policy_models") +@IdClass(PolicyModelId.class) +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class PolicyModel extends AuditEntity implements Serializable, Comparable<PolicyModel> { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522705701376645L; + + /** + * This variable is used to store the type mentioned in the micro-service + * blueprint. + */ + @Id + @Expose + @Column(nullable = false, name = "policy_model_type") + private String policyModelType; + + /** + * Semantic versioning on policy side. + */ + @Id + @Expose + @Column(name = "version", nullable = false) + private String version; + + @Column(columnDefinition = "MEDIUMTEXT", name = "policy_tosca") + private String policyModelTosca; + + @Expose + @Column(name = "policy_acronym") + private String policyAcronym; + + @ManyToMany(mappedBy = "policyModels", fetch = FetchType.EAGER) + private Set<LoopElementModel> usedByElementModels = new HashSet<>(); + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "policy_pdp_group") + private JsonObject policyPdpGroup; + + /** + * usedByElementModels getter. + * + * @return the usedByElementModels + */ + public Set<LoopElementModel> getUsedByElementModels() { + return usedByElementModels; + } + + /** + * policyPdpGroup getter. + * + * @return the policyPdpGroup + */ + public JsonObject getPolicyPdpGroup() { + return policyPdpGroup; + } + + /** + * policyPdpGroup setter. + * + * @param policyPdpGroup the policyPdpGroup to set + */ + public void setPolicyPdpGroup(JsonObject policyPdpGroup) { + this.policyPdpGroup = policyPdpGroup; + } + + /** + * policyModelTosca getter. + * + * @return the policyModelTosca + */ + public String getPolicyModelTosca() { + return policyModelTosca; + } + + /** + * policyModelTosca setter. + * + * @param policyModelTosca the policyModelTosca to set + */ + public void setPolicyModelTosca(String policyModelTosca) { + this.policyModelTosca = policyModelTosca; + } + + /** + * policyModelType getter. + * + * @return the modelType + */ + public String getPolicyModelType() { + return policyModelType; + } + + /** + * policyModelType setter. + * + * @param modelType the modelType to set + */ + public void setPolicyModelType(String modelType) { + this.policyModelType = modelType; + } + + /** + * version getter. + * + * @return the version + */ + public String getVersion() { + return version; + } + + /** + * version setter. + * + * @param version the version to set + */ + public void setVersion(String version) { + // Try to convert it before + this.version = version; + } + + /** + * policyAcronym getter. + * + * @return the policyAcronym value + */ + public String getPolicyAcronym() { + return policyAcronym; + } + + /** + * policyAcronym setter. + * + * @param policyAcronym The policyAcronym to set + */ + public void setPolicyAcronym(String policyAcronym) { + this.policyAcronym = policyAcronym; + } + + /** + * Default constructor for serialization. + */ + public PolicyModel() { + } + + /** + * Constructor. + * + * @param policyType The policyType (referenced in the blueprint + * @param policyModelTosca The policy tosca model in yaml + * @param version the version like 1.0.0 + * @param policyAcronym Subtype for policy if it exists (could be used by UI) + */ + public PolicyModel(String policyType, String policyModelTosca, String version, + String policyAcronym) { + this.policyModelType = policyType; + this.policyModelTosca = policyModelTosca; + this.version = version; + this.policyAcronym = policyAcronym; + if (this.policyAcronym == null) { + this.policyAcronym = createDefaultPolicyAcronym(policyType); + } + } + + /** + * Constructor with acronym generated by default from policyType. + * + * @param policyType The policyType (referenced in the blueprint + * @param policyModelTosca The policy tosca model in yaml + * @param version the version like 1.0.0 + */ + public PolicyModel(String policyType, String policyModelTosca, String version) { + this(policyType, policyModelTosca, version, null); + } + + public static String createDefaultPolicyAcronym(String policyType) { + String[] policyNameArray = policyType.split("\\."); + return policyNameArray[policyNameArray.length - 1]; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((policyModelType == null) ? 0 : policyModelType.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + PolicyModel other = (PolicyModel) obj; + if (policyModelType == null) { + if (other.policyModelType != null) { + return false; + } + } else if (!policyModelType.equals(other.policyModelType)) { + return false; + } + if (version == null) { + if (other.version != null) { + return false; + } + } else if (!version.equals(other.version)) { + return false; + } + return true; + } + + @Override + public int compareTo(PolicyModel arg0) { + + if (this.getPolicyModelType().equals(arg0.getPolicyModelType())) { + // Reverse it, so that by default we have the latest in they are same model type + return SemanticVersioning.compare(arg0.getVersion(), this.version); + } else { + return this.getPolicyModelType().compareTo(arg0.getPolicyModelType()); + } + + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelId.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelId.java new file mode 100644 index 000000000..2591bd174 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelId.java @@ -0,0 +1,92 @@ +/*- + * ============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.policy.clamp.loop.template; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; + +public class PolicyModelId implements Serializable { + + /** + * Serial Id. + */ + private static final long serialVersionUID = -2846526482064334745L; + + @Expose + private String policyModelType; + + @Expose + private String version; + + /** + * Default constructor for serialization. + */ + public PolicyModelId() { + + } + + /** + * Constructor. + */ + public PolicyModelId(String policyModelType, String version) { + this.policyModelType = policyModelType; + this.version = version; + } + + /** + * policyModelType getter. + * + * @return the policyModelType + */ + public String getPolicyModelType() { + return policyModelType; + } + + /** + * policyModelType setter. + * + * @param policyModelType the policyModelType to set + */ + public void setPolicyModelType(String policyModelType) { + this.policyModelType = policyModelType; + } + + /** + * version getter. + * + * @return the version + */ + public String getVersion() { + return version; + } + + /** + * version setter. + * + * @param version the version to set + */ + public void setVersion(String version) { + this.version = version; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsRepository.java new file mode 100644 index 000000000..6ff7e3d0c --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsRepository.java @@ -0,0 +1,37 @@ +/*- + * ============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.policy.clamp.loop.template; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface PolicyModelsRepository extends JpaRepository<PolicyModel, PolicyModelId> { + @Query("SELECT policymodel.policyModelType FROM PolicyModel as policymodel") + List<String> getAllPolicyModelType(); + + List<PolicyModel> findByPolicyModelType(String policyModelType); +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsService.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsService.java new file mode 100644 index 000000000..2d31b3b10 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsService.java @@ -0,0 +1,138 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020-2021 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.clamp.loop.template; + +import com.google.gson.JsonObject; +import java.util.List; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.policy.pdpgroup.PdpGroupsAnalyzer; +import org.onap.policy.models.pdp.concepts.PdpGroups; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +/** + * This class contains the methods to access the policyModel object in db. + */ +@Service +public class PolicyModelsService { + private final PolicyModelsRepository policyModelsRepository; + + /** + * This is the new tosca converter that must be used in clamp. + */ + @Autowired + private ToscaConverterWithDictionarySupport toscaConverterWithDictionarySupport; + + @Autowired + public PolicyModelsService(PolicyModelsRepository policyModelrepo) { + policyModelsRepository = policyModelrepo; + } + + /** + * Save or Update Policy Model. + * + * @param policyModel The policyModel + * @return The Policy Model + */ + public PolicyModel saveOrUpdatePolicyModel(PolicyModel policyModel) { + return policyModelsRepository.saveAndFlush(policyModel); + } + + /** + * Verify whether Policy Model exist by ID. + * + * @param policyModelId The policyModel Id + * @return The flag indicates whether Policy Model exist + */ + public boolean existsById(PolicyModelId policyModelId) { + return policyModelsRepository.existsById(policyModelId); + } + + /** + * This method retrieves the tosca model and convert it to a Json schema. + * That json schema is normally used by the UI. + * + * @param policyType The policy model type id + * @param policyTypeVersion The policy model type version + * @return A JsonObject with the json schema describing the tosca + */ + public JsonObject getPolicyModelJson(String policyType, String policyTypeVersion) { + PolicyModel thePolicyModel = getPolicyModel(policyType, policyTypeVersion); + // In the following use case we are not in the context of a closed loop, so the enrichment + // of the json cannot be done, that's why the serviceModel provided is NULL. + return toscaConverterWithDictionarySupport + .convertToscaToJsonSchemaObject(thePolicyModel.getPolicyModelTosca(), policyType, null); + } + + public List<String> getAllPolicyModelTypes() { + return policyModelsRepository.getAllPolicyModelType(); + } + + public Iterable<PolicyModel> getAllPolicyModels() { + return policyModelsRepository.findAll(); + } + + public PolicyModel getPolicyModel(String type, String version) { + return policyModelsRepository.findById(new PolicyModelId(type, version)).orElse(null); + } + + public Iterable<PolicyModel> getAllPolicyModelsByType(String type) { + return policyModelsRepository.findByPolicyModelType(type); + } + + /** + * Retrieves the Tosca model Yaml string. + * + * @param type The Policy Model Type + * @param version The policy model version + * @return The Tosca model Yaml string + */ + public String getPolicyModelTosca(String type, String version) { + return policyModelsRepository.findById(new PolicyModelId(type, version)) + .orElse(new PolicyModel()).getPolicyModelTosca(); + } + + /** + * This method creates an PolicyModel in Db if it does not exist. + * + * @param policyModel The policyModel to save + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public PolicyModel savePolicyModelInNewTransaction(PolicyModel policyModel) { + return policyModelsRepository.saveAndFlush(policyModel); + } + + /** + * Update the Pdp Group info in Policy Model DB. + * + * @param pdpGroups The list of Pdp Group info received from Policy Engine + */ + public void updatePdpGroupInfo(PdpGroups pdpGroups) { + List<PolicyModel> policyModelsList = policyModelsRepository.findAll(); + PdpGroupsAnalyzer.updatePdpGroupOfPolicyModels(policyModelsList, pdpGroups); + this.policyModelsRepository.saveAll(policyModelsList); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/Policy.java b/runtime/src/main/java/org/onap/policy/clamp/policy/Policy.java new file mode 100644 index 000000000..f8bdab6c2 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/Policy.java @@ -0,0 +1,255 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia Intellectual Property. All rights + * reserved. + * ================================================================================ + * Modifications Copyright (C) 2021 AT&T + * ================================================================================ + * 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.clamp.policy; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.UnsupportedEncodingException; +import java.util.Map; +import javax.persistence.Column; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinColumns; +import javax.persistence.ManyToOne; +import javax.persistence.MappedSuperclass; +import javax.persistence.Transient; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.json.JSONObject; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.policy.clamp.loop.common.AuditEntity; +import org.onap.policy.clamp.loop.service.Service; +import org.onap.policy.clamp.loop.template.LoopElementModel; +import org.onap.policy.clamp.loop.template.PolicyModel; +import org.yaml.snakeyaml.Yaml; + +@MappedSuperclass +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public abstract class Policy extends AuditEntity { + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(Policy.class); + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "json_representation", nullable = false) + private JsonObject jsonRepresentation; + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "configurations_json") + private JsonObject configurationsJson; + + /** + * This attribute can be null when the user add a policy on the loop instance, not the template. + * When null, It therefore indicates that this policy is not by default in the loop template. + */ + @Expose + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "loop_element_model_id") + private LoopElementModel loopElementModel; + + @Expose + @Column(name = "pdp_group") + private String pdpGroup; + + @Expose + @Column(name = "pdp_sub_group") + private String pdpSubgroup; + + @Expose + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumns({@JoinColumn(name = "policy_model_type", referencedColumnName = "policy_model_type"), + @JoinColumn(name = "policy_model_version", referencedColumnName = "version")}) + private PolicyModel policyModel; + + /** + * This method create the policy payload that must be sent to PEF. + * + * @return A String containing the payload + * @throws UnsupportedEncodingException In case of failure + */ + public String createPolicyPayload() throws UnsupportedEncodingException { + return PolicyPayload + .createPolicyPayload(this.getPolicyModel().getPolicyModelType(), this.getPolicyModel().getVersion(), + this.getName(), this.getPolicyModel().getVersion(), this.getConfigurationsJson(), + this.getPolicyModel() != null ? this.getPolicyModel().getPolicyModelTosca() : ""); + } + + /** + * Name getter. + * + * @return the name + */ + public abstract String getName(); + + /** + * Name setter. + */ + public abstract void setName(String name); + + /** + * jsonRepresentation getter. + * + * @return the jsonRepresentation + */ + public JsonObject getJsonRepresentation() { + return jsonRepresentation; + } + + /** + * jsonRepresentation setter. + * + * @param jsonRepresentation The jsonRepresentation to set + */ + public void setJsonRepresentation(JsonObject jsonRepresentation) { + this.jsonRepresentation = jsonRepresentation; + } + + /** + * Regenerate the Policy Json Representation. + * + * @param toscaConverter The tosca converter required to regenerate the json schema + * @param serviceModel The service model associated + */ + public abstract void updateJsonRepresentation(ToscaConverterWithDictionarySupport toscaConverter, + Service serviceModel); + + /** + * policyModel getter. + * + * @return the policyModel + */ + public PolicyModel getPolicyModel() { + return policyModel; + } + + /** + * policyModel setter. + * + * @param policyModel The new policyModel + */ + public void setPolicyModel(PolicyModel policyModel) { + this.policyModel = policyModel; + } + + /** + * configurationsJson getter. + * + * @return The configurationsJson + */ + public JsonObject getConfigurationsJson() { + return configurationsJson; + } + + /** + * configurationsJson setter. + * + * @param configurationsJson the configurationsJson to set + */ + public void setConfigurationsJson(JsonObject configurationsJson) { + this.configurationsJson = configurationsJson; + } + + /** + * loopElementModel getter. + * + * @return the loopElementModel + */ + public LoopElementModel getLoopElementModel() { + return loopElementModel; + } + + /** + * loopElementModel setter. + * + * @param loopElementModel the loopElementModel to set + */ + public void setLoopElementModel(LoopElementModel loopElementModel) { + this.loopElementModel = loopElementModel; + } + + /** + * pdpGroup getter. + * + * @return the pdpGroup + */ + public String getPdpGroup() { + return pdpGroup; + } + + /** + * pdpGroup setter. + * + * @param pdpGroup the pdpGroup to set + */ + public void setPdpGroup(String pdpGroup) { + this.pdpGroup = pdpGroup; + } + + /** + * pdpSubgroup getter. + * + * @return the pdpSubgroup + */ + public String getPdpSubgroup() { + return pdpSubgroup; + } + + /** + * pdpSubgroup setter. + * + * @param pdpSubgroup the pdpSubgroup to set + */ + public void setPdpSubgroup(String pdpSubgroup) { + this.pdpSubgroup = pdpSubgroup; + } + + /** + * Generate the policy name. + * + * @param policyType The policy type + * @param serviceName The service name + * @param serviceVersion The service version + * @param resourceName The resource name + * @param blueprintFilename The blueprint file name + * @return The generated policy name + */ + public static String generatePolicyName(String policyType, String serviceName, String serviceVersion, + String resourceName, String blueprintFilename) { + StringBuilder buffer = new StringBuilder(policyType).append("_").append(serviceName).append("_v") + .append(serviceVersion).append("_").append(resourceName).append("_") + .append(blueprintFilename.replaceAll(".yaml", "")); + return buffer.toString().replace('.', '_').replaceAll(" ", ""); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyEngineServices.java b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyEngineServices.java new file mode 100644 index 000000000..4142841e2 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyEngineServices.java @@ -0,0 +1,223 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2020-2021 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.clamp.policy; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import java.util.LinkedHashMap; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.ExchangeBuilder; +import org.onap.policy.clamp.clds.config.ClampProperties; +import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintMicroService; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.loop.template.PolicyModel; +import org.onap.policy.clamp.loop.template.PolicyModelsService; +import org.onap.policy.models.pdp.concepts.PdpGroups; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + + +/** + * The class implements the communication with the Policy Engine to retrieve + * policy models (tosca). It mainly delegates the physical calls to Camel + * engine. + * It supports a retry mechanism for these calls, configurations can be specified in the + * application.properties "policy.retry.interval"(default 0) and "policy.retry.limit"(default 1). + */ +@Component +public class PolicyEngineServices { + private final CamelContext camelContext; + + private final PolicyModelsService policyModelsService; + + private static final String RAISE_EXCEPTION_FLAG = "raiseHttpExceptionFlag"; + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyEngineServices.class); + private int retryInterval = 0; + private int retryLimit = 1; + + public static final String POLICY_RETRY_INTERVAL = "policy.retry.interval"; + public static final String POLICY_RETRY_LIMIT = "policy.retry.limit"; + + /** + * Default constructor. + * + * @param camelContext Camel context bean + * @param clampProperties ClampProperties bean + * @param policyModelsService policyModel service + */ + @Autowired + public PolicyEngineServices(CamelContext camelContext, ClampProperties clampProperties, + PolicyModelsService policyModelsService) { + this.camelContext = camelContext; + this.policyModelsService = policyModelsService; + if (clampProperties.getStringValue(POLICY_RETRY_LIMIT) != null) { + retryLimit = Integer.parseInt(clampProperties.getStringValue(POLICY_RETRY_LIMIT)); + } + if (clampProperties.getStringValue(POLICY_RETRY_INTERVAL) != null) { + retryInterval = Integer.parseInt(clampProperties.getStringValue(POLICY_RETRY_INTERVAL)); + } + } + + /** + * This method query Policy engine and create a PolicyModel object with type and version. + * If the policy already exist in the db it returns the existing one. + * + * @param policyType The policyType id + * @param policyVersion The policy version of that type + * @return A PolicyModel created from policyEngine data or null if nothing is found on policyEngine + */ + public PolicyModel createPolicyModelFromPolicyEngine(String policyType, String policyVersion) { + PolicyModel policyModelFound = policyModelsService.getPolicyModel(policyType, policyVersion); + if (policyModelFound == null) { + String policyTosca = this.downloadOnePolicyToscaModel(policyType, policyVersion); + if (policyTosca != null && !policyTosca.isEmpty()) { + return policyModelsService.savePolicyModelInNewTransaction( + new PolicyModel(policyType, policyTosca, policyVersion)); + } else { + logger.error("Policy not found in the Policy Engine, returning null: " + policyType + + "/" + policyVersion); + return null; + } + } else { + logger.info("Skipping policy model download as it exists already in the database " + policyType + + "/" + policyVersion); + return policyModelFound; + } + } + + /** + * This method query Policy engine and create a PolicyModel object with type and version. + * + * @param microService microservice object instance + * @return A PolicyModel created from policyEngine data + */ + public PolicyModel createPolicyModelFromPolicyEngine(BlueprintMicroService microService) { + return createPolicyModelFromPolicyEngine(microService.getModelType(), microService.getModelVersion()); + } + + /** + * This method synchronize the clamp database and the policy engine. + * So it creates the required PolicyModel. + */ + public void synchronizeAllPolicies() { + LinkedHashMap<String, Object> loadedYaml; + loadedYaml = new Yaml().load(downloadAllPolicyModels()); + if (loadedYaml == null || loadedYaml.isEmpty()) { + logger.warn("getAllPolicyType yaml returned by policy engine could not be decoded, as it's null or empty"); + return; + } + + LinkedHashMap<String, Object> policyTypesMap = (LinkedHashMap<String, Object>) loadedYaml.get("policy_types"); + policyTypesMap.forEach((key, value) -> + this.createPolicyModelFromPolicyEngine(key, + ((String) ((LinkedHashMap<String, Object>) value).get("version")))); + } + + /** + * This method can be used to download all policy types + data types defined in + * policy engine. + * + * @return A yaml containing all policy Types and all data types + */ + public String downloadAllPolicyModels() { + return callCamelRoute( + ExchangeBuilder.anExchange(camelContext).withProperty(RAISE_EXCEPTION_FLAG, true).build(), + "direct:get-all-policy-models", "Get all policies models"); + } + + /** + * This method can be used to download a policy tosca model on the engine. + * + * @param policyType The policy type (id) + * @param policyVersion The policy version + * @return A string with the whole policy tosca model + */ + public String downloadOnePolicyToscaModel(String policyType, String policyVersion) { + logger.info("Downloading the policy tosca model " + policyType + "/" + policyVersion); + DumperOptions options = new DumperOptions(); + options.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN); + options.setIndent(4); + options.setPrettyFlow(true); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml yamlParser = new Yaml(options); + String responseBody = callCamelRoute( + ExchangeBuilder.anExchange(camelContext).withProperty("policyModelType", policyType) + .withProperty("policyModelVersion", policyVersion).withProperty(RAISE_EXCEPTION_FLAG, false) + .build(), "direct:get-policy-tosca-model", + "Get one policy"); + + if (responseBody == null || responseBody.isEmpty()) { + logger.warn("getPolicyToscaModel returned by policy engine could not be decoded, as it's null or empty"); + return null; + } + + return yamlParser.dump(yamlParser.load(responseBody)); + } + + /** + * This method can be used to download all Pdp Groups data from policy engine. + */ + public void downloadPdpGroups() { + String responseBody = + callCamelRoute( + ExchangeBuilder.anExchange(camelContext).withProperty(RAISE_EXCEPTION_FLAG, false).build(), + "direct:get-all-pdp-groups", "Get Pdp Groups"); + + if (responseBody == null || responseBody.isEmpty()) { + logger.warn("getPdpGroups returned by policy engine could not be decoded, as it's null or empty"); + return; + } + + policyModelsService.updatePdpGroupInfo(JsonUtils.GSON.fromJson(responseBody, PdpGroups.class)); + } + + private String callCamelRoute(Exchange exchange, String camelFlow, String logMsg) { + for (int i = 0; i < retryLimit; i++) { + try (ProducerTemplate producerTemplate = camelContext.createProducerTemplate()) { + Exchange exchangeResponse = producerTemplate.send(camelFlow, exchange); + if (HttpStatus.valueOf((Integer) exchangeResponse.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)) + .is2xxSuccessful()) { + return (String) exchangeResponse.getIn().getBody(); + } else { + logger.info(logMsg + " query " + retryInterval + "ms before retrying ..."); + // wait for a while and try to connect to DCAE again + Thread.sleep(retryInterval); + + } + } catch (IOException e) { + logger.error("IOException caught when trying to call Camel flow:" + camelFlow, e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + return ""; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyPayload.java b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyPayload.java new file mode 100644 index 000000000..d2c860150 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyPayload.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2021 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.clamp.policy; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.io.UnsupportedEncodingException; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONObject; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.yaml.snakeyaml.Yaml; + +/** + * This class is a utility class to create the policy payload. + */ +public class PolicyPayload { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyPayload.class); + + private static JsonObject createJsonFromPolicyTosca(String toscaContent) { + Map<String, Object> map = + new Yaml().load(!StringUtils.isEmpty(toscaContent) ? toscaContent : ""); + return JsonUtils.GSON.fromJson(new JSONObject(map).toString(), JsonObject.class); + } + + /** + * This method create the policy payload that must be sent to PEF. + * + * @return A String containing the payload + * @throws UnsupportedEncodingException In case of failure + */ + public static String createPolicyPayload(String policyModelType, String policyModelVersion, String policyName, + String policyVersion, JsonObject policyProperties, String toscaContent) + throws UnsupportedEncodingException { + JsonObject policyPayloadResult = new JsonObject(); + + policyPayloadResult.add("tosca_definitions_version", + createJsonFromPolicyTosca(toscaContent).get("tosca_definitions_version")); + + JsonObject topologyTemplateNode = new JsonObject(); + policyPayloadResult.add("topology_template", topologyTemplateNode); + + JsonArray policiesArray = new JsonArray(); + topologyTemplateNode.add("policies", policiesArray); + + JsonObject thisPolicy = new JsonObject(); + policiesArray.add(thisPolicy); + + JsonObject policyDetails = new JsonObject(); + thisPolicy.add(policyName, policyDetails); + policyDetails.addProperty("type", policyModelType); + policyDetails.addProperty("type_version", policyModelVersion); + policyDetails.addProperty("version", policyVersion); + policyDetails.addProperty("name", policyName); + + JsonObject policyMetadata = new JsonObject(); + policyDetails.add("metadata", policyMetadata); + policyMetadata.addProperty("policy-id", policyName); + policyMetadata.addProperty("policy-version", policyVersion); + + policyDetails.add("properties", policyProperties); + + String policyPayload = JsonUtils.GSON.toJson(policyPayloadResult); + logger.info("Policy payload: " + policyPayload); + return policyPayload; + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyService.java b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyService.java new file mode 100644 index 000000000..35ffa2443 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyService.java @@ -0,0 +1,35 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.clamp.policy; + +import java.util.List; +import java.util.Set; +import org.onap.policy.clamp.loop.Loop; + +public interface PolicyService<T extends Policy> { + + Set<T> updatePolicies(Loop loop, List<T> newPolicies); + + boolean isExisting(String policyName); +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/downloader/PolicyEngineController.java b/runtime/src/main/java/org/onap/policy/clamp/policy/downloader/PolicyEngineController.java new file mode 100644 index 000000000..81775e5da --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/downloader/PolicyEngineController.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020-2021 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.clamp.policy.downloader; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.time.Instant; +import org.json.simple.parser.ParseException; +import org.onap.policy.clamp.loop.template.PolicyModelsRepository; +import org.onap.policy.clamp.policy.PolicyEngineServices; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; + +/** + * This class implements a periodic job that is done in the background to + * synchronize policy models available on the policy engine and the clamp + * database table PolicyModel. + */ +@Configuration +@Profile("clamp-policy-controller") +public class PolicyEngineController { + + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyEngineController.class); + protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger(); + protected static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger(); + public static final String POLICY_RETRY_INTERVAL = "policy.retry.interval"; + public static final String POLICY_RETRY_LIMIT = "policy.retry.limit"; + + private final PolicyEngineServices policyEngineServices; + + private Instant lastInstantExecuted; + + @Autowired + public PolicyEngineController(PolicyEngineServices policyEngineService, + PolicyModelsRepository policyModelsRepository) { + this.policyEngineServices = policyEngineService; + } + + @Scheduled(fixedRate = 300000) + public synchronized void synchronizeAllPolicies() { + policyEngineServices.synchronizeAllPolicies(); + lastInstantExecuted = Instant.now(); + } + + public Instant getLastInstantExecuted() { + return lastInstantExecuted; + } + + @Scheduled(fixedRate = 300000) + public synchronized void downloadPdpGroups() throws ParseException { + policyEngineServices.downloadPdpGroups(); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicy.java b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicy.java new file mode 100644 index 000000000..be5e7917c --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicy.java @@ -0,0 +1,276 @@ +/*- + * ============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.policy.clamp.policy.microservice; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.security.SecureRandom; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import org.apache.commons.lang3.RandomStringUtils; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.policy.clamp.loop.Loop; +import org.onap.policy.clamp.loop.service.Service; +import org.onap.policy.clamp.loop.template.LoopElementModel; +import org.onap.policy.clamp.loop.template.PolicyModel; +import org.onap.policy.clamp.policy.Policy; + +@Entity +@Table(name = "micro_service_policies") +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class MicroServicePolicy extends Policy implements Serializable { + /** + * The serial version ID. + */ + private static final long serialVersionUID = 6271238288583332616L; + + @Expose + @Id + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "context") + private String context; + + @Expose + @Column(name = "device_type_scope") + private String deviceTypeScope; + + @Expose + @Column(name = "shared", nullable = false) + private Boolean shared; + + @ManyToMany(mappedBy = "microServicePolicies", fetch = FetchType.EAGER) + private Set<Loop> usedByLoops = new HashSet<>(); + + @Expose + @Column(name = "dcae_deployment_id") + private String dcaeDeploymentId; + + @Expose + @Column(name = "dcae_deployment_status_url") + private String dcaeDeploymentStatusUrl; + + @Expose + @Column(name = "dcae_blueprint_id") + private String dcaeBlueprintId; + + /** + * Constructor for serialization. + */ + public MicroServicePolicy() { + } + + /** + * The constructor that does not make use of ToscaYamlToJsonConvertor but take + * the jsonRepresentation instead. + * + * @param name The name of the MicroService + * @param policyModel The policy model type of the MicroService + * @param shared The flag indicate whether the MicroService is + * shared + * @param jsonRepresentation The UI representation in json format + * @param loopElementModel The loop element model from which this instance should be created + * @param pdpGroup The Pdp Group info + * @param pdpSubgroup The Pdp Subgroup info + */ + public MicroServicePolicy(String name, PolicyModel policyModel, Boolean shared, + JsonObject jsonRepresentation, LoopElementModel loopElementModel, String pdpGroup, + String pdpSubgroup) { + this.name = name; + this.setPolicyModel(policyModel); + this.shared = shared; + this.setJsonRepresentation(jsonRepresentation); + this.setLoopElementModel(loopElementModel); + this.setPdpGroup(pdpGroup); + this.setPdpSubgroup(pdpSubgroup); + } + + /** + * Constructor with tosca converter. + * + * @param loop The loop instance + * @param service The service model object + * @param loopElementModel The loop element model from which this microservice instance is created + * @param toscaConverter The tosca converter that will used to convert the tosca policy model + */ + public MicroServicePolicy(Loop loop, Service service, LoopElementModel loopElementModel, + ToscaConverterWithDictionarySupport toscaConverter) { + this(Policy.generatePolicyName("MICROSERVICE", service.getName(), service.getVersion(), + loopElementModel.getPolicyModels().first().getPolicyAcronym() + '_' + + loopElementModel.getPolicyModels().first().getVersion(), + RandomStringUtils.random(3, 0, 0, true, true, null, new SecureRandom())), + loopElementModel.getPolicyModels().first(), false, new JsonObject(), loopElementModel, null, null); + this.updateJsonRepresentation(toscaConverter, service); + } + + @Override + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public void updateJsonRepresentation(ToscaConverterWithDictionarySupport toscaConverter, Service serviceModel) { + this.setJsonRepresentation( + toscaConverter.convertToscaToJsonSchemaObject(this.getPolicyModel().getPolicyModelTosca(), + this.getPolicyModel().getPolicyModelType(), serviceModel)); + } + + public Boolean getShared() { + return shared; + } + + void setShared(Boolean shared) { + this.shared = shared; + } + + public Set<Loop> getUsedByLoops() { + return usedByLoops; + } + + void setUsedByLoops(Set<Loop> usedBy) { + this.usedByLoops = usedBy; + } + + public String getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + public String getDeviceTypeScope() { + return deviceTypeScope; + } + + public void setDeviceTypeScope(String deviceTypeScope) { + this.deviceTypeScope = deviceTypeScope; + } + + /** + * dcaeDeploymentId getter. + * + * @return the dcaeDeploymentId + */ + public String getDcaeDeploymentId() { + return dcaeDeploymentId; + } + + /** + * dcaeDeploymentId setter. + * + * @param dcaeDeploymentId the dcaeDeploymentId to set + */ + public void setDcaeDeploymentId(String dcaeDeploymentId) { + this.dcaeDeploymentId = dcaeDeploymentId; + } + + /** + * dcaeDeploymentStatusUrl getter. + * + * @return the dcaeDeploymentStatusUrl + */ + public String getDcaeDeploymentStatusUrl() { + return dcaeDeploymentStatusUrl; + } + + /** + * dcaeDeploymentStatusUrl setter. + * + * @param dcaeDeploymentStatusUrl the dcaeDeploymentStatusUrl to set + */ + public void setDcaeDeploymentStatusUrl(String dcaeDeploymentStatusUrl) { + this.dcaeDeploymentStatusUrl = dcaeDeploymentStatusUrl; + } + + /** + * dcaeBlueprintId getter. + * + * @return the dcaeBlueprintId + */ + public String getDcaeBlueprintId() { + return dcaeBlueprintId; + } + + /** + * dcaeBlueprintId setter. + * + * @param dcaeBlueprintId the dcaeBlueprintId to set + */ + void setDcaeBlueprintId(String dcaeBlueprintId) { + this.dcaeBlueprintId = dcaeBlueprintId; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MicroServicePolicy other = (MicroServicePolicy) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyRepository.java b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyRepository.java new file mode 100644 index 000000000..2ce2c4f17 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyRepository.java @@ -0,0 +1,32 @@ +/*- + * ============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.policy.clamp.policy.microservice; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MicroServicePolicyRepository extends JpaRepository<MicroServicePolicy, String> { + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyService.java b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyService.java new file mode 100644 index 000000000..b9871049e --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyService.java @@ -0,0 +1,112 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.clamp.policy.microservice; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.loop.Loop; +import org.onap.policy.clamp.policy.PolicyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class MicroServicePolicyService implements PolicyService<MicroServicePolicy> { + + private final MicroServicePolicyRepository microServiceRepository; + + @Autowired + public MicroServicePolicyService(MicroServicePolicyRepository microServiceRepository) { + this.microServiceRepository = microServiceRepository; + } + + @Override + public Set<MicroServicePolicy> updatePolicies(Loop loop, List<MicroServicePolicy> newMicroservicePolicies) { + return newMicroservicePolicies.stream().map(policy -> getAndUpdateMicroServicePolicy(loop, policy)) + .collect(Collectors.toSet()); + } + + @Override + public boolean isExisting(String policyName) { + return microServiceRepository.existsById(policyName); + } + + /** + * Get and update the MicroService policy properties. + * + * @param loop The loop + * @param policy The new MicroService policy + * @return The updated MicroService policy + */ + public MicroServicePolicy getAndUpdateMicroServicePolicy(Loop loop, MicroServicePolicy policy) { + return microServiceRepository.save( + microServiceRepository + .findById(policy.getName()).map(p -> updateMicroservicePolicyProperties(p, policy, loop)) + .orElse(new MicroServicePolicy(policy.getName(), policy.getPolicyModel(), + policy.getShared(), policy.getJsonRepresentation(), null, policy.getPdpGroup(), + policy.getPdpSubgroup()))); + } + + private MicroServicePolicy updateMicroservicePolicyProperties(MicroServicePolicy oldPolicy, + MicroServicePolicy newPolicy, Loop loop) { + oldPolicy.setConfigurationsJson(newPolicy.getConfigurationsJson()); + if (!oldPolicy.getUsedByLoops().contains(loop)) { + oldPolicy.getUsedByLoops().add(loop); + } + oldPolicy.setPdpGroup(newPolicy.getPdpGroup()); + oldPolicy.setPdpSubgroup(newPolicy.getPdpSubgroup()); + return oldPolicy; + } + + /** + * Update the MicroService policy deployment related parameters. + * + * @param microServicePolicy The micro service policy + * @param deploymentId The deployment ID as returned by DCAE + * @param deploymentUrl The Deployment URL as returned by DCAE + */ + public void updateDcaeDeploymentFields(MicroServicePolicy microServicePolicy, String deploymentId, + String deploymentUrl) { + microServicePolicy.setDcaeDeploymentId(deploymentId); + microServicePolicy.setDcaeDeploymentStatusUrl(deploymentUrl); + microServiceRepository.saveAndFlush(microServicePolicy); + } + + + /** + * Api to refresh the MicroService Policy UI window. + * + * @param microServicePolicy The micro Service policy object + * @param toscaConverter The tosca converter required to convert the tosca model to json schema + * @param loop As a microservice object can belong to multiple loops, we need it here + */ + public void refreshMicroServicePolicyJsonRepresentation(MicroServicePolicy microServicePolicy, + ToscaConverterWithDictionarySupport toscaConverter, + Loop loop) { + microServicePolicy.updateJsonRepresentation(toscaConverter, loop.getModelService()); + this.microServiceRepository.saveAndFlush(microServicePolicy); + + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicy.java b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicy.java new file mode 100644 index 000000000..1646a7cc7 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicy.java @@ -0,0 +1,219 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.clamp.policy.operational; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.security.SecureRandom; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Transient; +import org.apache.commons.lang3.RandomStringUtils; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.policy.clamp.loop.Loop; +import org.onap.policy.clamp.loop.service.Service; +import org.onap.policy.clamp.loop.template.LoopElementModel; +import org.onap.policy.clamp.loop.template.PolicyModel; +import org.onap.policy.clamp.policy.Policy; + +@Entity +@Table(name = "operational_policies") +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class OperationalPolicy extends Policy implements Serializable { + /** + * The serial version ID. + */ + private static final long serialVersionUID = 6117076450841538255L; + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(OperationalPolicy.class); + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "loop_id", nullable = false) + private Loop loop; + + /** + * Constructor for serialization. + */ + public OperationalPolicy() { + } + + /** + * The constructor. + * + * @param name The name of the operational policy + * @param configurationsJson The operational policy property in the format of + * json + * @param jsonRepresentation The jsonObject defining the json schema + * @param policyModel The policy model associated if any, can be null + * @param loopElementModel The loop element from which this instance is supposed to be created + * @param pdpGroup The Pdp Group info + * @param pdpSubgroup The Pdp Subgroup info + */ + public OperationalPolicy(String name, JsonObject configurationsJson, + JsonObject jsonRepresentation, PolicyModel policyModel, + LoopElementModel loopElementModel, String pdpGroup, String pdpSubgroup) { + this.name = name; + this.setPolicyModel(policyModel); + this.setConfigurationsJson(configurationsJson); + this.setPdpGroup(pdpGroup); + this.setPdpSubgroup(pdpSubgroup); + this.setLoopElementModel(loopElementModel); + this.setJsonRepresentation(jsonRepresentation); + + } + + /** + * Create an operational policy from a loop element model. + * + * @param loop The parent loop + * @param service The loop service + * @param loopElementModel The loop element model + * @param toscaConverter The tosca converter that must be used to create the Json representation + */ + public OperationalPolicy(Loop loop, Service service, LoopElementModel loopElementModel, + ToscaConverterWithDictionarySupport toscaConverter) { + this(Policy.generatePolicyName("OPERATIONAL", service.getName(), service.getVersion(), + loopElementModel.getPolicyModels().first().getPolicyAcronym() + '_' + + loopElementModel.getPolicyModels().first().getVersion(), + RandomStringUtils.random(3, 0, 0, true, true, null, new SecureRandom())), new JsonObject(), + new JsonObject(), loopElementModel.getPolicyModels().first(), loopElementModel, null, null); + this.setLoop(loop); + this.updateJsonRepresentation(toscaConverter, service); + } + + /** + * Create an operational policy from a policy model. + * + * @param loop The parent loop + * @param service The loop service + * @param policyModel The policy model + * @param toscaConverter The tosca converter that must be used to create the Json representation + */ + public OperationalPolicy(Loop loop, Service service, PolicyModel policyModel, + ToscaConverterWithDictionarySupport toscaConverter) { + this(Policy.generatePolicyName("OPERATIONAL", service.getName(), service.getVersion(), + policyModel.getPolicyAcronym() + '_' + policyModel.getVersion(), + RandomStringUtils.random(3, 0, 0, true, true, null, new SecureRandom())), + new JsonObject(), + new JsonObject(), policyModel, null, null, null); + this.setLoop(loop); + this.updateJsonRepresentation(toscaConverter, service); + } + + public void setLoop(Loop loopName) { + this.loop = loopName; + } + + public Loop getLoop() { + return loop; + } + + @Override + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public void updateJsonRepresentation(ToscaConverterWithDictionarySupport toscaConverter, Service serviceModel) { + { + this.setJsonRepresentation(new JsonObject()); + if (this.getPolicyModel() == null) { + return; + } + + // Generic Case + this.setJsonRepresentation(toscaConverter.convertToscaToJsonSchemaObject( + this.getPolicyModel().getPolicyModelTosca(), + this.getPolicyModel().getPolicyModelType(), serviceModel)); + + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + OperationalPolicy other = (OperationalPolicy) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else { + if (!name.equals(other.name)) { + return false; + } + } + return true; + } + + @Override + public String createPolicyPayload() throws UnsupportedEncodingException { + return super.createPolicyPayload(); + + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepository.java b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepository.java new file mode 100644 index 000000000..b0a33669a --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepository.java @@ -0,0 +1,32 @@ +/*- + * ============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.policy.clamp.policy.operational; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface OperationalPolicyRepository extends JpaRepository<OperationalPolicy, String> { + void deleteByName(String policyName); +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java new file mode 100644 index 000000000..6718475ca --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java @@ -0,0 +1,348 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.clamp.policy.operational; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.io.IOException; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.clds.util.ResourceFileUtils; +import org.onap.policy.clamp.loop.service.Service; + +public class OperationalPolicyRepresentationBuilder { + + private static final EELFLogger logger = + EELFManager.getInstance().getLogger(OperationalPolicyRepresentationBuilder.class); + + public static final String PROPERTIES = "properties"; + public static final String ITEMS = "items"; + public static final String ANY_OF = "anyOf"; + public static final String TITLE = "title"; + public static final String RECIPE = "recipe"; + public static final String DEFAULT = "default"; + public static final String STRING = "string"; + public static final String TYPE = "type"; + public static final String TYPE_LIST = "list"; + public static final String TYPE_OBJECT = "object"; + public static final String TYPE_ARRAY = "array"; + + private OperationalPolicyRepresentationBuilder() { + throw new IllegalStateException("This is Utility class, not supposed to be initiated."); + } + + /** + * 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 + */ + public static JsonObject generateOperationalPolicySchema(Service modelJson) { + + JsonObject jsonSchema = null; + try { + jsonSchema = JsonUtils.GSON.fromJson( + ResourceFileUtils + .getResourceAsString("clds/json-schema/operational_policies/operational_policy.json"), + JsonObject.class); + jsonSchema.get(PROPERTIES).getAsJsonObject() + .get("operational_policy").getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("policies") + .getAsJsonObject().get(ITEMS).getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("target") + .getAsJsonObject().get(ANY_OF).getAsJsonArray().addAll(createAnyOfArray(modelJson, true)); + + // update CDS recipe and payload information to schema + for (JsonElement actor : jsonSchema.get(PROPERTIES).getAsJsonObject() + .get("operational_policy").getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("policies") + .getAsJsonObject().get(ITEMS).getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("actor") + .getAsJsonObject().get(ANY_OF).getAsJsonArray()) { + if ("CDS".equalsIgnoreCase(actor.getAsJsonObject().get(TITLE).getAsString())) { + actor.getAsJsonObject().get(PROPERTIES).getAsJsonObject().get(RECIPE).getAsJsonObject() + .get(ANY_OF).getAsJsonArray() + .addAll(createAnyOfArrayForCdsRecipe(modelJson)); + } + } + return jsonSchema; + } catch (IOException e) { + logger.error("Unable to generate the json schema because of an exception", e); + return new JsonObject(); + } + } + + 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(Service modelService, boolean generateType) { + JsonArray vnfSchemaArray = new JsonArray(); + JsonObject modelVnfs = modelService.getResourceByType("VF"); + + for (Entry<String, JsonElement> entry : modelVnfs.entrySet()) { + JsonObject vnfOneOfSchema = new JsonObject(); + vnfOneOfSchema.addProperty(TITLE, "VNF" + "-" + entry.getKey()); + JsonObject properties = new JsonObject(); + if (generateType) { + properties.add(TYPE, createSchemaProperty("Type", STRING, "VNF", "True", null)); + } + properties.add("resourceID", createSchemaProperty("Resource ID", STRING, + modelVnfs.get(entry.getKey()).getAsJsonObject().get("invariantUUID").getAsString(), "True", null)); + + vnfOneOfSchema.add(PROPERTIES, properties); + vnfSchemaArray.add(vnfOneOfSchema); + } + return vnfSchemaArray; + } + + private static JsonArray createBlankEntry() { + JsonArray result = new JsonArray(); + JsonObject blankObject = new JsonObject(); + blankObject.addProperty(TITLE, "User defined"); + blankObject.add(PROPERTIES, new JsonObject()); + result.add(blankObject); + return result; + } + + private static JsonArray createVfModuleSchema(Service modelService, boolean generateType) { + JsonArray vfModuleOneOfSchemaArray = new JsonArray(); + JsonObject modelVfModules = modelService.getResourceByType("VFModule"); + + for (Entry<String, JsonElement> entry : modelVfModules.entrySet()) { + JsonObject vfModuleOneOfSchema = new JsonObject(); + vfModuleOneOfSchema.addProperty(TITLE, "VFMODULE" + "-" + entry.getKey()); + JsonObject properties = new JsonObject(); + if (generateType) { + 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; + } + + /** + * Create an anyOf array of possible structure we may have for Target. + * + * @param modelJson The service object + * @return A JsonArray with everything inside + */ + public static JsonArray createAnyOfArray(Service modelJson, boolean generateType) { + JsonArray targetOneOfStructure = new JsonArray(); + // First entry must be user defined + targetOneOfStructure.addAll(createBlankEntry()); + targetOneOfStructure.addAll(createVnfSchema(modelJson, generateType)); + targetOneOfStructure.addAll(createVfModuleSchema(modelJson, generateType)); + return targetOneOfStructure; + } + + private static JsonArray createAnyOfArrayForCdsRecipe(Service modelJson) { + JsonArray anyOfStructure = new JsonArray(); + anyOfStructure.addAll(createAnyOfCdsRecipe(modelJson.getResourceDetails().getAsJsonObject("VF"))); + anyOfStructure.addAll(createAnyOfCdsRecipe(modelJson.getResourceDetails().getAsJsonObject("PNF"))); + return anyOfStructure; + } + + private static JsonArray createAnyOfCdsRecipe(JsonObject jsonObject) { + JsonArray schemaArray = new JsonArray(); + for (Entry<String, JsonElement> entry : jsonObject.entrySet()) { + JsonObject controllerProperties = entry.getValue().getAsJsonObject() + .getAsJsonObject("controllerProperties"); + + if (controllerProperties != null && controllerProperties.getAsJsonObject("workflows") != null) { + JsonObject workflows = controllerProperties.getAsJsonObject("workflows"); + for (Entry<String, JsonElement> workflowsEntry : workflows.entrySet()) { + JsonObject obj = new JsonObject(); + obj.addProperty(TITLE, workflowsEntry.getKey()); + obj.addProperty(TYPE, TYPE_OBJECT); + obj.add(PROPERTIES, createPayloadProperty(workflowsEntry.getValue().getAsJsonObject(), + controllerProperties, workflowsEntry.getKey())); + schemaArray.add(obj); + } + + } + } + return schemaArray; + } + + private static JsonObject createPayloadProperty(JsonObject workFlow, + JsonObject controllerProperties, String workFlowName) { + JsonObject payload = new JsonObject(); + payload.addProperty(TITLE, "Payload"); + payload.addProperty(TYPE, TYPE_OBJECT); + payload.add(PROPERTIES, createInputPropertiesForPayload(workFlow, controllerProperties, + workFlowName)); + JsonObject properties = new JsonObject(); + properties.add(RECIPE, createRecipeForCdsWorkflow(workFlowName)); + properties.add("payload", payload); + return properties; + } + + private static JsonObject createRecipeForCdsWorkflow(String workflow) { + JsonObject recipe = new JsonObject(); + recipe.addProperty(TITLE, RECIPE); + recipe.addProperty(TYPE, STRING); + recipe.addProperty(DEFAULT, workflow); + JsonObject options = new JsonObject(); + options.addProperty("hidden", true); + recipe.add("options", options); + return recipe; + } + + /** + * Returns the properties of payload based on the cds work flows. + * + * @param workFlow cds work flows to update payload + * @param controllerProperties cds properties to get blueprint name and + * version + * @param workFlowName work flow name + * @return returns the properties of payload + */ + public static JsonObject createInputPropertiesForPayload(JsonObject workFlow, + JsonObject controllerProperties, + String workFlowName) { + String artifactName = controllerProperties.get("sdnc_model_name").getAsString(); + String artifactVersion = controllerProperties.get("sdnc_model_version").getAsString(); + JsonObject inputs = workFlow.getAsJsonObject("inputs"); + JsonObject jsonObject = new JsonObject(); + jsonObject.add("artifact_name", createSchemaProperty( + "artifact name", STRING, artifactName, "True", null)); + jsonObject.add("artifact_version", createSchemaProperty( + "artifact version", STRING, artifactVersion, "True", null)); + jsonObject.add("mode", createCdsInputProperty( + "mode", STRING, "async", null)); + jsonObject.add("data", createDataProperty(inputs, workFlowName)); + return jsonObject; + } + + private static JsonObject createDataProperty(JsonObject inputs, String workflowName) { + JsonObject data = new JsonObject(); + data.addProperty(TITLE, "data"); + JsonObject dataObj = new JsonObject(); + addDataFields(inputs, dataObj, workflowName); + data.add(PROPERTIES, dataObj); + return data; + } + + private static void addDataFields(JsonObject inputs, + JsonObject dataObj, + String workFlowName) { + Set<Map.Entry<String, JsonElement>> entrySet = inputs.entrySet(); + for (Map.Entry<String, JsonElement> entry : entrySet) { + String key = entry.getKey(); + JsonObject inputProperty = inputs.getAsJsonObject(key); + if (key.equalsIgnoreCase(workFlowName + "-properties")) { + addDataFields(entry.getValue().getAsJsonObject().get(PROPERTIES).getAsJsonObject(), + dataObj, workFlowName); + } else { + dataObj.add(entry.getKey(), + createCdsInputProperty(key, inputProperty.get(TYPE).getAsString(), null, + entry.getValue().getAsJsonObject())); + } + } + } + + private static JsonObject createCdsInputProperty(String title, + String type, + String defaultValue, + JsonObject cdsProperty) { + JsonObject property = new JsonObject(); + property.addProperty(TITLE, title); + + if (TYPE_LIST.equalsIgnoreCase(type)) { + property.addProperty(TYPE, TYPE_ARRAY); + if (cdsProperty != null && cdsProperty.get(PROPERTIES) != null) { + JsonObject listProperties = new JsonObject(); + listProperties.add(PROPERTIES, getProperties(cdsProperty.get(PROPERTIES).getAsJsonObject())); + property.add(ITEMS, listProperties); + } + } else if (cdsProperty != null && TYPE_OBJECT.equalsIgnoreCase(type)) { + property.addProperty(TYPE, TYPE_OBJECT); + property.add(PROPERTIES, getProperties(cdsProperty.get(PROPERTIES).getAsJsonObject())); + } else { + property.addProperty(TYPE, type); + } + + if (defaultValue != null) { + property.addProperty(DEFAULT, defaultValue); + } + return property; + } + + private static JsonObject getProperties(JsonObject inputProperties) { + if (inputProperties == null) { + return null; + } + JsonObject dataObject = new JsonObject(); + addDataFields(inputProperties, dataObject, null); + return dataObject; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyService.java b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyService.java new file mode 100644 index 000000000..3f3f39b45 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyService.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.clamp.policy.operational; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.policy.clamp.loop.Loop; +import org.onap.policy.clamp.loop.template.PolicyModelsRepository; +import org.onap.policy.clamp.policy.PolicyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class OperationalPolicyService implements PolicyService<OperationalPolicy> { + + private final OperationalPolicyRepository operationalPolicyRepository; + + private final PolicyModelsRepository policyModelsRepository; + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(OperationalPolicyService.class); + + @Autowired + public OperationalPolicyService(OperationalPolicyRepository repository, + PolicyModelsRepository policyModelsRepository) { + this.operationalPolicyRepository = repository; + this.policyModelsRepository = policyModelsRepository; + } + + @Override + public Set<OperationalPolicy> updatePolicies(Loop loop, List<OperationalPolicy> operationalPolicies) { + return operationalPolicies + .parallelStream() + .map(policy -> + operationalPolicyRepository + .findById(policy.getName()) + .map(p -> setConfiguration(p, policy)) + .orElse(initializeMissingFields(loop, policy))) + .collect(Collectors.toSet()); + } + + @Override + public boolean isExisting(String policyName) { + return operationalPolicyRepository.existsById(policyName); + } + + private OperationalPolicy initializeMissingFields(Loop loop, OperationalPolicy policy) { + policy.setLoop(loop); + return policy; + } + + private OperationalPolicy setConfiguration(OperationalPolicy policy, OperationalPolicy newPolicy) { + policy.setConfigurationsJson(newPolicy.getConfigurationsJson()); + policy.setPdpGroup(newPolicy.getPdpGroup()); + policy.setPdpSubgroup(newPolicy.getPdpSubgroup()); + return policy; + } + + /** + * Api to refresh the Operational Policy UI window. + * + * @param operationalPolicy The operational policy object + * @param toscaConverter the tosca converter required to convert the tosca model to json schema + */ + public void refreshOperationalPolicyJsonRepresentation(OperationalPolicy operationalPolicy, + ToscaConverterWithDictionarySupport toscaConverter) { + operationalPolicy.updateJsonRepresentation(toscaConverter, operationalPolicy.getLoop().getModelService()); + this.operationalPolicyRepository.saveAndFlush(operationalPolicy); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayload.java b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayload.java new file mode 100644 index 000000000..c6b44076f --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayload.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2021 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.clamp.policy.pdpgroup; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonElement; +import java.util.ArrayList; +import java.util.Arrays; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.models.pdp.concepts.DeploymentGroup; +import org.onap.policy.models.pdp.concepts.DeploymentGroups; +import org.onap.policy.models.pdp.concepts.DeploymentSubGroup; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * This is an utility class that build the PDP group policy payload. + * This is used when policies have to be deployed to PDP group/subgroups on the Policy Engine. + * Currently it does not group the queries per pdpgroup/subgroups/action. + * This is currently NOT thread safe, do not use parallel streams to update the structure. + */ +public class PdpGroupPayload { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(PdpGroupPayload.class); + + /** + * The default node that will contain the actions array. + */ + public static final String PDP_ACTIONS = "PdpActions"; + + private final DeploymentGroups deploymentGroups = new DeploymentGroups(); + + /** + * Default constructor. + */ + public PdpGroupPayload() { + deploymentGroups.setGroups(new ArrayList<>()); + } + + /** + * Constructor that takes a list of actions in input. + * + * @param listOfPdpActions The list of actions that needs to be done. + * e.g: {"Pdpactions":["DELETE/PdpGroup1/PdpSubGroup1/PolicyName1/1.0.0",....]} + * @throws PdpGroupPayloadException in case of issues to read the listOfActions + */ + public PdpGroupPayload(final JsonElement listOfPdpActions) throws PdpGroupPayloadException { + this(); + this.readListOfActions(listOfPdpActions); + } + + /** + * This method converts the list of actions directly to the pdp payload query as String. + * + * @param listOfPdpActions The list of actions that needs to be done. + * e.g: {"Pdpactions":["DELETE/PdpGroup1/PdpSubGroup1/PolicyName1/1.0.0",....]} + * @return The string containing the PDP payload that can be sent directly + * @throws PdpGroupPayloadException in case of issues to read the listOfActions + */ + public static String generatePdpGroupPayloadFromList(final JsonElement listOfPdpActions) + throws PdpGroupPayloadException { + return new PdpGroupPayload(listOfPdpActions).generatePdpGroupPayload(); + } + + + private void readListOfActions(final JsonElement listOfPdpActions) throws PdpGroupPayloadException { + for (JsonElement action : listOfPdpActions.getAsJsonObject().getAsJsonArray(PDP_ACTIONS)) { + String[] opParams = action.getAsString().split("/"); + if (opParams.length == 5) { + this.updatePdpGroupMap(opParams[1], opParams[2], opParams[3], opParams[4], opParams[0]); + } else { + logger.error("One PDP push command does not contain the right number of arguments: " + action); + throw new PdpGroupPayloadException( + "One PDP push command does not contain the right number of arguments: " + action); + } + } + } + + /** + * This method updates the pdpGroupMap structure for a specific policy/version/pdpdGroup/PdpSubGroup. + * + * @param pdpGroup The pdp Group in String + * @param pdpSubGroup The pdp Sub Group in String + * @param policyName The policy name + * @param policyVersion The policy Version + * @param action DELETE or POST + */ + public void updatePdpGroupMap(String pdpGroup, + String pdpSubGroup, + String policyName, + String policyVersion, String action) { + // create subgroup + DeploymentSubGroup newSubGroup = new DeploymentSubGroup(); + newSubGroup.setPdpType(pdpSubGroup); + newSubGroup.setAction(DeploymentSubGroup.Action.valueOf(action)); + newSubGroup.setPolicies(Arrays.asList(new ToscaConceptIdentifier(policyName, policyVersion))); + // Add to deployment Groups structure + this.deploymentGroups.getGroups().stream().filter(group -> + group.getName().equals(pdpGroup)).findFirst() + .ifPresentOrElse(group -> group.getDeploymentSubgroups().add(newSubGroup), + () -> { + DeploymentGroup newGroup = new DeploymentGroup(); + newGroup.setName(pdpGroup); + newGroup.setDeploymentSubgroups(new ArrayList<>(Arrays.asList(newSubGroup))); + this.deploymentGroups.getGroups().add(newGroup); + }); + } + + /** + * This method generates the Payload in Json from the pdp Group structure containing the policies/versions + * that must be sent to the policy framework. + * + * @return The Json that can be sent to policy framework as String + */ + public String generatePdpGroupPayload() { + String payload = JsonUtils.GSON.toJson(this.deploymentGroups); + logger.info("PdpGroup policy payload: " + payload); + return payload; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadException.java b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadException.java new file mode 100644 index 000000000..4ce0721b2 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2021 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.clamp.policy.pdpgroup; + +/** + * Exception during Pdp Group payload construction. + */ +public class PdpGroupPayloadException extends Exception { + + /** + * serialization id. + */ + private static final long serialVersionUID = -5676848693241134101L; + + /** + * This constructor can be used to create a new PdpGroupPayloadException. + * + * @param message The message to dump + */ + public PdpGroupPayloadException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new PdpGroupPayloadException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public PdpGroupPayloadException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupsAnalyzer.java b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupsAnalyzer.java new file mode 100644 index 000000000..6098d0f63 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupsAnalyzer.java @@ -0,0 +1,180 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2021 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.clamp.policy.pdpgroup; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.commons.collections4.CollectionUtils; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.clamp.loop.template.PolicyModel; +import org.onap.policy.models.pdp.concepts.PdpGroup; +import org.onap.policy.models.pdp.concepts.PdpGroups; +import org.onap.policy.models.pdp.concepts.PdpSubGroup; +import org.onap.policy.models.pdp.enums.PdpState; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * This is an utility class to do searching in pdp groups and create json object describing the result. + */ +public class PdpGroupsAnalyzer { + + public static final String ASSIGNED_PDP_GROUPS_INFO = "pdpGroupInfo"; + public static final String SUPPORTED_PDP_GROUPS_INFO = "supportedPdpGroups"; + + /** + * This structure holds the map of PdpGroups per policies, policies are identifed by ToscaConceptIdentifier. + */ + private final Map<ToscaConceptIdentifier, Map<String, PdpGroup>> pdpGroupsDeploymentPerPolicy = + new ConcurrentHashMap<>(); + + /** + * Constructor taking he PDPGroups info from the PEF. + * It then caches the groups per policies and per types. + * + * @param pdpGroups The pdpgroup info from the PEF + */ + public PdpGroupsAnalyzer(PdpGroups pdpGroups) { + this.analyzePdpGroups(pdpGroups); + } + + /** + * Getter of the GroupDeploymentPerPolicy structure. + * + * @return The map of policies. + */ + public Map<ToscaConceptIdentifier, Map<String, PdpGroup>> getPdpGroupsDeploymentPerPolicy() { + return pdpGroupsDeploymentPerPolicy; + } + + private static void addInfoToPdpGroupsStructure(ToscaConceptIdentifier toscaId, + Map<ToscaConceptIdentifier, + Map<String, + PdpGroup>> pdpGroupsDeploymentPerToscaIdentifier, + PdpGroup pdpGroupSource, + PdpSubGroup pdpSubGroupSource) { + // Copy the subgroup but empty the policies & types + pdpGroupsDeploymentPerToscaIdentifier.computeIfAbsent(toscaId, toscaKey -> new ConcurrentHashMap<>()) + .computeIfAbsent(pdpGroupSource.getName(), pdpGroupName -> { + PdpGroup pdpGroupCopy = new PdpGroup(pdpGroupSource); + pdpGroupCopy.setPdpSubgroups(new ArrayList<>()); + return pdpGroupCopy; + }).getPdpSubgroups().add(new PdpSubGroup(pdpSubGroupSource)); + } + + private void analyzePdpGroups(PdpGroups pdpGroups) { + CollectionUtils.emptyIfNull(pdpGroups.getGroups()).stream() + .forEach(group -> CollectionUtils.emptyIfNull(group.getPdpSubgroups()).stream().forEach(subGroup -> + CollectionUtils.emptyIfNull(subGroup.getPolicies()).parallelStream().forEach(policy -> + PdpGroupsAnalyzer.addInfoToPdpGroupsStructure(policy, this.pdpGroupsDeploymentPerPolicy, + group, subGroup)))); + } + + /** + * This method retrieves all pdpGroups and subgroups where a specific policy name/version is deployed. + * + * @param policyName The policy name that must be used for searching + * @param version THe policy version that must be used for searching + * @return It returns a JsonObject containing each pdpGroup and subgroups associated + */ + public JsonObject getPdpGroupsForPolicy(String policyName, String version) { + Map<String, PdpGroup> mapOfGroups = + this.pdpGroupsDeploymentPerPolicy.get(new ToscaConceptIdentifier(policyName, version)); + if (mapOfGroups != null) { + JsonObject policyPdpGroups = new JsonObject(); + JsonArray pdpGroupsArray = new JsonArray(); + policyPdpGroups.add(ASSIGNED_PDP_GROUPS_INFO, pdpGroupsArray); + pdpGroupsArray.add(JsonUtils.GSON + .toJsonTree(mapOfGroups)); + return policyPdpGroups; + } + return null; + } + + /** + * Get supported subGroups based on the defined policy type and version for specific PDPGroup. + * It returns null if the Group is TERMINATED or if the policytype/version has not been found in the PDPSubgroups. + * + * @param pdpGroup The pdpGroup that must be analyzed + * @param policyType The policy type + * @param version The version + * @return The supported subGroups list in Json format + * @see org.onap.policy.models.pdp.concepts.PdpGroup + * @see org.onap.policy.models.pdp.enums.PdpState + */ + private static JsonObject getSupportedPdpSubgroupsForModelType(PdpGroup pdpGroup, String policyType, + String version) { + if (PdpState.TERMINATED.equals(pdpGroup.getPdpGroupState())) { + return null; + } + JsonObject supportedPdpGroup = new JsonObject(); + JsonArray supportedSubgroups = new JsonArray(); + supportedPdpGroup.add(pdpGroup.getName(), supportedSubgroups); + pdpGroup.getPdpSubgroups().stream().forEach(pdpSubGroup -> { + if (pdpSubGroup.getSupportedPolicyTypes().stream().anyMatch(policyTypeIdentifier -> + policyType.matches(policyTypeIdentifier.getName().replace(".", "\\.").replace("*", ".*")) + && version.equals(policyTypeIdentifier.getVersion()))) { + supportedSubgroups.add(pdpSubGroup.getPdpType()); + } + }); + return supportedSubgroups.size() == 0 ? null : supportedPdpGroup; + } + + /** + * This method retrieves all supported pdpGroups and subgroups for a specific policy type/version. + * + * @param pdpGroups The PdpGroups object containing all PEF pdp groups info + * @param policyType The policy type that must be used for searching + * @param version THe policy type version that must be used for searching + * @return It returns a JsonObject containing each pdpGroup and subgroups associated + */ + public static JsonObject getSupportedPdpGroupsForModelType(PdpGroups pdpGroups, String policyType, String version) { + JsonObject supportedPdpGroups = new JsonObject(); + JsonArray pdpGroupsArray = new JsonArray(); + supportedPdpGroups.add(SUPPORTED_PDP_GROUPS_INFO, pdpGroupsArray); + + pdpGroups.getGroups().stream().map(pdpGroup -> PdpGroupsAnalyzer.getSupportedPdpSubgroupsForModelType(pdpGroup, + policyType, version)).filter(Objects::nonNull) + .forEach(pdpGroupsArray::add); + + return pdpGroupsArray.size() != 0 ? supportedPdpGroups : null; + } + + /** + * This method updates each element in the policyModelsList given in argument based on the pdpGroups given. + * + * @param policyModelsList The list of Policy Models where each PolicyModel will be updated + * @param pdpGroups The PdpGroups containing all PDP group definition + */ + public static void updatePdpGroupOfPolicyModels(List<PolicyModel> policyModelsList, PdpGroups pdpGroups) { + policyModelsList.parallelStream().forEach(policyModel -> policyModel + .setPolicyPdpGroup(getSupportedPdpGroupsForModelType(pdpGroups, policyModel.getPolicyModelType(), + policyModel.getVersion()))); + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java new file mode 100644 index 000000000..6775eb0c6 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2021 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.clamp.policy.pdpgroup; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.util.stream.StreamSupport; +import org.onap.policy.clamp.clds.util.JsonUtils; +import org.onap.policy.models.pdp.concepts.PdpGroups; + +/** + * This is an utility class that contains methods to work on the different results provided by the PEF. + * Mainly used to aggregate the results. + */ +public class PoliciesPdpMerger { + + private PoliciesPdpMerger() {} + + /** + * This method extract the content of a policy without knowing the key (policy Id). + * This JsonElement normally contains only the policy ID then the content, + * there is only one member in the Json element. + * As this is not really practical to use this method remove that + * nested Json. + * + * @param policyJsonElement The policy as JsonElement + * @return It return the content as JsonObject + */ + public static JsonObject getPolicyContentOutOfJsonElement(JsonElement policyJsonElement) { + mergeJsonElement(policyJsonElement.getAsJsonObject(), policyJsonElement.getAsJsonObject() + .remove(((String) policyJsonElement.getAsJsonObject().keySet().toArray()[0])).getAsJsonObject()); + return policyJsonElement.getAsJsonObject(); + } + + /** + * This method merges 2 JsonElement together. If the jsonToMerge is null nothing is changed. + * + * @param json The initial json that will received the data + * @param jsonToMerge The json that will be added to the first json object + */ + public static void mergeJsonElement(JsonObject json, JsonObject jsonToMerge) { + if (jsonToMerge != null) { + jsonToMerge.entrySet().stream().forEach(entry -> json.add(entry.getKey(), entry.getValue())); + } + } + + /** + * This method merges the result of the policy listing and the associated Pdp Group info. + * It can be seen as an enrichment of the policy listing. + * + * @param jsonPoliciesList The Json containing the policies from the PEF + * @param pdpGroupsJson The json containing the PDP groups info from the PEF + * @return It returns a JsonObject containing the policies list enriched with PdpGroup info + */ + public static JsonObject mergePoliciesAndPdpGroupStates(String jsonPoliciesList, String pdpGroupsJson) { + PdpGroups pdpGroups = JsonUtils.GSON.fromJson(pdpGroupsJson, PdpGroups.class); + JsonObject policiesListJson = + JsonUtils.GSON.fromJson(jsonPoliciesList, JsonObject.class).get("topology_template") + .getAsJsonObject(); + StreamSupport.stream(policiesListJson.get("policies").getAsJsonArray().spliterator(), true) + .forEach(policyJson -> enrichOnePolicy(pdpGroups, getPolicyContentOutOfJsonElement(policyJson))); + return policiesListJson; + } + + /** + * Enrich one policy json node object with pdpGroup info. + * + * @param pdpGroups The pdpGroups from PEF to search the policy + * @param policyJsonNode The policy json node that must be enriched + */ + private static void enrichOnePolicy(PdpGroups pdpGroups, JsonObject policyJsonNode) { + PdpGroupsAnalyzer pdpGroupAnalyzer = new PdpGroupsAnalyzer(pdpGroups); + JsonObject deploymentPdpJson = pdpGroupAnalyzer + .getPdpGroupsForPolicy(policyJsonNode.get("name").getAsString(), + policyJsonNode.get("version").getAsString()); + mergeJsonElement(policyJsonNode, deploymentPdpJson); + + JsonObject supportedPdpGroupsJson = PdpGroupsAnalyzer + .getSupportedPdpGroupsForModelType(pdpGroups, policyJsonNode.get("type").getAsString(), + policyJsonNode.get("type_version").getAsString()); + mergeJsonElement(policyJsonNode, supportedPdpGroupsJson); + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/Dictionary.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/Dictionary.java new file mode 100644 index 000000000..4b01d6902 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/Dictionary.java @@ -0,0 +1,219 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.tosca; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import org.onap.policy.clamp.loop.common.AuditEntity; + +/** + * Represents Dictionary. + */ + +@Entity +@Table(name = "dictionary") +public class Dictionary extends AuditEntity implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701388645L; + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "dictionary_second_level") + private int secondLevelDictionary = 0; + + @Expose + @Column(name = "dictionary_type") + private String subDictionaryType; + + @Expose + @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}) + @JoinTable( + name = "dictionary_to_dictionaryelements", + joinColumns = @JoinColumn(name = "dictionary_name", referencedColumnName = "name"), + inverseJoinColumns = {@JoinColumn( + name = "dictionary_element_short_name", + referencedColumnName = "short_name")}) + private Set<DictionaryElement> dictionaryElements = new HashSet<>(); + + /** + * name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * secondLevelDictionary getter. + * + * @return the secondLevelDictionary + */ + public int getSecondLevelDictionary() { + return secondLevelDictionary; + } + + /** + * secondLevelDictionary setter. + * + * @param secondLevelDictionary the secondLevelDictionary to set + */ + public void setSecondLevelDictionary(int secondLevelDictionary) { + this.secondLevelDictionary = secondLevelDictionary; + } + + /** + * subDictionaryType getter. + * + * @return the subDictionaryType + */ + public String getSubDictionaryType() { + return subDictionaryType; + } + + /** + * subDictionaryType setter. + * + * @param subDictionaryType the subDictionaryType to set + */ + public void setSubDictionaryType(String subDictionaryType) { + this.subDictionaryType = subDictionaryType; + } + + /** + * dictionaryElements getter. + * + * @return the dictionaryElements List of dictionary element + */ + public Set<DictionaryElement> getDictionaryElements() { + return dictionaryElements; + } + + /** + * Method to add a new dictionaryElement to the list. + * + * @param dictionaryElement The dictionary element + */ + public void addDictionaryElements(DictionaryElement dictionaryElement) { + dictionaryElements.add(dictionaryElement); + dictionaryElement.getUsedByDictionaries().add(this); + } + + /** + * Method to set dictionaryElements. + * + * @param dictionaryElements The dictionary elements set + */ + public void setDictionaryElements(Set<DictionaryElement> dictionaryElements) { + this.dictionaryElements = dictionaryElements; + } + + /** + * Method to delete a dictionaryElement from the list. + * + * @param dictionaryElement The dictionary element + */ + public void removeDictionaryElement(DictionaryElement dictionaryElement) { + dictionaryElements.remove(dictionaryElement); + dictionaryElement.getUsedByDictionaries().remove(this); + } + + /** + * Default Constructor. + */ + public Dictionary() { + + } + + /** + * Constructor. + * + * @param name The Dictionary name + * @param secondLevelDictionary defines if dictionary is a secondary level + * @param subDictionaryType defines the type of secondary level dictionary + */ + public Dictionary(String name, int secondLevelDictionary, String subDictionaryType) { + this.name = name; + this.secondLevelDictionary = secondLevelDictionary; + this.subDictionaryType = subDictionaryType; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Dictionary other = (Dictionary) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElement.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElement.java new file mode 100644 index 000000000..ecf4b876c --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElement.java @@ -0,0 +1,254 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.tosca; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import org.onap.policy.clamp.loop.common.AuditEntity; + +/** + * Represents a Dictionary Item. + */ +@Entity +@Table(name = "dictionary_elements") +public class DictionaryElement extends AuditEntity implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701388644L; + + @Id + @Expose + @Column(nullable = false, name = "short_name") + private String shortName; + + @Expose + @Column(nullable = false, name = "name") + private String name; + + @Expose + @Column(nullable = false, name = "description") + private String description; + + @Expose + @Column(nullable = false, name = "type") + private String type; + + @Expose + @Column(nullable = true, name = "subdictionary_name") + private String subDictionary; + + @ManyToMany(mappedBy = "dictionaryElements", fetch = FetchType.EAGER) + private Set<Dictionary> usedByDictionaries = new HashSet<>(); + + /** + * name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * shortName getter. + * + * @return the shortName + */ + public String getShortName() { + return shortName; + } + + /** + * shortName setter. + * + * @param shortName the shortName to set + */ + public void setShortName(String shortName) { + this.shortName = shortName; + } + + /** + * description getter. + * + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * description setter. + * + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * type getter. + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * type setter. + * + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + + /** + * subDictionary getter. + * + * @return the subDictionary + */ + public String getSubDictionary() { + return subDictionary; + } + + /** + * subDictionary setter. + * + * @param subDictionary the subDictionary to set + */ + public void setSubDictionary(String subDictionary) { + this.subDictionary = subDictionary; + } + + /** + * usedByDictionaries getter. + * + * @return the usedByDictionaries + */ + public Set<Dictionary> getUsedByDictionaries() { + return usedByDictionaries; + } + + /** + * usedByDictionaries setter. + * + * @param usedByDictionaries the usedByDictionaries to set + */ + public void setUsedByDictionaries(Set<Dictionary> usedByDictionaries) { + this.usedByDictionaries = usedByDictionaries; + } + + /** + * Default Constructor. + */ + public DictionaryElement() { + } + + /** + * Constructor. + * + * @param name The Dictionary element name + * @param shortName The short name + * @param description The description + * @param type The type of element + * @param subDictionary The sub type + */ + public DictionaryElement(String name, String shortName, String description, String type, + String subDictionary) { + this.name = name; + this.shortName = shortName; + this.description = description; + this.type = type; + this.subDictionary = subDictionary; + } + + /** + * Constructor. + * + * @param name The Dictionary element name + * @param shortName The short name + * @param description The description + * @param type The type of element + * @param subDictionary The sub type + */ + public DictionaryElement(String name, String shortName, String description, String type, + String subDictionary, Set<Dictionary> usedByDictionaries) { + this.name = name; + this.shortName = shortName; + this.description = description; + this.type = type; + this.subDictionary = subDictionary; + this.usedByDictionaries = usedByDictionaries; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((shortName == null) ? 0 : shortName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + DictionaryElement other = (DictionaryElement) obj; + if (shortName == null) { + if (other.shortName != null) { + return false; + } + } else if (!shortName.equals(other.shortName)) { + return false; + } + return true; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElementsRepository.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElementsRepository.java new file mode 100644 index 000000000..0bc50fe1a --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElementsRepository.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.tosca; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DictionaryElementsRepository extends JpaRepository<DictionaryElement, String> { + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryRepository.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryRepository.java new file mode 100644 index 000000000..a2f417d17 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryRepository.java @@ -0,0 +1,40 @@ +/*- + * ============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.policy.clamp.tosca; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface DictionaryRepository extends JpaRepository<Dictionary, String> { + + @Query("SELECT dict.name FROM Dictionary as dict") + List<String> getAllDictionaryNames(); + + @Query("SELECT dict.name FROM Dictionary as dict where dict.secondLevelDictionary = 1") + List<String> getAllSecondaryLevelDictionaryNames(); + +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryService.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryService.java new file mode 100644 index 000000000..849d4baae --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryService.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.tosca; + +import com.google.common.collect.Sets; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.persistence.EntityNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class DictionaryService { + + private final DictionaryRepository dictionaryRepository; + private final DictionaryElementsRepository dictionaryElementsRepository; + + /** + * Constructor. + */ + @Autowired + public DictionaryService(DictionaryRepository dictionaryRepository, + DictionaryElementsRepository dictionaryElementsRepository) { + this.dictionaryRepository = dictionaryRepository; + this.dictionaryElementsRepository = dictionaryElementsRepository; + + } + + public Dictionary saveOrUpdateDictionary(Dictionary dictionary) { + return dictionaryRepository.saveAndFlush(dictionary); + } + + /** + * Creates or Updates Dictionary Element. + * + * @param dictionaryName The Dictionary name + * @param dictionary The Dictionary object with dictionary elements + * @return updated Dictionary object with all dictionary elements + */ + public Dictionary saveOrUpdateDictionaryElement(String dictionaryName, Dictionary dictionary) { + Dictionary dict = getDictionary(dictionaryName); + + Set<DictionaryElement> newDictionaryElements = dictionary.getDictionaryElements(); + + if (newDictionaryElements != null && !newDictionaryElements.isEmpty()) { + Set<DictionaryElement> updatedDictionaryElements = newDictionaryElements.stream() + .map(dictionaryElement -> getAndUpdateDictionaryElement(dict, dictionaryElement)) + .collect(Collectors.toSet()); + + dict.getDictionaryElements().forEach(dictElement -> { + if (!updatedDictionaryElements.contains(dictElement)) { + updatedDictionaryElements.add(dictElement); + } + }); + dict.setDictionaryElements(updatedDictionaryElements); + } + return dictionaryRepository.saveAndFlush(dict); + + } + + private DictionaryElement getAndUpdateDictionaryElement(Dictionary dictionary, + DictionaryElement element) { + return dictionaryElementsRepository + .save(dictionaryElementsRepository.findById(element.getShortName()) + .map(p -> updateDictionaryElement(p, element, dictionary)) + .orElse(new DictionaryElement(element.getName(), element.getShortName(), + element.getDescription(), element.getType(), element.getSubDictionary(), + Sets.newHashSet(dictionary)))); + } + + public void deleteDictionary(Dictionary dictionary) { + dictionaryRepository.delete(dictionary); + } + + public void deleteDictionary(String dictionaryName) { + dictionaryRepository.deleteById(dictionaryName); + } + + public List<Dictionary> getAllDictionaries() { + return dictionaryRepository.findAll(); + } + + public List<String> getAllSecondaryLevelDictionaryNames() { + return dictionaryRepository.getAllSecondaryLevelDictionaryNames(); + } + + public Dictionary getDictionary(String dictionaryName) { + return dictionaryRepository.findById(dictionaryName).orElseThrow( + () -> new EntityNotFoundException("Couldn't find Dictionary named: " + dictionaryName)); + } + + /** + * Deletes a dictionary element from Dictionary by shortName. + * + * @param dictionaryName The dictionary name + * @param dictionaryElementShortName the dictionary Element Short name + */ + public void deleteDictionaryElement(String dictionaryName, String dictionaryElementShortName) { + if (dictionaryRepository.existsById(dictionaryName)) { + DictionaryElement element = + dictionaryElementsRepository.findById(dictionaryElementShortName).orElse(null); + if (element != null) { + Dictionary dict = getDictionary(dictionaryName); + dict.removeDictionaryElement(element); + dictionaryRepository.saveAndFlush(dict); + } + } + } + + private DictionaryElement updateDictionaryElement(DictionaryElement oldDictionaryElement, + DictionaryElement newDictionaryElement, Dictionary dictionary) { + oldDictionaryElement.setName(newDictionaryElement.getName()); + oldDictionaryElement.setDescription(newDictionaryElement.getDescription()); + oldDictionaryElement.setType(newDictionaryElement.getType()); + oldDictionaryElement.setSubDictionary(newDictionaryElement.getSubDictionary()); + oldDictionaryElement.getUsedByDictionaries().add(dictionary); + return oldDictionaryElement; + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/util/PassDecoder.java b/runtime/src/main/java/org/onap/policy/clamp/util/PassDecoder.java new file mode 100644 index 000000000..b8e90e3d0 --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/util/PassDecoder.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2019, 2021 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.clamp.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import org.onap.aaf.cadi.Symm; +import org.onap.policy.clamp.clds.util.ResourceFileUtils; + +/** + * PassDecoder for decrypting the truststore and keystore password. + */ +public class PassDecoder { + + private PassDecoder() { + } + + /** + * Used to log PassDecoder class. + */ + private static final EELFLogger logger = EELFManager.getInstance().getLogger(PassDecoder.class); + + /** + * Decode the password. + * + * @param encryptedPass The encrypted password + * @param keyFileName The key file name in String + */ + public static String decode(String encryptedPass, String keyFileName) { + if (null == keyFileName) { + logger.debug("Key file is not defined, thus password will not be decrypted"); + return encryptedPass; + } + if (null == encryptedPass) { + logger.error("Encrypted password is not defined"); + return null; + } + try { + return Symm.obtain(ResourceFileUtils.getResourceAsStream(keyFileName)).depass(encryptedPass); + } catch (IOException e) { + logger.error("Exception occurred during the key decryption", e); + return null; + } + } +} diff --git a/runtime/src/main/java/org/onap/policy/clamp/util/SemanticVersioning.java b/runtime/src/main/java/org/onap/policy/clamp/util/SemanticVersioning.java new file mode 100644 index 000000000..58367193f --- /dev/null +++ b/runtime/src/main/java/org/onap/policy/clamp/util/SemanticVersioning.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.clamp.util; + +/** + * This class is the base class for object that requires semantic versioning. + * ... This class supports also a.b.c.d... etc ... as a version. + */ +public class SemanticVersioning { + public static final int BEFORE = -1; + public static final int EQUAL = 0; + public static final int AFTER = 1; + public static final String DEFAULT_VERSION = "1.0.0"; + + /** + * The compare method that compare arg0 to arg1. + * + * @param arg0 A version in string for semantic versioning (a.b.c.d...) + * @param arg1 A version in string for semantic versioning (a.b.c.d...) + * @return objects (arg0, arg1) given as parameters. It returns the value: 0: if + * (arg0==arg1) -1: if (arg0 < arg1) 1: if (arg0 > arg1) + */ + public static int compare(String arg0, String arg1) { + + if (arg0 == null && arg1 == null) { + return EQUAL; + } + if (arg0 == null) { + return BEFORE; + } + if (arg1 == null) { + return AFTER; + } + String[] arg0Array = arg0.split("\\."); + String[] arg1Array = arg1.split("\\."); + + int smalestStringLength = Math.min(arg0Array.length, arg1Array.length); + + for (int currentVersionIndex = + 0; currentVersionIndex < smalestStringLength; ++currentVersionIndex) { + if (Integer.parseInt(arg0Array[currentVersionIndex]) < Integer + .parseInt(arg1Array[currentVersionIndex])) { + return BEFORE; + } else if (Integer.parseInt(arg0Array[currentVersionIndex]) > Integer + .parseInt(arg1Array[currentVersionIndex])) { + return AFTER; + } + // equals, so do not return anything, continue + } + if (arg0Array.length == arg1Array.length) { + return EQUAL; + } else { + return Integer.compare(arg0Array.length, arg1Array.length); + } + } + + /** + * Method to increment a version from its current version. + * + * @param currentVersion The current Version + * @return the increment version string + */ + public static String incrementMajorVersion(String currentVersion) { + if (currentVersion == null || currentVersion.isEmpty()) { + return DEFAULT_VERSION; + } + String[] versionArray = currentVersion.split("\\."); + return String.valueOf(Integer.parseInt(versionArray[0]) + 1) + ".0.0"; + } +} |