diff options
author | Patrick Brady <pb071s@att.com> | 2017-02-15 23:11:26 -0800 |
---|---|---|
committer | Patrick Brady <pb071s@att.com> | 2017-02-15 23:13:06 -0800 |
commit | 1c192d2dd68724e292b6a30f463085a262e1e813 (patch) | |
tree | d0e2b3a396e169863cd0efaa835c8675e9d5aaac /appc-adapters/appc-iaas-adapter | |
parent | c69ba05c7508aa7d7f675189a45c8c87569369ef (diff) |
Moving all files to root directory
Change-Id: Ica5535fd6ec85f350fe1640b42137b49f83f10f0
Signed-off-by: Patrick Brady <pb071s@att.com>
Diffstat (limited to 'appc-adapters/appc-iaas-adapter')
52 files changed, 10087 insertions, 0 deletions
diff --git a/appc-adapters/appc-iaas-adapter/.gitignore b/appc-adapters/appc-iaas-adapter/.gitignore new file mode 100644 index 000000000..d027396de --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/.gitignore @@ -0,0 +1 @@ +/.settings/ diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/.gitignore b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/.gitignore new file mode 100644 index 000000000..b33175423 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/.gitignore @@ -0,0 +1,4 @@ +/bin/ +/target/ +/.settings/ +/build/ diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/pom.xml b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/pom.xml new file mode 100644 index 000000000..967c34858 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/pom.xml @@ -0,0 +1,222 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-iaas-adapter</artifactId> + <version>1.0.0</version> + </parent> + + <artifactId>appc-iaas-adapter-bundle</artifactId> + <packaging>bundle</packaging> + <name>IaaS Adapter - bundle</name> + + <dependencies> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-common</artifactId> + <version>${project.version}</version> + <classifier>jar-with-dependencies</classifier> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-common</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>javax</groupId> + <artifactId>javaee-api</artifactId> + <version>7.0</version> + </dependency> + + <dependency> + <groupId>com.att.cdp</groupId> + <artifactId>cdp-pal-common</artifactId> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>com.att.cdp</groupId> + <artifactId>cdp-pal-openstack</artifactId> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + </dependency> + + <!-- Jersey support needed for OpenStack connector and API version logic --> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-client</artifactId> + </dependency> + + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-json</artifactId> + </dependency> + + <dependency> + <groupId>javax.xml.bind</groupId> + <artifactId>jaxb-api</artifactId> + <version>2.1</version> + </dependency> + + <dependency> + <groupId>javax.xml</groupId> + <artifactId>jaxp-api</artifactId> + <version>1.4.2</version> + </dependency> + + <!-- Needed to run test cases --> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-common</artifactId> + <version>2.9.1</version> + </dependency> + + <dependency> + <groupId>org.codehaus.jackson</groupId> + <artifactId>jackson-jaxrs</artifactId> + <version>1.9.12</version> + </dependency> + + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>4.5.1</version> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.openecomp.sdnc.core</groupId> + <artifactId>sli-common</artifactId> + <scope>compile</scope> + <!-- Added exclusion to prevent missing dependency issue on dblib --> + <exclusions> + <exclusion> + <groupId>org.openecomp.sdnc.core</groupId> + <artifactId>dblib-provider</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>org.openecomp.sdnc.core</groupId> + <artifactId>sli-provider</artifactId> + <scope>compile</scope> + <!-- Added exclusion to prevent missing dependency issue on dblib --> + <exclusions> + <exclusion> + <groupId>org.openecomp.sdnc.core</groupId> + <artifactId>dblib-provider</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>equinoxSDK381</groupId> + <artifactId>org.eclipse.osgi</artifactId> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + </dependency> + + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + <version>5.1.31</version> + <type>jar</type> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>com.vmware</groupId> + <artifactId>vijava</artifactId> + <version>5.1</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>xerces</groupId> + <artifactId>xerces</artifactId> + <version>2.4.0</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + <version>${apache.httpcomponents.version}</version> + </dependency> + + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.2</version> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName>appc-iaas-adapter</Bundle-SymbolicName> + <Bundle-Activator>org.openecomp.appc.adapter.iaas.AppcProviderAdapterActivator</Bundle-Activator> + <Export-Package>org.openecomp.appc.adapter.iaas</Export-Package> + <Import-Package>org.openecomp.sdnc.sli.*,org.osgi.framework.*,org.slf4j.*,com.vmware.*,org.apache.xerces.*,javax.net.*,javax.net.ssl.*,org.xml.sax.*,javax.xml.bind.*,javax.naming.*</Import-Package> + <Embed-Dependency>*;scope=compile|runtime;artifactId=!sli-common|org.eclipse.osgi|slf4j-api|jcl-over-slf4j|mysql-connector-java|xml-apis</Embed-Dependency> + <Embed-Transitive>true</Embed-Transitive> + </instructions> + + <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation> + </configuration> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>NonSlowTests</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <excludedGroups>org.openecomp.appc.adapter.iaas.impl.TestProviderAdapterImpl</excludedGroups> + </configuration> + </plugin> + </plugins> + </build> + </profile> + </profiles> +</project> diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/AppcProviderAdapterActivator.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/AppcProviderAdapterActivator.java new file mode 100644 index 000000000..fa60c67a9 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/AppcProviderAdapterActivator.java @@ -0,0 +1,143 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas; + +import org.openecomp.appc.Constants; +import org.openecomp.appc.adapter.iaas.impl.ProviderAdapterImpl; +import org.openecomp.appc.configuration.Configuration; +import org.openecomp.appc.configuration.ConfigurationFactory; +import org.openecomp.appc.i18n.Msg; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +/** + * This activator is used to initialize and terminate the connection pool to one or more providers. + * <p> + * The CDP abstraction layer supports multiple types of providers, with each provider supporting multiple tenants. The + * "connection" to a specific tenant on a specific provider is represented by a "context" object. These context objects + * are authenticated to a specific tenant on the provider, but can be reused from one request to another. Contexts are + * slow to set up and are resource intensive, so they are cached. However, the contexts for a specific tenant on a + * specific provider must be cached separately. + * </p> + * <p> + * Activation of the bundle creates an empty cache which is organized first by provider type, then by tenant name, with + * the contents being an empty pool of contexts for that provider/tenant combination. The pool is created on first use, + * and retained for as long as the bundle is active. + * </p> + * <p> + * When the bundle is deactivated, the cache is torn down with all contexts being closed. + * </p> + */ +public class AppcProviderAdapterActivator implements BundleActivator { + + /** + * The bundle registration + */ + private ServiceRegistration registration = null; + + /** + * The reference to the actual implementation object that implements the services + */ + private ProviderAdapter adapter; + + /** + * The logger to be used + */ + // private static final Logger LOG = LoggerFactory.getLogger(AppcProviderAdapterActivator.class); + private static final EELFLogger logger = EELFManager.getInstance().getLogger(AppcProviderAdapterActivator.class); + + /** + * The configuration object used to configure this bundle + */ + private Configuration configuration; + + /** + * Called when this bundle is started so the Framework can perform the bundle-specific activities necessary to start + * this bundle. This method can be used to register services or to allocate any resources that this bundle needs. + * <p> + * This method must complete and return to its caller in a timely manner. + * </p> + * + * @param context + * The execution context of the bundle being started. + * @throws java.lang.Exception + * If this method throws an exception, this bundle is marked as stopped and the Framework will remove + * this bundle's listeners, unregister all services registered by this bundle, and release all services + * used by this bundle. + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + logger.info("Starting bundle " + getName()); + + configuration = ConfigurationFactory.getConfiguration(); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + logger.info(Msg.COMPONENT_INITIALIZING, appName, "IAAS adapter"); + adapter = new ProviderAdapterImpl(configuration.getProperties()); + if (registration == null) { + logger.info(Msg.REGISTERING_SERVICE, appName, adapter.getAdapterName(), + ProviderAdapter.class.getSimpleName()); + registration = context.registerService(ProviderAdapter.class, adapter, null); + } + + logger.info(Msg.COMPONENT_INITIALIZED, appName, "IAAS adapter"); + } + + /** + * Called when this bundle is stopped so the Framework can perform the bundle-specific activities necessary to stop + * the bundle. In general, this method should undo the work that the BundleActivator.start method started. There + * should be no active threads that were started by this bundle when this bundle returns. A stopped bundle must not + * call any Framework objects. + * <p> + * This method must complete and return to its caller in a timely manner. + * </p> + * + * @param context + * The execution context of the bundle being stopped. + * @throws java.lang.Exception + * If this method throws an exception, the bundle is still marked as stopped, and the Framework will + * remove the bundle's listeners, unregister all services registered by the bundle, and release all + * services used by the bundle. * + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + logger.info("Stopping bundle " + getName()); + + if (registration != null) { + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + logger.info(Msg.COMPONENT_TERMINATING, appName, "IAAS adapter"); + logger.info(Msg.UNREGISTERING_SERVICE, appName, adapter.getAdapterName()); + registration.unregister(); + registration = null; + logger.info(Msg.COMPONENT_TERMINATED, appName, "IAAS adapter"); + } + } + + public String getName() { + return "APPC IaaS adapter"; + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/ProviderAdapter.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/ProviderAdapter.java new file mode 100644 index 000000000..f7a8b30ed --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/ProviderAdapter.java @@ -0,0 +1,294 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas; + +import java.util.Map; + +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.exceptions.UnknownProviderException; +import com.att.cdp.zones.model.Image; +import com.att.cdp.zones.model.Server; +import com.att.cdp.zones.model.Stack; +import org.openecomp.sdnc.sli.SvcLogicContext; +import org.openecomp.sdnc.sli.SvcLogicJavaPlugin; + +/** + * This interface defines the operations that the provider adapter exposes. + * <p> + * This interface defines static constant property values that can be used to configure the adapter. These constants are + * prefixed with the name PROPERTY_ to indicate that they are configuration properties. These properties are read from + * the configuration file for the adapter and are used to define the providers, identity service URLs, and other + * information needed by the adapter to interface with an IaaS provider. + * </p> + */ +public interface ProviderAdapter extends SvcLogicJavaPlugin { + + /** + * The type of provider to be accessed to locate and operate on a virtual machine instance. This is used to load the + * correct provider support through the CDP IaaS abstraction layer and can be OpenStackProvider, BareMetalProvider, + * or any other supported provider type. + */ + static final String PROPERTY_PROVIDER_TYPE = "org.openecomp.appc.provider.type"; + + /** + * The adapter maintains a cache of providers organized by the name of the provider, not its type. This is + * equivalent to the system or installation name. All regions within the same installation are assumed to be the + * same type. + */ + static final String PROPERTY_PROVIDER_NAME = "org.openecomp.appc.provider.name"; + + /** + * The fully-qualified URL of the instance to be manipulated as it is known to the provider. + */ + static final String PROPERTY_INSTANCE_URL = "org.openecomp.appc.instance.url"; + + /** + * The fully-qualified URL of the instance to be manipulated as it is known to the provider. + */ + static final String PROPERTY_IDENTITY_URL = "org.openecomp.appc.identity.url"; + /** + * heat stack id to perform operation on stack + */ + static final String PROPERTY_STACK_ID = "org.openecomp.appc.stack.id"; + + static final String PROPERTY_SNAPSHOT_ID = "snapshot.id"; + + static final String PROPERTY_INPUT_SNAPSHOT_ID = "org.openecomp.appc.snapshot.id"; + + static final String DG_OUTPUT_PARAM_NAMESPACE = "output."; + + /** + * This method is used to restart an existing virtual machine given the fully qualified URL of the machine. + * <p> + * This method is invoked from a directed graph as an <code>Executor</code> node. This means that the parameters + * passed to the method are passed as properties in a map. This method expects the following properties to be + * defined: + * <dl> + * <dt>org.openecomp.appc.provider.type</dt> + * <dd>The appropriate provider type, such as <code>OpenStackProvider</code>. This is used by the CDP IaaS + * abstraction layer to dynamically load and open a connection to the appropriate provider type. All CDP supported + * provider types are legal.</dd> + * <dt>org.openecomp.appc.instance.url</dt> + * <dd>The fully qualified URL of the instance to be restarted, as it is known to the provider (i.e., the self-link + * URL of the server)</dd> + * </dl> + * </p> + * + * @param properties + * A map of name-value pairs that supply the parameters needed by this method. The properties needed are + * defined above. + * @param context + * The service logic context of the graph being executed. + * @return The <code>Server</code> object that represents the VM being restarted. The returned server object can be + * inspected for the final state of the server once the restart has been completed. The method does not + * return until the restart has either completed or has failed. + * @throws APPCException + * If the server cannot be restarted for some reason + */ + Server restartServer(Map<String, String> properties, SvcLogicContext context) throws APPCException; + + /** + * This method is used to stop the indicated server + * <p> + * This method is invoked from a directed graph as an <code>Executor</code> node. This means that the parameters + * passed to the method are passed as properties in a map. This method expects the following properties to be + * defined: + * <dl> + * <dt>org.openecomp.appc.provider.type</dt> + * <dd>The appropriate provider type, such as <code>OpenStackProvider</code>. This is used by the CDP IaaS + * abstraction layer to dynamically load and open a connection to the appropriate provider type. All CDP supported + * provider types are legal.</dd> + * <dt>org.openecomp.appc.instance.url</dt> + * <dd>The fully qualified URL of the instance to be stopped, as it is known to the provider (i.e., the self-link + * URL of the server)</dd> + * </dl> + * </p> + * + * @param properties + * A map of name-value pairs that supply the parameters needed by this method. The properties needed are + * defined above. + * @param context + * The service logic context of the graph being executed. + * @return The <code>Server</code> object that represents the VM being stopped. The returned server object can be + * inspected for the final state of the server once the stop has been completed. The method does not return + * until the stop has either completed or has failed. + * @throws APPCException + * If the server cannot be stopped for some reason + */ + Server stopServer(Map<String, String> properties, SvcLogicContext context) throws APPCException; + + /** + * This method is used to start the indicated server + * <p> + * This method is invoked from a directed graph as an <code>Executor</code> node. This means that the parameters + * passed to the method are passed as properties in a map. This method expects the following properties to be + * defined: + * <dl> + * <dt>org.openecomp.appc.provider.type</dt> + * <dd>The appropriate provider type, such as <code>OpenStackProvider</code>. This is used by the CDP IaaS + * abstraction layer to dynamically load and open a connection to the appropriate provider type. All CDP supported + * provider types are legal.</dd> + * <dt>org.openecomp.appc.instance.url</dt> + * <dd>The fully qualified URL of the instance to be started, as it is known to the provider (i.e., the self-link + * URL of the server)</dd> + * </dl> + * </p> + * + * @param properties + * A map of name-value pairs that supply the parameters needed by this method. The properties needed are + * defined above. + * @param context + * The service logic context of the graph being executed. + * @return The <code>Server</code> object that represents the VM being started. The returned server object can be + * inspected for the final state of the server once the start has been completed. The method does not return + * until the start has either completed or has failed. + * @throws APPCException + * If the server cannot be started for some reason + */ + Server startServer(Map<String, String> properties, SvcLogicContext context) throws APPCException; + + /** + * This method is used to rebuild the indicated server + * <p> + * This method is invoked from a directed graph as an <code>Executor</code> node. This means that the parameters + * passed to the method are passed as properties in a map. This method expects the following properties to be + * defined: + * <dl> + * <dt>org.openecomp.appc.provider.type</dt> + * <dd>The appropriate provider type, such as <code>OpenStackProvider</code>. This is used by the CDP IaaS + * abstraction layer to dynamically load and open a connection to the appropriate provider type. All CDP supported + * provider types are legal.</dd> + * <dt>org.openecomp.appc.instance.url</dt> + * <dd>The fully qualified URL of the instance to be rebuilt, as it is known to the provider (i.e., the self-link + * URL of the server)</dd> + * </dl> + * </p> + * + * @param properties + * A map of name-value pairs that supply the parameters needed by this method. The properties needed are + * defined above. + * @param context + * The service logic context of the graph being executed. + * @return The <code>Server</code> object that represents the VM being rebuilt. The returned server object can be + * inspected for the final state of the server once the rebuild has been completed. The method does not + * return until the rebuild has either completed or has failed. + * @throws APPCException + * If the server cannot be rebuilt for some reason + */ + Server rebuildServer(Map<String, String> properties, SvcLogicContext context) throws APPCException; + + /** + * This method is used to terminate the indicated server + * <p> + * This method is invoked from a directed graph as an <code>Executor</code> node. This means that the parameters + * passed to the method are passed as properties in a map. This method expects the following properties to be + * defined: + * <dl> + * <dt>org.openecomp.appc.provider.type</dt> + * <dd>The appropriate provider type, such as <code>OpenStackProvider</code>. This is used by the CDP IaaS + * abstraction layer to dynamically load and open a connection to the appropriate provider type. All CDP supported + * provider types are legal.</dd> + * <dt>org.openecomp.appc.instance.url</dt> + * <dd>The fully qualified URL of the instance to be terminate, as it is known to the provider (i.e., the self-link + * URL of the server)</dd> + * </dl> + * </p> + * + * @param properties + * A map of name-value pairs that supply the parameters needed by this method. The properties needed are + * defined above. + * @param context + * The service logic context of the graph being executed. + * @return The <code>Server</code> object that represents the VM being rebuilt. The returned server object can be + * inspected for the final state of the server once the rebuild has been completed. The method does not + * return until the rebuild has either completed or has failed. + * @throws APPCException + * If the server cannot be terminate for some reason + */ + Server terminateServer(Map<String, String> properties, SvcLogicContext context) throws APPCException; + + /** + * Returns the symbolic name of the adapter + * + * @return The adapter name + */ + String getAdapterName(); + + Server evacuateServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException; + + Server migrateServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException; + + Server vmStatuschecker(Map<String, String> params, SvcLogicContext ctx) throws APPCException; + + Stack terminateStack(Map<String, String> params, SvcLogicContext ctx) throws APPCException; + + Stack snapshotStack(Map<String, String> params, SvcLogicContext ctx) throws APPCException; + + Stack restoreStack(Map<String, String> params, SvcLogicContext ctx) throws APPCException; + + /** + * This method is used to do the lookup of the indicated server + * <p> + * This method is invoked from a directed graph as an <code>Executor</code> node. This means that the parameters + * passed to the method are passed as properties in a map. This method expects the following properties to be + * defined: + * <dl> + * <dt>org.openecomp.appc.provider.type</dt> + * <dd>The appropriate provider type, such as <code>OpenStackProvider</code>. This is used by the CDP IaaS + * abstraction layer to dynamically load and open a connection to the appropriate provider type. All CDP supported + * provider types are legal.</dd> + * <dt>org.openecomp.appc.instance.url</dt> + * <dd>The fully qualified URL of the instance to be lookup, as it is known to the provider (i.e., the self-link URL + * of the server)</dd> + * </dl> + * </p> + * + * @param properties + * A map of name-value pairs that supply the parameters needed by this method. The properties needed are + * defined above. + * @param context + * The service logic context of the graph being executed. + * @return The <code>Server</code> object that represents the VM being rebuilt. The returned server object can be + * inspected for the final state of the server once the rebuild has been completed. The method does not + * return until the rebuild has either completed or has failed. + * @throws APPCException + * If the server cannot be found for some reason + */ + Server lookupServer(Map<String, String> properties, SvcLogicContext context) throws APPCException; + + /** + * The + * + * @param params + * A map of name-value pairs that supply the parameters needed by this method. The properties needed are + * defined above. + * @param ctx + * The service logic context of the graph being executed. + * @return The <code>Image</code> object that represents the VM being restarted. The returned server object can be + * inspected for the final state of the server once the restart has been completed. The method does not + * return until the restart has either completed or has failed. + * @throws APPCException + * If the server cannot be restarted for some reason + */ + Image createSnapshot(Map<String, String> params, SvcLogicContext ctx) throws APPCException; + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/IdentityURL.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/IdentityURL.java new file mode 100644 index 000000000..e9391fcb8 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/IdentityURL.java @@ -0,0 +1,120 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This class is used to parse the VM URL returned from OpenStack and extract all of the constituent parts. + */ +public class IdentityURL { + /** + * The regular expression pattern used to parse the URL. Capturing groups are used to identify and extract the + * various component parts of the URL. + */ + private static Pattern pattern = Pattern.compile("(\\p{Alnum}+)://([^/:]+)(?::([0-9]+))?/(v[0-9\\.]+)/?"); + + /** + * The URL scheme or protocol, such as HTTP or HTTPS + */ + private String scheme; + + /** + * The host name or ip address + */ + private String host; + + /** + * The port number, or null if no port is defined + */ + private String port; + + /** + * The version of the service + */ + private String version; + + /** + * A private default constructor prevents instantiation by any method other than the factory method + * + * @see #parseURL(String) + */ + private IdentityURL() { + + } + + /** + * This static method is used to parse the provided server URL string and return a parse results object (VMURL) + * which represents the state of the parse. + * + * @param serverUrl + * The server URL to be parsed + * @return The VMURL parse results object, or null if the URL was not valid or null. + */ + public static IdentityURL parseURL(String serverUrl) { + IdentityURL obj = null; + if (serverUrl != null) { + Matcher matcher = pattern.matcher(serverUrl.trim()); + if (matcher.matches()) { + obj = new IdentityURL(); + obj.scheme = matcher.group(1); + obj.host = matcher.group(2); + obj.port = matcher.group(3); + obj.version = matcher.group(4); + } + } + + return obj; + } + + /** + * @return The URL scheme + */ + public String getScheme() { + return scheme; + } + + /** + * @return The URL host + */ + public String getHost() { + return host; + } + + /** + * @return The URL port, or null if no port was defined + */ + public String getPort() { + return port; + } + + public String getVersion() { + return version; + } + + @Override + public String toString() { + return String.format("%s://%s:%s/%s", scheme, host, port, version); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/ProviderAdapterImpl.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/ProviderAdapterImpl.java new file mode 100644 index 000000000..b1bba0918 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/ProviderAdapterImpl.java @@ -0,0 +1,2723 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import com.woorea.openstack.base.client.OpenStackBaseException; +import com.woorea.openstack.heat.Heat; +import org.glassfish.grizzly.http.util.HttpStatus; +import org.openecomp.appc.Constants; +import org.openecomp.appc.adapter.iaas.ProviderAdapter; +import org.openecomp.appc.adapter.openstack.heat.SnapshotResource; +import org.openecomp.appc.adapter.openstack.heat.StackResource; +import org.openecomp.appc.adapter.openstack.heat.model.CreateSnapshotParams; +import org.openecomp.appc.adapter.openstack.heat.model.Snapshot; +import org.openecomp.appc.configuration.Configuration; +import org.openecomp.appc.configuration.ConfigurationFactory; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.exceptions.UnknownProviderException; +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.pool.Pool; +import org.openecomp.appc.pool.PoolExtensionException; +import org.openecomp.appc.util.StructuredPropertyHelper; +import org.openecomp.appc.util.StructuredPropertyHelper.Node; +import com.att.cdp.exceptions.*; +import com.att.cdp.openstack.OpenStackContext; +import com.att.cdp.openstack.connectors.HeatConnector; +import com.att.cdp.openstack.util.ExceptionMapper; +import com.att.cdp.pal.util.StringHelper; +import com.att.cdp.zones.*; +import com.att.cdp.zones.model.Image; +import com.att.cdp.zones.model.Server; +import com.att.cdp.zones.model.ServerBootSource; +import com.att.cdp.zones.model.Stack; +import com.att.cdp.zones.model.Server.Status; +import com.att.cdp.zones.spi.AbstractService; +import com.att.cdp.zones.spi.RequestState; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.att.eelf.i18n.EELFResourceManager; +import org.openecomp.sdnc.sli.SvcLogicContext; +import org.slf4j.MDC; + +import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME; + +import java.io.IOException; +import java.net.URI; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Pattern; + +/** + * This class implements the {@link ProviderAdapter} interface. This interface defines the behaviors that our service + * provides. + */ +@SuppressWarnings("javadoc") +public class ProviderAdapterImpl implements ProviderAdapter { + + /** + * The name of the adapter + */ + @SuppressWarnings("nls") + private static final String ADAPTER_NAME = "Appc IaaS Adapter"; + + /** + * The username and password to use for dynamically created connections + */ + private static String DEFAULT_USER; + private static String DEFAULT_PASS; + + /** + * The constant used to define the adapter name in the mapped diagnostic context + */ + @SuppressWarnings("nls") + private static final String MDC_ADAPTER = "adapter"; + + /** + * The constant used to define the service name in the mapped diagnostic context + */ + @SuppressWarnings("nls") + static final String MDC_SERVICE = "service"; + + /** + * The constant for the status code for a failed outcome + */ + @SuppressWarnings("nls") + private static final String OUTCOME_FAILURE = "failure"; + + /** + * The constant for the status code for a successful outcome + */ + @SuppressWarnings("nls") + private static final String OUTCOME_SUCCESS = "success"; + + /** + * A constant for the property token "provider" used in the structured property specifications + */ + @SuppressWarnings("nls") + private static final String PROPERTY_PROVIDER = "provider"; + + /** + * A constant for the property token "identity" used in the structured property specifications + */ + @SuppressWarnings("nls") + private static final String PROPERTY_PROVIDER_IDENTITY = "identity"; + + /** + * A constant for the property token "tenant" used in the structured property specifications + */ + @SuppressWarnings("nls") + private static final String PROPERTY_PROVIDER_TENANT = "tenant"; + + /** + * A constant for the property token "tenant name" used in the structured property specifications + */ + @SuppressWarnings("nls") + private static final String PROPERTY_PROVIDER_TENANT_NAME = "name"; + + /** + * A constant for the property token "password" used in the structured property specifications + */ + @SuppressWarnings("nls") + private static final String PROPERTY_PROVIDER_TENANT_PASSWORD = "password"; // NOSONAR + + /** + * A constant for the property token "userid" used in the structured property specifications + */ + @SuppressWarnings("nls") + private static final String PROPERTY_PROVIDER_TENANT_USERID = "userid"; + + /** + * A constant for the property token "type" used in the structured property specifications + */ + @SuppressWarnings("nls") + private static final String PROPERTY_PROVIDER_TYPE = "type"; + + /** + * The name of the service to evacuate a server + */ + @SuppressWarnings("nls") + private static final String EVACUATE_SERVICE = "evacuateServer"; + + /** + * The name of the service to migrate a server + */ + @SuppressWarnings("nls") + private static final String MIGRATE_SERVICE = "migrateServer"; + + /** + * The name of the service to rebuild a server + */ + @SuppressWarnings("nls") + private static final String REBUILD_SERVICE = "rebuildServer"; + + /** + * The name of the service to restart a server + */ + @SuppressWarnings("nls") + private static final String RESTART_SERVICE = "restartServer"; + + /** + * The name of the service to check status of a server + */ + @SuppressWarnings("nls") + private static final String VMSTATUSCHECK_SERVICE = "vmStatuschecker"; + + + /** + * The name of the service to restart a server + */ + @SuppressWarnings("nls") + private static final String SNAPSHOT_SERVICE = "createSnapshot"; + + /** + * The name of the service to terminate a stack + */ + @SuppressWarnings("nls") + private static final String TERMINATE_STACK = "terminateStack"; + + /** + * The name of the service to snapshot a stack + */ + @SuppressWarnings("nls") + private static final String SNAPSHOT_STACK = "snapshotStack"; + + /** + * The name of a service to start a server + */ + @SuppressWarnings("nls") + private static final String START_SERVICE = "startServer"; + + /** + * The name of the service to stop a server + */ + @SuppressWarnings("nls") + private static final String STOP_SERVICE = "stopServer"; + + /** + * The name of the service to stop a server + */ + @SuppressWarnings("nls") + private static final String TERMINATE_SERVICE = "terminateServer"; + + /** + * The name of the service to lookup a server + */ + @SuppressWarnings("nls") + private static final String LOOKUP_SERVICE = "lookupServer"; + + /** + * The logger to be used + */ + private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderAdapterImpl.class); + + private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + /** + * The constant for a left parenthesis + */ + private static final char LPAREN = '('; + + /** + * The constant for a new line control code + */ + private static final char NL = '\n'; + + /** + * The constant for a single quote + */ + private static final char QUOTE = '\''; + + /** + * The constant for a right parenthesis + */ + private static final char RPAREN = ')'; + + /** + * The constant for a space + */ + private static final char SPACE = ' '; + + /** + * A reference to the adapter configuration object. + */ + private Configuration configuration; + + /** + * A cache of providers that are predefined. + */ + private Map<String /* provider name */, ProviderCache> providerCache; + + /** + * A list of valid initial VM statuses for a migrate operations + */ + private static final Collection<Status> migratableStatuses = Arrays.asList(Status.READY, Status.RUNNING, Status.SUSPENDED); + + /** + * This default constructor is used as a work around because the activator wasnt getting called + */ + @SuppressWarnings("all") + public ProviderAdapterImpl() { + initialize(); + + } + + /** + * This constructor is used primarily in the test cases to bypass initialization of the adapter for isolated, + * disconnected testing + * + * @param initialize + * True if the adapter is to be initialized, can false if not + */ + @SuppressWarnings("all") + public ProviderAdapterImpl(boolean initialize) { + configuration = ConfigurationFactory.getConfiguration(); + if (initialize) { + initialize(); + } + } + + /** + * @param props + * not used + */ + public ProviderAdapterImpl(@SuppressWarnings("unused") Properties props) { + initialize(); + + } + + /** + * Returns the symbolic name of the adapter + * + * @return The adapter name + * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#getAdapterName() + */ + @Override + public String getAdapterName() { + return configuration.getProperty(Constants.PROPERTY_ADAPTER_NAME); + } + + @SuppressWarnings("nls") + @Override + public Image createSnapshot(Map<String, String> params, SvcLogicContext ctx) throws APPCException { + Image snapshot = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, SNAPSHOT_SERVICE); + MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Snapshot"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + logger.info(Msg.SNAPSHOTING_SERVER, appName); + String msg; + + try { + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + debugParameters(params); + debugContext(ctx); + + VMURL vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); + String identStr = (ident == null) ? null : ident.toString(); + + Context context = null; + try { + context = getContext(rc, vm_url, identStr); + if (context != null) { + Server server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + + if (hasImageAccess(rc, context)) { + snapshot = createSnapshot(rc, server); + doSuccess(rc); + } else { + msg = EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(), + "Accessing Image Service Failed"); + logger.error(msg); + doFailure(rc, HttpStatus.FORBIDDEN_403, msg); + } + context.close(); + } + } catch (ResourceNotFoundException e) { + msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + } catch (Throwable t) { + msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + SNAPSHOT_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + doFailure(rc, e.getStatus(), e.getMessage()); + } + return snapshot; + } + + private boolean validateVM(RequestContext rc, String appName, String vm_url, VMURL vm) + throws RequestFailedException { + String msg; + if (vm == null) { + msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + return true; + } + validateVMURL(vm); + return false; + } + + private Image createSnapshot(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + Context context = server.getContext(); + Provider provider = context.getProvider(); + ImageService service = context.getImageService(); // Already checked access by this point + + String snapshotName = generateSnapshotName(server.getName()); + + logger.info(String.format("Creating snapshot of server %s (%s) with name %s", server.getName(), server.getId(), + snapshotName)); + + // Request Snapshot + String msg; + while (rc.attempt()) { + try { + server.createSnapshot(snapshotName); + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Stop Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + + // Locate snapshot image + Image snapshot = null; + while (rc.attempt()) { + try { + snapshot = service.getImageByName(snapshotName); + if (snapshot != null) { + break; + } + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Stop Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + + // Wait for it to be ready + waitForStateChange(rc, snapshot, Image.Status.ACTIVE); + + return snapshot; + } + + private String generateSnapshotName(String server) { + SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); + return String.format("Snapshot of %s at %s", server, df.format(new Date())); + } + + /** + * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#evacuateServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext) + */ + @SuppressWarnings("nls") + @Override + public Server evacuateServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException { + Server server = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, EVACUATE_SERVICE); + MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Evacuate"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + logger.info(Msg.EVACUATING_SERVER, appName); + String msg; + + try { + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + String providerName = params.get(ProviderAdapter.PROPERTY_PROVIDER_NAME); + debugParameters(params); + debugContext(ctx); + + VMURL vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + Context context = null; + try { + context = getContext(rc, vm_url, providerName); + if (context != null) { + server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + evacuateServer(rc, server); + server.refreshStatus(); + context.close(); + doSuccess(rc); + } + } catch (ResourceNotFoundException e) { + msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + } catch (Throwable t) { + msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + EVACUATE_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + doFailure(rc, e.getStatus(), e.getMessage()); + } + + return server; + } + + /** + * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#migrateServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext) + */ + @SuppressWarnings("nls") + @Override + public Server migrateServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException { + Server server = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, MIGRATE_SERVICE); + MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Migrate"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + logger.info(Msg.MIGRATING_SERVER, appName); + String msg; + + try { + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + debugParameters(params); + debugContext(ctx); + + VMURL vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); + String identStr = (ident == null) ? null : ident.toString(); + + Context context = null; + try { + context = getContext(rc, vm_url, identStr); + if (context != null) { + server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + migrateServer(rc, server); + server.refreshStatus(); + context.close(); + doSuccess(rc); + } + } catch (ResourceNotFoundException e) { + msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + } catch (Throwable t) { + msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + MIGRATE_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + doFailure(rc, e.getStatus(), e.getMessage()); + } + + return server; + } + + private void evacuateServer(RequestContext rc, @SuppressWarnings("unused") Server server) throws ZoneException, RequestFailedException { + doFailure(rc, HttpStatus.NOT_IMPLEMENTED_501, "The operation 'EVACUATE' is not yet implemented"); + } + + private void migrateServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + String msg; + Context ctx = server.getContext(); + ComputeService service = ctx.getComputeService(); + + // Init status will equal final status + Status initialStatus = server.getStatus(); + + if (initialStatus == null) { + throw new ZoneException("Failed to determine server's starting status"); + } + + // We can only migrate certain statuses + if (!migratableStatuses.contains(initialStatus)) { + throw new ZoneException(String.format("Cannot migrate server that is in %s state. Must be in one of [%s]", + initialStatus, migratableStatuses)); + } + + boolean inConfirmPhase = false; + try { + while (rc.attempt()) { + try { + if (!inConfirmPhase) { + // Initial migrate request + service.migrateServer(server.getId()); + // Wait for change to verify resize + waitForStateChange(rc, server, Status.READY); + inConfirmPhase = true; + } + + // Verify resize + service.processResize(server); + // Wait for complete. will go back to init status + waitForStateChange(rc, server, initialStatus); + logger.info("Completed migrate request successfully"); + return; + } catch (ContextConnectionException e) { + msg = getConnectionExceptionMessage(rc, ctx, e); + logger.error(msg, e); + rc.delay(); + } + } + } catch (ZoneException e) { + String phase = inConfirmPhase ? "VERIFY MIGRATE" : "REQUEST MIGRATE"; + msg = EELFResourceManager.format(Msg.MIGRATE_SERVER_FAILED, server.getName(), server.getId(), phase, + e.getMessage()); + generateEvent(rc, false, msg); + logger.error(msg, e); + throw new RequestFailedException("Migrate Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server); + } + + } + + /** + * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#rebuildServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext) + */ + @SuppressWarnings("nls") + @Override + public Server rebuildServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException { + Server server = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, REBUILD_SERVICE); + MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Rebuild"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + logger.info(Msg.REBUILDING_SERVER, appName); + String msg; + + try { + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + debugParameters(params); + debugContext(ctx); + + VMURL vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); + String identStr = (ident == null) ? null : ident.toString(); + + Context context = null; + try { + context = getContext(rc, vm_url, identStr); + if (context != null) { + server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + + // Manually checking image service until new PAL release + if (hasImageAccess(rc, context)) { + rebuildServer(rc, server); + doSuccess(rc); + } else { + msg = EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(), + "Accessing Image Service Failed"); + logger.error(msg); + doFailure(rc, HttpStatus.FORBIDDEN_403, msg); + } + context.close(); + } + } catch (ResourceNotFoundException e) { + msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + } catch (Throwable t) { + msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + STOP_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + doFailure(rc, e.getStatus(), e.getMessage()); + } + + return server; + } + + /** + * This method is used to restart an existing virtual machine given the fully qualified URL of the machine. + * <p> + * The fully qualified URL contains enough information to locate the appropriate server. The URL is of the form + * <pre> + * [scheme]://[host[:port]] / [path] / [tenant_id] / servers / [vm_id] + * </pre> Where the various parts of the URL can be parsed and extracted and used to locate the appropriate service + * in the provider service catalog. This then allows us to open a context using the CDP abstraction, obtain the + * server by its UUID, and then perform the restart. + * </p> + * + * @throws UnknownProviderException + * If the provider cannot be found + * @throws IllegalArgumentException + * if the expected argument(s) are not defined or are invalid + * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#restartServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext) + */ + @SuppressWarnings("nls") + @Override + public Server restartServer(Map<String, String> params, SvcLogicContext ctx) + throws UnknownProviderException, IllegalArgumentException { + Server server = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, RESTART_SERVICE); + MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Restart"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + logger.info(Msg.RESTARTING_SERVER, appName); + + try { + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + debugParameters(params); + debugContext(ctx); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + + VMURL vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); + String identStr = (ident == null) ? null : ident.toString(); + + Context context = null; + try { + context = getContext(rc, vm_url, identStr); + if (context != null) { + server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + restartServer(rc, server); + context.close(); + doSuccess(rc); + } + } catch (ResourceNotFoundException e) { + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + } catch (Throwable t) { + String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + RESTART_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + doFailure(rc, e.getStatus(), e.getMessage()); + } + + return server; + } + + /* *********************************************************************************/ + /* DEVEN PANCHAL: This method is used to check the status of the VM */ + /**********************************************************************************/ + public Server vmStatuschecker(Map<String, String> params, SvcLogicContext ctx) throws UnknownProviderException, IllegalArgumentException { + Server server = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, VMSTATUSCHECK_SERVICE); + MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter: vmstatuscheck"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + + try { + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + debugParameters(params); + debugContext(ctx); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + + VMURL vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); + String identStr = (ident == null) ? null : ident.toString(); + + Context context = null; + try { + context = getContext(rc, vm_url, identStr); + if (context != null) { + server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + + String statusvm; + switch (server.getStatus()) { + case DELETED: + statusvm = "deleted"; + break; + + case RUNNING: + statusvm = "running"; + break; + + case ERROR: + statusvm = "error"; + break; + + case READY: + statusvm = "ready"; + break; + + case PAUSED: + statusvm = "paused"; + break; + + case SUSPENDED: + statusvm = "suspended"; + break; + + case PENDING: + statusvm = "pending"; + break; + + default: + statusvm = "default-unknown state-should never occur"; + break; + } + + + String statusofVM = statusvm; + context.close(); + SvcLogicContext svcLogic = rc.getSvcLogicContext(); + svcLogic.setStatus(OUTCOME_SUCCESS); + svcLogic.setAttribute("org.openecomp.statusofvm", statusofVM); + svcLogic.setAttribute(Constants.STATUS_OF_VM, statusofVM); + svcLogic.setAttribute(Constants.ATTRIBUTE_ERROR_CODE, Integer.toString(HttpStatus.OK_200.getStatusCode())); + } + } catch (ResourceNotFoundException e) { + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + } catch (Throwable t) { + String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + RESTART_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + doFailure(rc, e.getStatus(), e.getMessage()); + } + + return server; + } + + /* *********************************************************************************/ + + + /** + * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#startServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext) + */ + @SuppressWarnings("nls") + @Override + public Server startServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException { + Server server = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, START_SERVICE); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + logger.info(Msg.RESTARTING_SERVER, appName); + + try { + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + debugParameters(params); + debugContext(ctx); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + String providerName = params.get(ProviderAdapter.PROPERTY_PROVIDER_NAME); + + VMURL vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + Context context = null; + try { + context = getContext(rc, vm_url, providerName); + if (context != null) { + server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + stopServer(rc, server); + server.refreshStatus(); + context.close(); + doSuccess(rc); + } + } catch (ResourceNotFoundException e) { + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + } catch (Throwable t) { + String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + START_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + doFailure(rc, e.getStatus(), e.getMessage()); + } + + return server; + } + + /** + * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#stopServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext) + */ + @SuppressWarnings("nls") + @Override + public Server stopServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException { + Server server = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, STOP_SERVICE); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + logger.info(Msg.STOPPING_SERVER, appName); + + try { + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + debugParameters(params); + debugContext(ctx); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + ctx.setAttribute("STOP_STATUS", "SUCCESS"); + + VMURL vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); + String identStr = (ident == null) ? null : ident.toString(); + + Context context = null; + try { + context = getContext(rc, vm_url, identStr); + if (context != null) { + server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + if (server.getStatus().equals(Status.PENDING)) { + throw new RequestFailedException("Server is in pending Status"); + } + stopServer(rc, server); + server.refreshStatus(); + if (server.getStatus().equals(Status.ERROR)) { + throw new RequestFailedException("Server is in ERROR state after operation"); + } + context.close(); + doSuccess(rc); + }else{ + ctx.setAttribute("STOP_STATUS", "SERVER_NOT_FOUND"); + } + } catch (ResourceNotFoundException e) { + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + ctx.setAttribute("STOP_STATUS", "SERVER_NOT_FOUND"); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + } catch (Throwable t) { + String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + STOP_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName()); + logger.error(msg, t); + ctx.setAttribute("STOP_STATUS", "ERROR"); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + logger.error(EELFResourceManager.format(Msg.STOP_SERVER_FAILED, appName, "n/a", "n/a", e.getMessage())); + ctx.setAttribute("STOP_STATUS", "ERROR"); + doFailure(rc, e.getStatus(), e.getMessage()); + } + + return server; + } + + /** + * This method is used to validate that the parameters contain all required property names, and that the values are + * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists. + * + * @param ctx + * The request context object that manages the request + * @param parameters + * The parameters to be checked + * @param propertyNames + * The list of property names that are required to be present. + * @throws RequestFailedException + * If the parameters are not valid + */ + @SuppressWarnings({ + "nls", "static-method" + }) + private void validateParametersExist(@SuppressWarnings("unused") RequestContext ctx, Map<String, String> parameters, String... propertyNames) + throws RequestFailedException { + boolean success = true; + StringBuilder msg = new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE))); + msg.append(NL); + for (String propertyName : propertyNames) { + String value = parameters.get(propertyName); + if (value == null || value.trim().length() == 0) { + success = false; + msg.append(QUOTE); + msg.append(propertyName); + msg.append(QUOTE); + msg.append(SPACE); + } + } + + if (!success) { + logger.error(msg.toString()); + throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400, (Server)null); + } + } + + /** + * This method is used to create a diagnostic dump of the context for the log + * + * @param context + * The context to be dumped + */ + @SuppressWarnings({ + "nls", "static-method" + }) + private void debugContext(SvcLogicContext context) { + Set<String> keys = context.getAttributeKeySet(); + StringBuilder builder = new StringBuilder(); + + builder.append("Service Logic Context: Status "); + builder.append(LPAREN); + builder.append(context.getStatus()); + builder.append(RPAREN); + builder.append(", Attribute count "); + builder.append(LPAREN); + builder.append(keys == null ? "none" : Integer.toString(keys.size())); + builder.append(RPAREN); + if (keys != null && !keys.isEmpty()) { + builder.append(NL); + for (String key : keys) { + String value = context.getAttribute(key); + builder.append("Attribute "); + builder.append(LPAREN); + builder.append(key); + builder.append(RPAREN); + builder.append(", value "); + builder.append(LPAREN); + builder.append(value == null ? "" : value); + builder.append(RPAREN); + builder.append(NL); + } + } + + logger.debug(builder.toString()); + } + + void validateVMURL(VMURL vm) throws RequestFailedException { + String name = "vm-id"; + if (vm == null) { + throw new RequestFailedException(String.format("The value %s cannot be null.", name)); + } + + // Check that its a good uri + // This will probably never get hit bc of an earlier check while parsing + // the string to a VMURL + try { + //noinspection ResultOfMethodCallIgnored + URI.create(vm.toString()); + } catch (Exception e) { + throw new RequestFailedException( + String.format("The value %s is not well formed [%s].", name, vm.toString())); + } + + // Check the tenant and vmid segments + String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})"; + Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE); + + if (!pattern.matcher(vm.getTenantId()).matches()) { + throw new RequestFailedException( + String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId())); + } + if (!pattern.matcher(vm.getServerId()).matches()) { + throw new RequestFailedException( + String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId())); + } + } + + @SuppressWarnings("unused") + private void validateIdentityURL(IdentityURL id) throws RequestFailedException { + String name = "identity-url"; + if (id == null) { + throw new RequestFailedException(String.format("The value %s cannot be null.", name)); + } + + // Check that its a good uri + // This will probably never get hit bc of an earlier check while parsing + // the string to a VMURL + try { + //noinspection ResultOfMethodCallIgnored + URI.create(id.toString()); + } catch (Exception e) { + throw new RequestFailedException( + String.format("The value %s is not well formed [%s].", name, id.toString())); + } + } + + /** + * This method is used to dump the value of the parameters to the log for debugging purposes. + * + * @param parameters + * The parameters to be printed to the log + */ + @SuppressWarnings("static-method") + private void debugParameters(Map<String, String> parameters) { + for (String key : parameters.keySet()) { + logger.debug(Msg.PROPERTY_VALUE, key, parameters.get(key)); + } + } + + /** + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param code + * @param message + */ + @SuppressWarnings("static-method") + private void doFailure(RequestContext rc, HttpStatus code, String message) { + try { + doFailure(rc, code, message, null); + } catch (APPCException ignored) {/* never happens */} + } + + + private void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException { + SvcLogicContext svcLogic = rc.getSvcLogicContext(); + String msg = (message == null) ? code.getReasonPhrase() : message; + if (msg.contains("\n")) { + msg = msg.substring(0, msg.indexOf("\n")); + } + String status; + try { + status = Integer.toString(code.getStatusCode()); + } catch (Exception e) { + status = "500"; + } + svcLogic.setStatus(OUTCOME_FAILURE); + svcLogic.setAttribute(Constants.ATTRIBUTE_ERROR_CODE, status); + svcLogic.setAttribute(Constants.ATTRIBUTE_ERROR_MESSAGE, msg); + svcLogic.setAttribute(Constants.DG_OUTPUT_STATUS_MESSAGE, msg); + + if (null != cause) throw new APPCException(cause); + } + + /** + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + */ + @SuppressWarnings("static-method") + private void doSuccess(RequestContext rc) { + SvcLogicContext svcLogic = rc.getSvcLogicContext(); + svcLogic.setStatus(OUTCOME_SUCCESS); + svcLogic.setAttribute(Constants.ATTRIBUTE_ERROR_CODE, Integer.toString(HttpStatus.OK_200.getStatusCode())); + } + + /** + * Generates the event indicating what happened + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param success + * True if the event represents a successful outcome + * @param msg + * The detailed message + */ + private void generateEvent(@SuppressWarnings("unused") RequestContext rc, @SuppressWarnings("unused") boolean success, @SuppressWarnings("unused") String msg) { + // indication to the DG to generate the event? + } + + /** + * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a + * supported provider, regardless of region(s), and to return an opened context that can be used to access that + * server. + * + * @param rc + * The request context that wraps and manages the state of the request + * @param selfLinkURL + * The fully-qualified self-link URL of the server + * @param providerName + * The name of the provider to be searched + * @return The context that can be used to access the server, or null if not found. + */ + @SuppressWarnings("nls") + private Context getContext(RequestContext rc, String selfLinkURL, String providerName) { + VMURL vm = VMURL.parseURL(selfLinkURL); + IdentityURL ident = IdentityURL.parseURL(providerName); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + + if (vm == null) { + String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL); + logger.error(msg); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + return null; + } + + /* + * Get the cache of tenants and contexts for the named provider, if one exists + */ + ProviderCache cache = providerCache.get(providerName); + + /* + * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to + * the cache and continue, otherwise fail the request. + */ + if (cache == null) { + if (ident != null) { + cache = createProviderCache(vm, ident); + } + if (cache != null) { + providerCache.put(cache.getProviderName(), cache); + } else { + String msg = + EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName, providerCache.keySet().toString()); + logger.error(msg); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + return null; + } + } + + if (providerName == null) { + logger + .debug(String.format("Using the default provider cache [%s] since no valid identity url was passed in.", + cache.getIdentityURL())); + } + + // get the tenant cache for the vm + String identityURL = cache.getIdentityURL(); + TenantCache tenantCache = cache.getTenant(vm.getTenantId()); + + if(tenantCache == null){ + //no tenantCache matching tenant, add tenant to the provider cache + tenantCache = cache.addTenant(vm.getTenantId(),null,DEFAULT_USER, DEFAULT_PASS); + + if(tenantCache == null){ + //tenant not found + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + return null; + } + } + + //reserve the context + String tenantName = tenantCache.getTenantName(); + String tenantId = tenantCache.getTenantId(); + String region = tenantCache.determineRegion(vm); + + if (region != null) { + Pool<Context> pool = tenantCache.getPools().get(region); + + while (rc.attempt()) { + try { + Context context = pool.reserve(); + + /* + * Insert logic here to test the context for connectivity because we may have gotten one from + * the pool that was previously created. + */ + if (context.isStale()) { + context.relogin(); + } + return context; + } catch (PoolExtensionException e) { + String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL, + tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()), + Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } catch (Exception e) { + String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e, + e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName()); + + logger.error(msg, e); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + return null; + } + } + + String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL); + logger.error(msg); + doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg); + return null; + } + + + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + return null; + } + + /** + * initialize the provider adapter by building the context cache + */ + private void initialize() { + configuration = ConfigurationFactory.getConfiguration(); + + /* + * Initialize the provider cache for all defined providers. The definition of the providers uses a structured + * property set, where the names form a hierarchical name space (dotted notation, such as one.two.three). Each + * name in the name space can also be serialized by appending a sequence number. All nodes at the same level + * with the same serial number are grouped together in the namespace hierarchy. This allows a hierarchical + * multi-valued property to be defined, which can then be used to setup the provider and tenant caches. + * <p> + * For example, the following definitions show how the namespace hierarchy is defined for two providers, with + * two tenants on the first provider and a single tenant for the second provider. <pre> + * provider1.type=OpenStackProvider1 + * provider1.name=OpenStackProviderName1 + * provider1.identity=http://192.168.1.2:5000/v2.0 + * provider1.tenant1.name=MY-TENANT-NAME + * provider1.tenant1.userid=userid + * provider1.tenant1.password=userid@123 + * provider1.tenant2.name=MY-TENANT-NAME + * provider1.tenant2.userid=userid + * provider1.tenant2.password=userid@123 + * provider2.type=OpenStackProvider2 + * provider2.name=OpenStackProviderName2 + * provider2.identity=http://192.168.1.2:5000/v2.0 + * provider2.tenant1.name=MY-TENANT-NAME + * provider2.tenant1.userid=userid + * provider2.tenant1.password=userid@123 + * </pre> + * </p> + */ + providerCache = new HashMap<>(); + Properties properties = configuration.getProperties(); + List<Node> providers = StructuredPropertyHelper.getStructuredProperties(properties, PROPERTY_PROVIDER); + + for (Node provider : providers) { + ProviderCache cache = new ProviderCache(); + List<Node> providerNodes = provider.getChildren(); + for (Node node : providerNodes) { + if (node.getName().equals(PROPERTY_PROVIDER_TYPE)) { + cache.setProviderType(node.getValue()); + } else if (node.getName().equals(PROPERTY_PROVIDER_IDENTITY)) { + cache.setIdentityURL(node.getValue()); + cache.setProviderName(node.getValue()); + } else if (node.getName().startsWith(PROPERTY_PROVIDER_TENANT)) { + String tenantName = null; + String userId = null; + String password = null; + for (Node node2 : node.getChildren()) { + switch (node2.getName()) { + case PROPERTY_PROVIDER_TENANT_NAME: + tenantName = node2.getValue(); + break; + case PROPERTY_PROVIDER_TENANT_USERID: + userId = node2.getValue(); + DEFAULT_USER = node2.getValue(); + break; + case PROPERTY_PROVIDER_TENANT_PASSWORD: + password = node2.getValue(); + DEFAULT_PASS = node2.getValue(); + break; + } + } + + cache.addTenant(null, tenantName, userId, password); + } + } + + /* + * Add the provider to the set of providers cached + */ + if (cache.getIdentityURL() != null && cache.getProviderType() != null) { + providerCache.put(null, cache); + providerCache.put(cache.getIdentityURL(), cache); + } + + /* + * Now, initialize the cache for the loaded provider + */ + cache.initialize(); + } + } + + /** + * This method is called to rebuild the provided server. + * <p> + * If the server was booted from a volume, then the request is failed immediately and no action is taken. Rebuilding + * a VM from a bootable volume, where the bootable volume itself is not rebuilt, serves no purpose. + * </p> + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * @throws ZoneException + * @throws RequestFailedException + */ + @SuppressWarnings("nls") + private void rebuildServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + + ServerBootSource builtFrom = server.getBootSource(); + String msg; + + // Throw exception for non image/snap boot source + if (ServerBootSource.VOLUME.equals(builtFrom)) { + msg = String.format("Rebuilding is currently not supported for servers built from bootable volumes [%s]", + server.getId()); + generateEvent(rc, false, msg); + logger.error(msg); + throw new RequestFailedException("Rebuild Server", msg, HttpStatus.FORBIDDEN_403, server); + } + /* + * Pending is a bit of a special case. If we find the server is in a pending state, then the provider is in the + * process of changing state of the server. So, lets try to wait a little bit and see if the state settles down + * to one we can deal with. If not, then we have to fail the request. + */ + Context context = server.getContext(); + Provider provider = context.getProvider(); + ComputeService service = context.getComputeService(); + if (server.getStatus().equals(Status.PENDING)) { + waitForStateChange(rc, server, Status.READY, Status.RUNNING, Status.ERROR, Status.SUSPENDED, Status.PAUSED); + } + + /* + * Get the image to use. This is determined by the presence or absence of snapshot images. If any snapshots + * exist, then the latest snapshot is used, otherwise the image used to construct the VM is used. + */ + List<Image> snapshots = server.getSnapshots(); + String imageToUse; + if (snapshots != null && !snapshots.isEmpty()) { + imageToUse = snapshots.get(0).getId(); + } else { + imageToUse = server.getImage(); + ImageService imageService = server.getContext().getImageService(); + try { + while (rc.attempt()) { + try { + /* + * We are just trying to make sure that the image exists. We arent interested in the details at + * this point. + */ + imageService.getImage(imageToUse); + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), + imageService.getURL(), context.getTenant().getName(), context.getTenant().getId(), + e.getMessage(), Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + } catch (ZoneException e) { + msg = EELFResourceManager.format(Msg.IMAGE_NOT_FOUND, imageToUse, "rebuild"); + generateEvent(rc, false, msg); + logger.error(msg); + throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server); + } + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + + /* + * We determine what to do based on the current state of the server + */ + switch (server.getStatus()) { + case DELETED: + // Nothing to do, the server is gone + msg = EELFResourceManager.format(Msg.SERVER_DELETED, server.getName(), server.getId(), + server.getTenantId(), "rebuilt"); + generateEvent(rc, false, msg); + logger.error(msg); + throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server); + + case RUNNING: + // Attempt to stop the server, then rebuild it + stopServer(rc, server); + rebuildServer(rc, server, imageToUse); + startServer(rc, server); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + case ERROR: + msg = EELFResourceManager.format(Msg.SERVER_ERROR_STATE, server.getName(), server.getId(), + server.getTenantId(), "rebuild"); + generateEvent(rc, false, msg); + logger.error(msg); + throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server); + + case READY: + // Attempt to rebuild the server + rebuildServer(rc, server, imageToUse); + startServer(rc, server); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + case PAUSED: + // if paused, un-pause it, stop it, and rebuild it + unpauseServer(rc, server); + stopServer(rc, server); + rebuildServer(rc, server, imageToUse); + startServer(rc, server); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + case SUSPENDED: + // Attempt to resume the suspended server, stop it, and rebuild it + resumeServer(rc, server); + stopServer(rc, server); + rebuildServer(rc, server, imageToUse); + startServer(rc, server); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + default: + // Hmmm, unknown status, should never occur + msg = EELFResourceManager.format(Msg.UNKNOWN_SERVER_STATE, server.getName(), server.getId(), + server.getTenantId(), server.getStatus().name()); + generateEvent(rc, false, msg); + logger.error(msg); + throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server); + } + } + + /** + * This method handles the case of restarting a server once we have found the server and have obtained the abstract + * representation of the server via the context (i.e., the "Server" object from the CDP-Zones abstraction). + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * The server object representing the server we want to operate on + * @throws ZoneException + */ + @SuppressWarnings("nls") + private void restartServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + /* + * Pending is a bit of a special case. If we find the server is in a pending state, then the provider is in the + * process of changing state of the server. So, lets try to wait a little bit and see if the state settles down + * to one we can deal with. If not, then we have to fail the request. + */ + String msg; + if (server.getStatus().equals(Status.PENDING)) { + waitForStateChange(rc, server, Status.READY, Status.RUNNING, Status.ERROR, Status.SUSPENDED, Status.PAUSED); + } + + /* + * We determine what to do based on the current state of the server + */ + switch (server.getStatus()) { + case DELETED: + // Nothing to do, the server is gone + msg = EELFResourceManager.format(Msg.SERVER_DELETED, server.getName(), server.getId(), + server.getTenantId(), "restarted"); + generateEvent(rc, false, msg); + logger.error(msg); + break; + + case RUNNING: + // Attempt to stop and start the server + stopServer(rc, server); + startServer(rc, server); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + case ERROR: + msg = EELFResourceManager.format(Msg.SERVER_ERROR_STATE, server.getName(), server.getId(), + server.getTenantId(), "rebuild"); + generateEvent(rc, false, msg); + logger.error(msg); + throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server); + + case READY: + // Attempt to start the server + startServer(rc, server); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + case PAUSED: + // if paused, un-pause it + unpauseServer(rc, server); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + case SUSPENDED: + // Attempt to resume the suspended server + resumeServer(rc, server); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + default: + // Hmmm, unknown status, should never occur + msg = EELFResourceManager.format(Msg.UNKNOWN_SERVER_STATE, server.getName(), server.getId(), + server.getTenantId(), server.getStatus().name()); + generateEvent(rc, false, msg); + logger.error(msg); + break; + } + + } + + /** + * Resume a suspended server and wait for it to enter a running state + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * The server to be resumed + * @throws ZoneException + * @throws RequestFailedException + */ + @SuppressWarnings("nls") + private void resumeServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + logger.debug(Msg.RESUME_SERVER, server.getId()); + + Context context = server.getContext(); + String msg; + Provider provider = context.getProvider(); + ComputeService service = context.getComputeService(); + while (rc.attempt()) { + try { + server.resume(); + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Resume Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + waitForStateChange(rc, server, Status.RUNNING); + } + + /** + * Start the server and wait for it to enter a running state + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * The server to be started + * @throws ZoneException + * @throws RequestFailedException + */ + @SuppressWarnings("nls") + private void startServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + logger.debug(Msg.START_SERVER, server.getId()); + String msg; + Context context = server.getContext(); + Provider provider = context.getProvider(); + ComputeService service = context.getComputeService(); + while (rc.attempt()) { + try { + server.start(); + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Start Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + waitForStateChange(rc, server, Status.RUNNING); + } + + /** + * Stop the specified server and wait for it to stop + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * The server to be stopped + * @throws ZoneException + * @throws RequestFailedException + */ + @SuppressWarnings("nls") + private void stopServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + logger.debug(Msg.STOP_SERVER, server.getId()); + + String msg; + Context context = server.getContext(); + Provider provider = context.getProvider(); + ComputeService service = context.getComputeService(); + while (rc.attempt()) { + try { + server.stop(); + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Stop Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + waitForStateChange(rc, server, Status.READY, Status.ERROR); + } + + /** + * Un-Pause a paused server and wait for it to enter a running state + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * The server to be un-paused + * @throws ZoneException + * @throws RequestFailedException + */ + @SuppressWarnings("nls") + private void unpauseServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + logger.debug(Msg.UNPAUSE_SERVER, server.getId()); + + String msg; + Context context = server.getContext(); + Provider provider = context.getProvider(); + ComputeService service = context.getComputeService(); + while (rc.attempt()) { + try { + server.unpause(); + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Unpause Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + waitForStateChange(rc, server, Status.RUNNING, Status.READY); + } + + /** + * Enter a pool-wait loop checking the server state to see if it has entered one of the desired states or not. + * <p> + * This method checks the state of the server periodically for one of the desired states. When the server enters one + * of the desired states, the method returns a successful indication (true). If the server never enters one of the + * desired states within the allocated timeout period, then the method returns a failed response (false). No + * exceptions are thrown from this method. + * </p> + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * The server to wait on + * @param desiredStates + * A variable list of desired states, any one of which is allowed. + * @throws RequestFailedException + * If the request times out or fails for some reason + */ + @SuppressWarnings("nls") + private void waitForStateChange(RequestContext rc, Server server, Server.Status... desiredStates) + throws RequestFailedException { + int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL); + int timeout = configuration.getIntegerProperty(Constants.PROPERTY_SERVER_STATE_CHANGE_TIMEOUT); + Context context = server.getContext(); + Provider provider = context.getProvider(); + ComputeService service = context.getComputeService(); + String msg; + + long endTime = System.currentTimeMillis() + (timeout * 1000); // + + while (rc.attempt()) { + try { + try { + server.waitForStateChange(pollInterval, timeout, desiredStates); + break; + } catch (TimeoutException e) { + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + List<String> list = new ArrayList<>(); + for (Server.Status desiredState : desiredStates) { + list.add(desiredState.name()); + } + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } catch (ZoneException e) { + List<String> list = new ArrayList<>(); + for (Server.Status desiredState : desiredStates) { + list.add(desiredState.name()); + } + String reason = EELFResourceManager.format(Msg.STATE_CHANGE_EXCEPTION, e.getClass().getSimpleName(), + "server", server.getName(), server.getId(), StringHelper.asList(list), server.getStatus().name(), + e.getMessage()); + logger.error(reason); + logger.error(EELFResourceManager.format(e)); + + // Instead of failing we are going to wait and try again. + // Timeout is reduced by delay time + logger.info(String.format("Retrying in %ds", rc.getRetryDelay())); + rc.delay(); + timeout = (int) (endTime - System.currentTimeMillis()) / 1000; + // throw new RequestFailedException(e, operation, reason, + // HttpStatus.BAD_GATEWAY_502, server); + } + } + + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Waiting for State Change", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + } + + /** + * Enter a pool-wait loop checking the server state to see if it has entered one of the desired states or not. + * <p> + * This method checks the state of the server periodically for one of the desired states. When the server enters one + * of the desired states, the method returns a successful indication (true). If the server never enters one of the + * desired states within the allocated timeout period, then the method returns a failed response (false). No + * exceptions are thrown from this method. + * </p> + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param image + * The server to wait on + * @param desiredStates + * A variable list of desired states, any one of which is allowed. + * @throws RequestFailedException + * If the request times out or fails for some reason + * @throws NotLoggedInException + */ + @SuppressWarnings("nls") + private void waitForStateChange(RequestContext rc, Image image, Image.Status... desiredStates) + throws RequestFailedException, NotLoggedInException { + int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL); + int timeout = configuration.getIntegerProperty(Constants.PROPERTY_SERVER_STATE_CHANGE_TIMEOUT); + Context context = image.getContext(); + Provider provider = context.getProvider(); + ImageService service = context.getImageService(); + String msg; + + long endTime = System.currentTimeMillis() + (timeout * 1000); // + + while (rc.attempt()) { + try { + try { + image.waitForStateChange(pollInterval, timeout, desiredStates); + break; + } catch (TimeoutException e) { + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + List<String> list = new ArrayList<>(); + for (Image.Status desiredState : desiredStates) { + list.add(desiredState.name()); + } + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } catch (ZoneException e) { + List<String> list = new ArrayList<>(); + for (Image.Status desiredState : desiredStates) { + list.add(desiredState.name()); + } + String reason = EELFResourceManager.format(Msg.STATE_CHANGE_EXCEPTION, e.getClass().getSimpleName(), + "server", image.getName(), image.getId(), StringHelper.asList(list), image.getStatus().name(), + e.getMessage()); + logger.error(reason); + logger.error(EELFResourceManager.format(e)); + + // Instead of failing we are going to wait and try again. + // Timeout is reduced by delay time + logger.info(String.format("Retrying in %ds", rc.getRetryDelay())); + rc.delay(); + timeout = (int) (endTime - System.currentTimeMillis()) / 1000; + // throw new RequestFailedException(e, operation, reason, + // HttpStatus.BAD_GATEWAY_502, server); + } + } + + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Waiting for State Change", msg, HttpStatus.BAD_GATEWAY_502, new Server()); + } + rc.reset(); + } + + /** + * Rebuild the indicated server with the indicated image. This method assumes the server has been determined to be + * in the correct state to do the rebuild. + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * the server to be rebuilt + * @param image + * The image to be used (or snapshot) + * @throws RequestFailedException + * if the server does not change state in the allotted time + */ + @SuppressWarnings("nls") + private void rebuildServer(RequestContext rc, Server server, String image) throws RequestFailedException { + String msg; + Context context = server.getContext(); + Provider provider = context.getProvider(); + ComputeService service = context.getComputeService(); + + try { + while (rc.attempt()) { + try { + server.rebuild(image); + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + + /* + * We need to provide some time for OpenStack to start processing the request. + */ + try { + Thread.sleep(10L * 1000L); + } catch (InterruptedException e) { + logger.trace("Sleep threw interrupted exception, should never occur"); + } + } catch (ZoneException e) { + msg = + EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(), e.getMessage()); + logger.error(msg); + throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + + /* + * Once we have started the process, now we wait for the final state of stopped. This should be the final state + * (since we started the rebuild with the server stopped). + */ + waitForStateChange(rc, server, Status.READY); + + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + } + + /** + * Looks up the indicated server using the provided context and returns the server to the caller + * + * @param rc + * The request context + * @param context + * The provider context + * @param id + * The id of the server + * @return The server, or null if there is a problem + * @throws ZoneException + * If the server cannot be found + * @throws RequestFailedException + * If the server cannot be found because we cant connect to the provider + */ + @SuppressWarnings("nls") + private Server lookupServer(RequestContext rc, Context context, String id) + throws ZoneException, RequestFailedException { + ComputeService service = context.getComputeService(); + Server server = null; + String msg; + Provider provider = context.getProvider(); + + while (rc.attempt()) { + try { + server = service.getServer(id); + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg); + throw new RequestFailedException("Lookup Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + return server; + } + + private String getConnectionExceptionMessage(RequestContext rc, Context ctx, ContextConnectionException e) + throws ZoneException { + return EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, ctx.getProvider().getName(), + ctx.getComputeService().getURL(), ctx.getTenant().getName(), ctx.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + } + + private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) { + if (vm != null && ident != null) { + ProviderCache cache = new ProviderCache(); + + cache.setIdentityURL(ident.toString()); + cache.setProviderName(ident.toString()); + // cache.setProviderType("OpenStack"); + + TenantCache tenant = cache.addTenant(vm.getTenantId(),null, DEFAULT_USER, DEFAULT_PASS); + + // Make sure we could initialize the the cache otherwise return null + if (tenant != null && tenant.isInitialized()) { + return cache; + } + } + return null; + } + + /** + * This method is used to delete an existing virtual machine given the fully qualified URL of the machine. + * <p> + * The fully qualified URL contains enough information to locate the appropriate server. The URL is of the form + * <pre> + * [scheme]://[host[:port]] / [path] / [tenant_id] / servers / [vm_id] + * </pre> Where the various parts of the URL can be parsed and extracted and used to locate the appropriate service + * in the provider service catalog. This then allows us to open a context using the CDP abstraction, obtain the + * server by its UUID, and then perform the restart. + * </p> + * + * @throws UnknownProviderException + * If the provider cannot be found + * @throws IllegalArgumentException + * if the expected argument(s) are not defined or are invalid + * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#terminateServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext) + */ + @SuppressWarnings("nls") + @Override + public Server terminateServer(Map<String, String> params, SvcLogicContext ctx) + throws UnknownProviderException, IllegalArgumentException { + Server server = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, TERMINATE_SERVICE); + MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Terminate"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + if (logger.isDebugEnabled()) { + logger.debug("Inside org.openecomp.appc.adapter.iaas.impl.ProviderAdapter.terminateServer"); + } + + try { + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + debugParameters(params); + debugContext(ctx); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + ctx.setAttribute("TERMINATE_STATUS", "SUCCESS"); + + VMURL vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); + String identStr = (ident == null) ? null : ident.toString(); + + Context context = null; + try { + context = getContext(rc, vm_url, identStr); + if (context != null) { + server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + logger.info(EELFResourceManager.format(Msg.TERMINATING_SERVER, server.getName())); + terminateServer(rc, server); + logger.info(EELFResourceManager.format(Msg.TERMINATE_SERVER, server.getName())); + context.close(); + doSuccess(rc); + }else{ + ctx.setAttribute("TERMINATE_STATUS", "SERVER_NOT_FOUND"); + } + } catch (ResourceNotFoundException e) { + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + ctx.setAttribute("TERMINATE_STATUS", "SERVER_NOT_FOUND"); + } catch (Throwable t) { + String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + RESTART_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + logger.error(EELFResourceManager.format(Msg.TERMINATE_SERVER_FAILED, appName, "n/a", "n/a", e.getMessage())); + doFailure(rc, e.getStatus(), e.getMessage()); + ctx.setAttribute("TERMINATE_STATUS", "ERROR"); + } + + return server; + } + + /** + * This method handles the case of restarting a server once we have found the server and have obtained the abstract + * representation of the server via the context (i.e., the "Server" object from the CDP-Zones abstraction). + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * The server object representing the server we want to operate on + * @throws ZoneException + */ + @SuppressWarnings("nls") + private void terminateServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + /* + * Pending is a bit of a special case. If we find the server is in a pending state, then the provider is in the + * process of changing state of the server. So, lets try to wait a little bit and see if the state settles down + * to one we can deal with. If not, then we have to fail the request. + */ + String msg; + if (server.getStatus().equals(Status.PENDING)) { + waitForStateChange(rc, server, Status.READY, Status.RUNNING, Status.ERROR, Status.SUSPENDED, Status.PAUSED); + } + + /* + * We determine what to do based on the current state of the server + */ + switch (server.getStatus()) { + case DELETED: + // Nothing to do, the server is gone + msg = EELFResourceManager.format(Msg.SERVER_DELETED, server.getName(), server.getId(), + server.getTenantId(), "restarted"); + generateEvent(rc, false, msg); + logger.error(msg); + break; + + case RUNNING: + // Attempt to stop and start the server + logger.info("stopping SERVER"); + stopServer(rc, server); + deleteServer(rc, server); + logger.info("after delete SERVER"); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + case ERROR: + + case READY: + + case PAUSED: + + case SUSPENDED: + // Attempt to delete the suspended server + deleteServer(rc, server); + generateEvent(rc, true, OUTCOME_SUCCESS); + break; + + default: + // Hmmm, unknown status, should never occur + msg = EELFResourceManager.format(Msg.UNKNOWN_SERVER_STATE, server.getName(), server.getId(), + server.getTenantId(), server.getStatus().name()); + generateEvent(rc, false, msg); + logger.error(msg); + break; + } + + } + + /** + * Start the server and wait for it to enter a running state + * + * @param rc + * The request context that manages the state and recovery of the request for the life of its processing. + * @param server + * The server to be started + * @throws ZoneException + * @throws RequestFailedException + */ + @SuppressWarnings("nls") + private void deleteServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException { + String msg; + Context context = server.getContext(); + Provider provider = context.getProvider(); + ComputeService service = context.getComputeService(); + while (rc.attempt()) { + try { + logger.info("deleting SERVER"); + server.delete(); + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL()); + logger.error(msg); + throw new RequestFailedException("Delete Server", msg, HttpStatus.BAD_GATEWAY_502, server); + } + rc.reset(); + } + + private boolean hasImageAccess(@SuppressWarnings("unused") RequestContext rc, Context context) { + logger.info("Checking permissions for image service."); + try { + ImageService service = context.getImageService(); + service.getImageByName("CHECK_IMAGE_ACCESS"); + logger.info("Image service is accessible."); + return true; + } catch (ZoneException e) { + logger.warn("Image service could not be accessed. Some operations may fail.", e); + return false; + } + } + + @SuppressWarnings("nls") + @Override + public Stack terminateStack(Map<String, String> params, SvcLogicContext ctx) throws IllegalArgumentException, APPCException { + Stack stack = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + + ctx.setAttribute("TERMINATE_STATUS", "STACK_NOT_FOUND"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + + try { + + logAndValidate(params, ctx, rc, TERMINATE_STACK, "Terminate Stack", + ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME, + ProviderAdapter.PROPERTY_STACK_ID); + + String stackId = params.get(ProviderAdapter.PROPERTY_STACK_ID); + String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + + Context context = resolveContext(rc, params, appName, vm_url); + + try { + if (context != null) { + stack = lookupStack(rc, context, stackId); + logger.debug(Msg.STACK_FOUND, vm_url, context.getTenantName(), stack.getStatus().toString()); + logger.info(EELFResourceManager.format(Msg.TERMINATING_STACK, stack.getName())); + deleteStack(rc, stack); + logger.info(EELFResourceManager.format(Msg.TERMINATE_STACK, stack.getName())); + context.close(); + doSuccess(rc); + }else{ + ctx.setAttribute("TERMINATE_STATUS", "SERVER_NOT_FOUND"); + } + } catch (ResourceNotFoundException e) { + String msg = EELFResourceManager.format(Msg.STACK_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + } catch (Throwable t) { + String msg = EELFResourceManager.format(Msg.STACK_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + TERMINATE_STACK, vm_url, context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + } catch (RequestFailedException e) { + logger.error(EELFResourceManager.format(Msg.TERMINATE_STACK_FAILED, appName, "n/a", "n/a")); + doFailure(rc, e.getStatus(), e.getMessage()); + } + return stack; + } + + @Override + public Stack snapshotStack(Map<String, String> params, SvcLogicContext ctx) throws IllegalArgumentException, APPCException { + Stack stack = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + + ctx.setAttribute("SNAPSHOT_STATUS", "STACK_NOT_FOUND"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + + String vm_url = null; + Context context = null; + try { + + logAndValidate(params, ctx, rc, SNAPSHOT_STACK, "Snapshot Stack", + ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME, + ProviderAdapter.PROPERTY_STACK_ID); + + String stackId = params.get(ProviderAdapter.PROPERTY_STACK_ID); + vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + + context = resolveContext(rc, params, appName, vm_url); + + if (context != null) { + stack = lookupStack(rc, context, stackId); + logger.debug(Msg.STACK_FOUND, vm_url, context.getTenantName(), stack.getStatus().toString()); + logger.info(EELFResourceManager.format(Msg.SNAPSHOTING_STACK, stack.getName())); + + Snapshot snapshot = snapshotStack(rc, stack); + + ctx.setAttribute(ProviderAdapter.DG_OUTPUT_PARAM_NAMESPACE + + ProviderAdapter.PROPERTY_SNAPSHOT_ID, snapshot.getId()); + + logger.info(EELFResourceManager.format(Msg.STACK_SNAPSHOTED, stack.getName(), snapshot.getId())); + context.close(); + doSuccess(rc); + } else { + ctx.setAttribute(Constants.DG_ATTRIBUTE_STATUS, "failure"); + } + + } catch (ResourceNotFoundException e) { + String msg = EELFResourceManager.format(Msg.STACK_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg, e); + } catch (RequestFailedException e) { + logger.error(EELFResourceManager.format(Msg.MISSING_PARAMETER_IN_REQUEST, e.getReason(), "snapshotStack")); + doFailure(rc, e.getStatus(), e.getMessage(), e); + } catch (Throwable t) { + String msg = EELFResourceManager.format(Msg.STACK_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + "snapshotStack", vm_url, null == context ? "n/a" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg, t); + } + return stack; + } + + @Override + public Stack restoreStack(Map<String, String> params, SvcLogicContext ctx) throws IllegalArgumentException, APPCException { + Stack stack = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); + + ctx.setAttribute("SNAPSHOT_STATUS", "STACK_NOT_FOUND"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + + String vm_url = null; + Context context = null; + + try { + + logAndValidate(params, ctx, rc, SNAPSHOT_STACK, "Snapshot Stack", + ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME, + ProviderAdapter.PROPERTY_STACK_ID, + ProviderAdapter.PROPERTY_INPUT_SNAPSHOT_ID); + + String stackId = params.get(ProviderAdapter.PROPERTY_STACK_ID); + vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + + String snapshotId = params.get(ProviderAdapter.PROPERTY_INPUT_SNAPSHOT_ID); + + context = resolveContext(rc, params, appName, vm_url); + + if (context != null) { + stack = lookupStack(rc, context, stackId); + logger.debug(Msg.STACK_FOUND, vm_url, context.getTenantName(), stack.getStatus().toString()); + logger.info(EELFResourceManager.format(Msg.RESTORING_STACK, stack.getName(), snapshotId)); + restoreStack(stack, snapshotId); + logger.info(EELFResourceManager.format(Msg.STACK_RESTORED, stack.getName(), snapshotId)); + context.close(); + doSuccess(rc); + } else { + ctx.setAttribute(Constants.DG_ATTRIBUTE_STATUS, "failure"); + } + + } catch (ResourceNotFoundException e) { + String msg = EELFResourceManager.format(Msg.STACK_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg, e); + } catch (RequestFailedException e) { + logger.error(EELFResourceManager.format(Msg.MISSING_PARAMETER_IN_REQUEST, e.getReason(), "restoreStack")); + doFailure(rc, e.getStatus(), e.getMessage(), e); + } catch (Throwable t) { + String msg = EELFResourceManager.format(Msg.STACK_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + "restoreStack", vm_url, null == context ? "n/a" : context.getTenantName()); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg, t); + } + return stack; + } + + private void logAndValidate(Map<String, String> params, SvcLogicContext ctx, RequestContext rc, String methodName, String serviceName, String ... attributes) + throws RequestFailedException { + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, SNAPSHOT_STACK); + MDC.put(MDC_SERVICE_NAME, String.format("App-C IaaS Adapter:%s", serviceName)); + if (logger.isDebugEnabled()) { + logger.debug(String.format("Inside org.openecomp.appc.adapter.iaas.impl.ProviderAdapter.%s", methodName)); + } + + validateParametersExist(rc, params, attributes); + + debugParameters(params); + debugContext(ctx); + } + + private Context resolveContext(RequestContext rc, Map<String, String> params, String appName, String vm_url) + throws RequestFailedException { + + VMURL vm = VMURL.parseURL(vm_url); + if (vm == null) { + String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + logger.error(msg); + return null; + } + validateVMURL(vm); + IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); + String identStr = (ident == null) ? null : ident.toString(); + + return getContext(rc, vm_url, identStr); + + } + + private void deleteStack(RequestContext rc, Stack stack) throws ZoneException, RequestFailedException { + SvcLogicContext ctx = rc.getSvcLogicContext(); + Context context = stack.getContext(); + StackService stackService = context.getStackService(); + logger.debug("Deleting Stack: " + "id:{ " + stack.getId() + "}"); + stackService.deleteStack(stack); + + // wait for the stack deletion + boolean success = waitForStackStatus(rc, stack, Stack.Status.DELETED); + if (success) { + ctx.setAttribute("TERMINATE_STATUS", "SUCCESS"); + } else { + ctx.setAttribute("TERMINATE_STATUS", "ERROR"); + throw new RequestFailedException("Delete Stack failure : " + Msg.STACK_OPERATION_EXCEPTION.toString()); + } + } + + private boolean waitForStackStatus(RequestContext rc, Stack stack, Stack.Status expectedStatus) throws ZoneException, RequestFailedException { + SvcLogicContext ctx = rc.getSvcLogicContext(); + Context context = stack.getContext(); + StackService stackService = context.getStackService(); + + int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL); + int timeout = configuration.getIntegerProperty(Constants.PROPERTY_STACK_STATE_CHANGE_TIMEOUT); + long maxTimeToWait = System.currentTimeMillis() + (long) timeout * 1000; + Stack.Status stackStatus; + while (System.currentTimeMillis() < maxTimeToWait) { + stackStatus = stackService.getStack(stack.getName(), stack.getId()).getStatus(); + logger.debug("Stack status : " + stackStatus.toString()); + if (stackStatus == expectedStatus) { + return true; + } else if (stackStatus == Stack.Status.FAILED) { + return false; + } else { + try { + Thread.sleep(pollInterval * 1000); + } catch (InterruptedException e) { + logger.trace("Sleep threw interrupted exception, should never occur"); + } + } + } + + ctx.setAttribute("TERMINATE_STATUS", "ERROR"); + throw new TimeoutException("Timeout waiting for stack status change"); + + } + + private Snapshot snapshotStack(@SuppressWarnings("unused") RequestContext rc, Stack stack) throws ZoneException, RequestFailedException { + Snapshot snapshot = new Snapshot(); + Context context = stack.getContext(); + + OpenStackContext osContext = (OpenStackContext)context; + + final HeatConnector heatConnector = osContext.getHeatConnector(); + ((OpenStackContext)context).refreshIfStale(heatConnector); + + trackRequest(context); + RequestState.put("SERVICE", "Orchestration"); + RequestState.put("SERVICE_URL", heatConnector.getEndpoint()); + + Heat heat = heatConnector.getClient(); + + SnapshotResource snapshotResource = new SnapshotResource(heat); + + try { + + snapshot = snapshotResource.create(stack.getName(), stack.getId(), new CreateSnapshotParams()).execute(); + + // wait for the stack deletion + StackResource stackResource = new StackResource(heat); + if (!waitForStack(stack, stackResource, "SNAPSHOT_COMPLETE")) { + throw new RequestFailedException("Stack Snapshot failed."); + } + + } catch (OpenStackBaseException e) { + ExceptionMapper.mapException(e); + } + + return snapshot; + } + + private void restoreStack(Stack stack, String snapshotId) throws ZoneException, RequestFailedException { + Context context = stack.getContext(); + + OpenStackContext osContext = (OpenStackContext)context; + + final HeatConnector heatConnector = osContext.getHeatConnector(); + ((OpenStackContext)context).refreshIfStale(heatConnector); + + trackRequest(context); + RequestState.put("SERVICE", "Orchestration"); + RequestState.put("SERVICE_URL", heatConnector.getEndpoint()); + + Heat heat = heatConnector.getClient(); + + SnapshotResource snapshotResource = new SnapshotResource(heat); + + try { + + snapshotResource.restore(stack.getName(), stack.getId(), snapshotId).execute(); + + // wait for the snapshot restore + StackResource stackResource = new StackResource(heat); + if (!waitForStack(stack, stackResource, "RESTORE_COMPLETE")) { + throw new RequestFailedException("Snapshot restore failed."); + } + + } catch (OpenStackBaseException e) { + ExceptionMapper.mapException(e); + } + + } + + private boolean waitForStack(Stack stack, StackResource stackResource, String expectedStatus) + throws OpenStackBaseException, TimeoutException { + int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL); + int timeout = configuration.getIntegerProperty(Constants.PROPERTY_STACK_STATE_CHANGE_TIMEOUT); + long maxTimeToWait = System.currentTimeMillis() + (long) timeout * 1000; + + while (System.currentTimeMillis() < maxTimeToWait) { + String stackStatus = stackResource.show(stack.getName(), stack.getId()).execute().getStackStatus(); + logger.debug("Stack status : " + stackStatus); + if (stackStatus.toUpperCase().contains("FAILED")) return false; + if(checkStatus(expectedStatus, pollInterval, stackStatus)) return true; + } + throw new TimeoutException("Timeout waiting for stack status change"); + } + + private boolean checkStatus(String expectedStatus, int pollInterval, String actualStatus) { + if (actualStatus.toUpperCase().equals(expectedStatus)) { + return true; + } else { + try { + Thread.sleep(pollInterval * 1000); + } catch (InterruptedException ignored) { + } + } + return false; + } + + private void trackRequest(Context context, AbstractService.State... states) { + RequestState.clear(); + + if (null == states) return; + for (AbstractService.State state : states) { + RequestState.put(state.getName(), state.getValue()); + } + + Thread currentThread = Thread.currentThread(); + StackTraceElement[] stack = currentThread.getStackTrace(); + if (stack != null && stack.length > 0) { + int index = 0; + StackTraceElement element; + for (; index < stack.length; index++) { + element = stack[index]; + if ("trackRequest".equals(element.getMethodName())) { //$NON-NLS-1$ + break; + } + } + index++; + + if (index < stack.length) { + element = stack[index]; + RequestState.put(RequestState.METHOD, element.getMethodName()); + RequestState.put(RequestState.CLASS, element.getClassName()); + RequestState.put(RequestState.LINE_NUMBER, Integer.toString(element.getLineNumber())); + RequestState.put(RequestState.THREAD, currentThread.getName()); + RequestState.put(RequestState.PROVIDER, context.getProvider().getName()); + RequestState.put(RequestState.TENANT, context.getTenantName()); + RequestState.put(RequestState.PRINCIPAL, context.getPrincipal()); + } + } + } + + private Stack lookupStack(RequestContext rc, Context context, String id) + throws ZoneException, RequestFailedException { + StackService stackService = context.getStackService(); + Stack stack = null; + String msg; + Provider provider = context.getProvider(); + while (rc.attempt()) { + try { + List<Stack> stackList = stackService.getStacks(); + for (Stack stackObj : stackList) { + if (stackObj.getId().equals(id)) { + stack = stackObj; + break; + } + } + break; + } catch (ContextConnectionException e) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), stackService.getURL(), + context.getTenant().getName(), context.getTenant().getId(), e.getMessage(), + Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()), + Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } + + } + if (rc.isFailed()) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), stackService.getURL()); + logger.error(msg); + doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg); + throw new RequestFailedException("Lookup Stack", msg, HttpStatus.BAD_GATEWAY_502, stack); + } + + if (stack == null) { + throw new ResourceNotFoundException("Stack not found with Id : {" + id + "}"); + } + return stack; + } + + @SuppressWarnings("nls") + @Override + public Server lookupServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException { + Server server = null; + RequestContext rc = new RequestContext(ctx); + rc.isAlive(); //should we test the return and fail if false? + MDC.put(MDC_ADAPTER, ADAPTER_NAME); + MDC.put(MDC_SERVICE, LOOKUP_SERVICE); + MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:LookupServer"); + String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + + //for debugging merge into single method? + debugParameters(params); + debugContext(ctx); + + String vm_url = null; + VMURL vm = null; + try { + + //process vm_url + validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL, + ProviderAdapter.PROPERTY_PROVIDER_NAME); + vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL); + vm = VMURL.parseURL(vm_url); + if (validateVM(rc, appName, vm_url, vm)) return null; + + + //use try with resource to ensure context is closed (returned to pool) + try(Context context = resolveContext(rc, params, appName, vm_url)){ + //resloveContext & getContext call doFailure and log errors before returning null + if (context != null){ + server = lookupServer(rc, context, vm.getServerId()); + logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString()); + ctx.setAttribute("serverFound", "success"); + doSuccess(rc); + } + } catch (ZoneException e) { + //server not found + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + ctx.setAttribute("serverFound", "failure"); + } catch (IOException e) { + //exception closing context + String msg = EELFResourceManager.format(Msg.CLOSE_CONTEXT_FAILED, e, vm_url); + logger.error(msg); + } catch (Throwable t) { + String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(), + LOOKUP_SERVICE, vm_url, "Unknown" ); + logger.error(msg, t); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + } + + } catch (RequestFailedException e) { + // parameters not valid, unable to connect to provider + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + ctx.setAttribute("serverFound", "failure"); + } + return server; + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/ProviderCache.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/ProviderCache.java new file mode 100644 index 000000000..c70875da0 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/ProviderCache.java @@ -0,0 +1,164 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class maintains a cache of information by provider, where a provider is identified by both a type and an + * identity URL used to connect to that provider. + * <p> + * Providers may be multi-tenant, such as OpenStack, where the available services and resources vary from one tenant to + * another. Therefore, the provider cache maintains a cache of tenants and the service catalogs for each, as well as the + * credentials used to access the tenants, and a pool of Context objects for each tenant. The context pool allows use of + * the CDP abstraction layer to access the services of the provider within the specific tenant. + * </p> + */ +public class ProviderCache { + + /** + * The type of provider (e.g., OpenStackProvider) used to setup the CDP abstraction layer and load the appropriate + * support + */ + private String providerType; + + /** + * The URL of the provider's identity service or whatever service is used to login and authenticate to the provider + */ + private String identityURL; + + /** + * A string used to identify the provider instance + */ + private String providerName; + + /** + * The map of tenant cache objects by tenant id + */ + private Map<String /* tenant id */, TenantCache> tenants = new HashMap<String, TenantCache>(); + + /** + * @return the value of providerType + */ + public String getProviderType() { + return providerType; + } + + /** + * This method is called to initialize the provider cache, set up the context pools for each of the tenants, + * discover all of the regions supported on the provider, and load all of the service catalogs for each provider. + */ + public void initialize() { + for (Map.Entry<String, TenantCache> entry: tenants.entrySet()) { + entry.getValue().initialize(); + } + } + + /** + * @param providerType + * the value for providerType + */ + public void setProviderType(String providerType) { + this.providerType = providerType; + } + + /** + * @return the value of identityURL + */ + public String getIdentityURL() { + return identityURL; + } + + /** + * @param identityURL + * the value for identityURL + */ + public void setIdentityURL(String identityURL) { + this.identityURL = identityURL; + } + + /** + * @return the value of providerName + */ + public String getProviderName() { + return providerName; + } + + /** + * @param providerName + * the value for providerName + */ + public void setProviderName(String providerName) { + this.providerName = providerName; + } + + /** + * @return the value of tenants + */ + public Map<String, TenantCache> getTenants() { + return tenants; + } + + /** + * This method is a helper to return a specific TenantCache + * + * @param tenantId + * @return + */ + public TenantCache getTenant(String tenantId){ + return tenants.get(tenantId); + } + + // Previously there was no way to add additional tenants to the tenant cache + /** + * This method is used to add a tenant to the provider cache + * + * @param tenantId + * @param UserId + * @param password + * @return the new initialized TenantCache or null if unsuccessful + */ + public TenantCache addTenant(String tenantId, String tenantName, String userId, String password){ + if(tenantId != null || tenantName != null && userId != null && password != null){ + TenantCache tenant = new TenantCache(this); + if(tenantId != null){ + tenant.setTenantId(tenantId); + } + if(tenantName != null){ + tenant.setTenantName(tenantName); + } + tenant.setUserid(userId); + tenant.setPassword(password); + + if(identityURL != null){ + tenant.initialize(); + } + + if (tenant.isInitialized()) { + tenants.put(tenant.getTenantId(), tenant); + return tenant; + } + } + return null; + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/RequestContext.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/RequestContext.java new file mode 100644 index 000000000..395d37847 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/RequestContext.java @@ -0,0 +1,250 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import org.openecomp.appc.Constants; +import org.openecomp.appc.configuration.Configuration; +import org.openecomp.appc.configuration.ConfigurationFactory; +import org.openecomp.sdnc.sli.SvcLogicContext; + +/** + * This class is used to track and maintain recovery and time-to-live information for a request as it is being + * processed. + */ +public class RequestContext { + /** + * The number of seconds of wait time between successive attempts to connect to the provider. This is used to + * recover from provider outages or failures. It is not used to recover from logical errors, such as an invalid + * request, server not found, etc. + */ + private Integer retryDelay; + + /** + * The number of times we will attempt to connect to the provider. This is used to recover from provider outages or + * failures. It is not used to recover from logical errors, such as an invalid request, server not found, etc. + */ + private Integer retryLimit; + + /** + * The total time, in milliseconds, that the provider can have to process this request. If the accumulated time + * exceeds the time to live, then the request is failed with a timeout exception, regardless of the state of the + * provider. Note that the caller may supply this as a value in seconds, in which case it must be converted to + * milliseconds for the request context. + */ + private Long timeToLive; + + /** + * The accumulated time, in milliseconds, that has been used so far to process the request. This is compared to the + * time to live each time it is updated. If the accumulated time exceeds the time to live, then the request is + * failed with a timeout exception, regardless of the state of the provider. + */ + private long accumulatedTime; + + /** + * The total number of retries attempted so far + */ + private int attempt; + + /** + * The time when the stopwatch was started + */ + private long startTime = -1; + + /** + * The service logic (DG) context from the SLI + */ + private SvcLogicContext svcLogicContext; + + /** + * The configuration + */ + private Configuration configuration = ConfigurationFactory.getConfiguration(); + + /** + * Set to true whenever the retry limit has been exceeded, reset to false when reset() is called. + */ + private boolean retryFailed; + + /** + * Creates the request context + * + * @param context + * The service logic (SLI) context associated with the current DG + */ + public RequestContext(SvcLogicContext context) { + setSvcLogicContext(context); + } + + /** + * @return The retry delay, in seconds. If zero, then no retry is to be performed + */ + public int getRetryDelay() { + if (retryDelay == null) { + int value = configuration.getIntegerProperty(Constants.PROPERTY_RETRY_DELAY); + retryDelay = Integer.valueOf(value); + } + + return retryDelay.intValue(); + } + + /** + * This method is a helper that allows the caller to delay for the retry interval time and not have to handle the + * thread interruption, timer handling, etc. + */ + public void delay() { + long time = getRetryDelay() * 1000L; + long future = System.currentTimeMillis() + time; + if (time != 0) { + while (System.currentTimeMillis() < future && time > 0) { + try { + Thread.sleep(time); + } catch (InterruptedException e) { + /* + * This is rare, but it can happen if another thread interrupts us while we are sleeping. In that + * case, the thread is resumed before the delay time has actually expired, so re-calculate the + * amount of delay time needed and reenter the sleep until we get to the future time. + */ + time = future - System.currentTimeMillis(); + } + } + } + } + + /** + * @return The number of retries that are allowed per connection + */ + public int getRetryLimit() { + if (retryLimit == null) { + int value = configuration.getIntegerProperty(Constants.PROPERTY_RETRY_LIMIT); + retryLimit = Integer.valueOf(value); + } + + return retryLimit.intValue(); + } + + /** + * Check and count the connection attempt. + * + * @return True if the connection should be attempted. False indicates that the number of retries has been exhausted + * and it should NOT be attempted. + */ + public boolean attempt() { + if (retryFailed || attempt >= getRetryLimit()) { + retryFailed = true; + return false; + } + attempt++; + + return true; + } + + /** + * @return The number of retry attempts so far + */ + public int getAttempts() { + return attempt; + } + + /** + * @return True if the retry limit has been exceeded, false otherwise + */ + public boolean isFailed() { + return retryFailed; + } + + /** + * This method both checks the time to live to see if it has been exceeded and accumulates the total time used so + * far. + * <p> + * Each time this method is called it accumulates the total duration since the last time it was called to the total + * time accumulator. It then checks the total time to the time to live and if greater, it returns false. As long as + * the total time used is less than or equal to the time to live limit, the method returns true. It is important to + * call this method at the very beginning of the process so that all parts of the process are tracked. + * </p> + * + * @return True if the total time to live has not been exceeded. False indicates that the total time to live has + * been exceeded and no further processing should be performed. + */ + public boolean isAlive() { + long now = System.currentTimeMillis(); + if (startTime == -1) { + startTime = now; + return true; + } + accumulatedTime += (now - startTime); + startTime = now; + if (accumulatedTime > timeToLive) { + return false; + } + return true; + } + + /** + * @return The total amount of time used, in milliseconds. + */ + public long getTotalDuration() { + return accumulatedTime; + } + + /** + * This method is called to reset the retry counters. It has no effect on the time to live accumulator. + */ + public void reset() { + attempt = 0; + } + + /** + * Sets the time to live to the value, expressed in seconds + * + * @param time + * The time to live, in seconds + */ + public void setTimeToLiveSeconds(int time) { + setTimeToLiveMS(time * 1000L); + } + + /** + * Sets the time to live to the value, expressed in milliseconds + * + * @param time + * The time to live, in milliseconds + */ + public void setTimeToLiveMS(long time) { + this.timeToLive = time; + } + + /** + * @return The service logic context associated with this request + */ + public SvcLogicContext getSvcLogicContext() { + return svcLogicContext; + } + + /** + * @param svcLogicContext + * The service logic context to be associated with this request + */ + public void setSvcLogicContext(SvcLogicContext svcLogicContext) { + this.svcLogicContext = svcLogicContext; + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/RequestFailedException.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/RequestFailedException.java new file mode 100644 index 000000000..c7e7e93c8 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/RequestFailedException.java @@ -0,0 +1,277 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import org.glassfish.grizzly.http.util.HttpStatus; +import com.att.cdp.zones.model.Server; +import com.att.cdp.zones.model.Stack; + +/** + * This class is used to capture the exact cause and point of failure for the processing of a request. It is then used + * to encode the reason for the failure, status code, and anything else that needs to be captured and reported for + * diagnostic purposes. + */ +public class RequestFailedException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * The operation that was being requested or performed at the time of the failure. + */ + private String operation; + + /** + * A message that details the reason for the failure + */ + private String reason; + + /** + * The server that was being operated upon + */ + private Server server; + + /** + * The stack that was being operated upon + */ + private Stack stack; + /** + * The id of the server being operated upon if the server object is not available (such as the server was not found) + */ + private String serverId; + + /** + * The id of the stack being operated upon if the stack object is not available (such as the stack was not found) + */ + private String stackId; + /** + * The most appropriate Http Status code that reflects the error + */ + private HttpStatus status; + + /** + * + */ + public RequestFailedException() { + // intentionally empty + } + + /** + * @param message + * The error message + */ + public RequestFailedException(String message) { + super(message); + } + + /** + * Construct the request failed exception with the operation being performed, reason for the failure, http status + * code that is most appropriate, and the server we were processing. + * + * @param operation + * The operation being performed + * @param reason + * The reason that the operation was failed + * @param status + * The http status code that is most appropriate + * @param server + * The server that we were processing + */ + @SuppressWarnings("nls") + public RequestFailedException(String operation, String reason, HttpStatus status, Server server) { + super(operation + ":" + reason); + this.operation = operation; + this.reason = reason; + this.status = status; + this.server = server; + if (server != null) { + this.serverId = server.getId(); + } + } + + + /** + * Construct the request failed exception with the operation being performed, reason for the failure, http status + * code that is most appropriate, and the stack we were processing. + * + * @param operation + * The operation being performed + * @param reason + * The reason that the operation was failed + * @param status + * The http status code that is most appropriate + * @param stack + * The stack that we were processing + */ + @SuppressWarnings("nls") + public RequestFailedException(String operation, String reason, HttpStatus status, Stack stack) { + super(operation + ":" + reason); + this.operation = operation; + this.reason = reason; + this.status = status; + this.stack = stack; + if (stack != null) { + this.stackId = stack.getId(); + } + } + + /** + * Construct the request failed exception with the operation being performed, reason for the failure, http status + * code that is most appropriate, and the server we were processing. + * + * @param ex + * The exception that we are wrapping + * @param operation + * The operation being performed + * @param reason + * The reason that the operation was failed + * @param status + * The http status code that is most appropriate + * @param server + * The server that we were processing + */ + @SuppressWarnings("nls") + public RequestFailedException(Throwable ex, String operation, String reason, HttpStatus status, Server server) { + super(operation + ":" + reason, ex); + this.operation = operation; + this.reason = reason; + this.status = status; + this.server = server; + if (server != null) { + this.serverId = server.getId(); + } + } + + /** + * @param message + * The error message + * @param cause + * A nested exception + */ + public RequestFailedException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param message + * The error message + * @param cause + * A nested exception + * @param enableSuppression + * whether or not suppression is enabled or disabled + * @param writableStackTrace + * whether or not the stack trace should be writable + */ + public RequestFailedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * @param cause + * the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or unknown.) + */ + public RequestFailedException(Throwable cause) { + super(cause); + } + + /** + * @return The operation being performed + */ + public String getOperation() { + return operation; + } + + /** + * @return The reason for the failure + */ + public String getReason() { + return reason; + } + + /** + * @return The server being operated upon + */ + public Server getServer() { + return server; + } + + /** + * @return The id of the server being operated upon + */ + public String getServerId() { + return serverId; + } + + /** + * @return The status code from the operation + */ + public HttpStatus getStatus() { + return status; + } + + /** + * @param operation + * The operation being performed + */ + public void setOperation(String operation) { + this.operation = operation; + } + + /** + * @param reason + * The reason for the failure + */ + public void setReason(String reason) { + this.reason = reason; + } + + /** + * @param server + * The server being operated upon + */ + public void setServer(Server server) { + this.server = server; + if (server != null) { + setServerId(server.getId()); + } + } + + /** + * @param serverId + * The id of the server being operated upon + */ + public void setServerId(String serverId) { + this.serverId = serverId; + } + + /** + * @param status + * The status of the request + */ + public void setStatus(HttpStatus status) { + this.status = status; + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/ServiceCatalog.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/ServiceCatalog.java new file mode 100644 index 000000000..8ac81b2b9 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/ServiceCatalog.java @@ -0,0 +1,488 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import java.net.NoRouteToHostException; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import com.att.cdp.exceptions.ContextConnectionException; +import com.att.cdp.exceptions.ZoneException; +import com.att.cdp.openstack.util.ExceptionMapper; +import com.att.cdp.pal.util.Time; +import com.att.cdp.zones.ContextFactory; +import com.att.cdp.zones.spi.AbstractService; +import com.att.cdp.zones.spi.RequestState; +import com.att.cdp.zones.spi.AbstractService.State; + +import com.sun.jersey.api.client.ClientHandlerException; +import com.woorea.openstack.base.client.OpenStackBaseException; +import com.woorea.openstack.base.client.OpenStackClientConnector; +import com.woorea.openstack.base.client.OpenStackResponseException; +import com.woorea.openstack.base.client.OpenStackSimpleTokenProvider; +import com.woorea.openstack.keystone.Keystone; +import com.woorea.openstack.keystone.api.TokensResource; +import com.woorea.openstack.keystone.model.Access; +import com.woorea.openstack.keystone.model.Access.Service; +import com.woorea.openstack.keystone.model.Access.Service.Endpoint; +import com.woorea.openstack.keystone.model.Authentication; +import com.woorea.openstack.keystone.model.Tenant; +import com.woorea.openstack.keystone.model.authentication.UsernamePassword; + +/** + * This class is used to capture and cache the service catalog for a specific OpenStack provider. + * <p> + * This is needed because the way the servers are represented in the ECOMP product is as their fully qualified URL's. + * This is very problematic, because we cant identify their region from the URL, URL's change, and we cant identify the + * versions of the service implementations. In otherwords, the URL does not provide us enough information. + * </p> + * <p> + * The zone abstraction layer is designed to detect the versions of the services dynamically, and step up or down to + * match those reported versions. In order to do that, we need to know before hand what region we are accessing (since + * the supported versions may be different by regions). We will need to authenticate to the identity service in order to + * do this, plus we have to duplicate the code supporting proxies and trusted hosts that exists in the abstraction + * layer, but that cant be helped. + * </p> + * <p> + * What we do to circumvent this is connect to the provider using the lowest supported identity api, and read the entire + * service catalog into this object. Then, we parse the vm URL to extract the host and port and match that to the + * compute services defined in the catalog. When we find a compute service that has the same host name and port, + * whatever region that service is supporting is the region for that server. + * </p> + * <p> + * While we really only need to do this for compute nodes, there is no telling what other situations may arise where the + * full service catalog may be needed. Also, there is very little additional cost (additional RAM) associated with + * caching the full service catalog since there is no way to list only a portion of it. + * </p> + */ +public class ServiceCatalog { + + /** + * The service name for the compute service endpoint + */ + public static final String COMPUTE_SERVICE = "compute"; //$NON-NLS-1$ + + /** + * The service name for the identity service endpoint + */ + public static final String IDENTITY_SERVICE = "identity"; //$NON-NLS-1$ + + /** + * The service name for the compute service endpoint + */ + public static final String IMAGE_SERVICE = "image"; //$NON-NLS-1$ + + /** + * The service name for the network service endpoint + */ + public static final String NETWORK_SERVICE = "network"; //$NON-NLS-1$ + + /** + * The service name for the orchestration service endpoint + */ + public static final String ORCHESTRATION_SERVICE = "orchestration"; //$NON-NLS-1$ + + /** + * The service name for the volume service endpoint + */ + public static final String VOLUME_SERVICE = "volume"; //$NON-NLS-1$ + + /** + * The service name for the persistent object service endpoint + */ + public static final String OBJECT_SERVICE = "object-store"; //$NON-NLS-1$ + + /** + * The service name for the metering service endpoint + */ + public static final String METERING_SERVICE = "metering"; //$NON-NLS-1$ + + /** + * The Openstack Access object that manages the authenticated token and access control + */ + private Access access; + + /** + * The time (local) that the token expires and we need to re-authenticate + */ + @SuppressWarnings("unused") + private long expiresLocal; + + /** + * The set of all regions that have been defined + */ + private Set<String> regions; + + /** + * The read/write lock used to protect the cache contents + */ + private ReadWriteLock rwLock; + + /** + * A map of endpoints for each service organized by service type + */ + private Map<String /* Service Type */, List<Service.Endpoint>> serviceEndpoints; + + /** + * A map of service types that are published + */ + private Map<String /* Service Type */, Service> serviceTypes; + + /** + * The tenant that we are accessing + */ + private Tenant tenant; + + /** + * A "token provider" that manages the authentication token that we obtain when logging in + */ + private OpenStackSimpleTokenProvider tokenProvider; + + public static final String CLIENT_CONNECTOR_CLASS = "com.woorea.openstack.connector.JerseyConnector"; + + /** + * Create the ServiceCatalog cache and load it from the specified provider + * + * @param identityURL + * The identity service URL to connect to + * @param tenantIdentifier + * The name or id of the tenant to authenticate with. If the ID is a UUID format (32-character + * hexadecimal string), then the authentication is done using the tenant ID, otherwise it is done using + * the name. + * @param principal + * The user id to authenticate to the provider + * @param credential + * The password to authenticate to the provider + * @param properties + * Additional properties used to configure the connection, such as proxy and trusted hosts lists + * @throws ZoneException + * @throws ClassNotFoundException + * @throws IllegalAccessException + * @throws InstantiationException + */ + public ServiceCatalog(String identityURL, String tenantIdentifier, String principal, String credential, + Properties properties) throws ZoneException { + rwLock = new ReentrantReadWriteLock(); + serviceTypes = new HashMap<>(); + serviceEndpoints = new HashMap<>(); + regions = new HashSet<>(); + + Class<?> connectorClass; + OpenStackClientConnector connector; + try { + connectorClass = Class.forName(CLIENT_CONNECTOR_CLASS); + connector = (OpenStackClientConnector) connectorClass.newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + return; + } + Keystone keystone = new Keystone(identityURL, connector); + + String proxyHost = properties.getProperty(ContextFactory.PROPERTY_PROXY_HOST); + String proxyPort = properties.getProperty(ContextFactory.PROPERTY_PROXY_PORT); + String trustedHosts = properties.getProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, ""); //$NON-NLS-1$ + if (proxyHost != null && proxyHost.length() > 0) { + keystone.getProperties().setProperty(com.woorea.openstack.common.client.Constants.PROXY_HOST, proxyHost); + keystone.getProperties().setProperty(com.woorea.openstack.common.client.Constants.PROXY_PORT, proxyPort); + } + if (trustedHosts != null) { + keystone.getProperties().setProperty(com.woorea.openstack.common.client.Constants.TRUST_HOST_LIST, + trustedHosts); + } + + Authentication authentication = new UsernamePassword(principal, credential); + TokensResource tokens = keystone.tokens(); + TokensResource.Authenticate authenticate = tokens.authenticate(authentication); + if (tenantIdentifier.length() == 32 && tenantIdentifier.matches("[0-9a-fA-F]+")) { //$NON-NLS-1$ + authenticate = authenticate.withTenantId(tenantIdentifier); + } else { + authenticate = authenticate.withTenantName(tenantIdentifier); + } + + /* + * We have to set up the TrackRequest TLS collection for the ExceptionMapper + */ + trackRequest(); + RequestState.put(RequestState.PROVIDER, "OpenStackProvider"); + RequestState.put(RequestState.TENANT, tenantIdentifier); + RequestState.put(RequestState.PRINCIPAL, principal); + + try { + access = authenticate.execute(); + expiresLocal = getLocalExpiration(access); + tenant = access.getToken().getTenant(); + tokenProvider = new OpenStackSimpleTokenProvider(access.getToken().getId()); + keystone.setTokenProvider(tokenProvider); + parseServiceCatalog(access.getServiceCatalog()); + } catch (OpenStackBaseException e) { + ExceptionMapper.mapException(e); + } catch (Exception ex) { + throw new ContextConnectionException(ex.getMessage()); + } + } + + /** + * Returns the list of service endpoints for the published service type + * + * @param serviceType + * The service type to obtain the endpoints for + * @return The list of endpoints for the service type, or null if none exist + */ + public List<Service.Endpoint> getEndpoints(String serviceType) { + Lock readLock = rwLock.readLock(); + readLock.lock(); + try { + return serviceEndpoints.get(serviceType); + } finally { + readLock.unlock(); + } + } + + /** + * Computes the local time when the access token will expire, after which we will need to re-login to access the + * provider. + * + * @param accessKey + * The access key used to access the provider + * @return The local time the key expires + */ + private static long getLocalExpiration(Access accessKey) { + Date now = Time.getCurrentUTCDate(); + if (accessKey != null && accessKey.getToken() != null) { + Calendar issued = accessKey.getToken().getIssued_at(); + Calendar expires = accessKey.getToken().getExpires(); + if (issued != null && expires != null) { + long tokenLife = expires.getTimeInMillis() - issued.getTimeInMillis(); + return now.getTime() + tokenLife; + } + } + return now.getTime(); + } + + /** + * @return The set of all regions that are defined + */ + public Set<String> getRegions() { + Lock readLock = rwLock.readLock(); + readLock.lock(); + try { + return regions; + } finally { + readLock.unlock(); + } + } + + /** + * @return A list of service types that are published + */ + public List<String> getServiceTypes() { + Lock readLock = rwLock.readLock(); + readLock.lock(); + try { + ArrayList<String> result = new ArrayList<>(); + result.addAll(serviceTypes.keySet()); + return result; + } finally { + readLock.unlock(); + } + } + + /** + * @return The tenant id + */ + public String getTenantId() { + Lock readLock = rwLock.readLock(); + readLock.lock(); + try { + return tenant.getId(); + } finally { + readLock.unlock(); + } + } + + /** + * @return The tenant name + */ + public String getTenantName() { + Lock readLock = rwLock.readLock(); + readLock.lock(); + try { + return tenant.getName(); + } finally { + readLock.unlock(); + } + } + + /** + * Returns an indication if the specified service type is published by this provider + * + * @param serviceType + * The service type to check for + * @return True if a service of that type is published + */ + public boolean isServicePublished(String serviceType) { + Lock readLock = rwLock.readLock(); + readLock.lock(); + try { + return serviceTypes.containsKey(serviceType); + } finally { + readLock.unlock(); + } + } + + /** + * Parses the service catalog and caches the results + * + * @param services + * The list of services published by this provider + */ + private void parseServiceCatalog(List<Service> services) { + Lock lock = rwLock.writeLock(); + lock.lock(); + try { + serviceTypes.clear(); + serviceEndpoints.clear(); + regions.clear(); + + for (Service service : services) { + String type = service.getType(); + serviceTypes.put(type, service); + + List<Service.Endpoint> endpoints = service.getEndpoints(); + for (Service.Endpoint endpoint : endpoints) { + List<Service.Endpoint> endpointList = serviceEndpoints.get(type); + if (endpointList == null) { + endpointList = new ArrayList<>(); + serviceEndpoints.put(type, endpointList); + } + endpointList.add(endpoint); + + String region = endpoint.getRegion(); + if (!regions.contains(region)) { + regions.add(region); + } + } + } + } finally { + lock.unlock(); + } + } + + /** + * This method is used to provide a diagnostic listing of the service catalog + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + + StringBuilder builder = new StringBuilder(); + Lock lock = rwLock.readLock(); + lock.lock(); + try { + builder.append(String.format("Service Catalog: tenant %s, id[%s], description[%s]\n", tenant.getName(), //$NON-NLS-1$ + tenant.getId(), tenant.getDescription())); + if (regions != null && !regions.isEmpty()) { + builder.append(String.format("%d regions:\n", regions.size())); //$NON-NLS-1$ + for (String region : regions) { + builder.append("\t" + region + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + builder.append(String.format("%d services:\n", serviceEndpoints.size())); //$NON-NLS-1$ + for (String serviceType : serviceEndpoints.keySet()) { + List<Endpoint> endpoints = serviceEndpoints.get(serviceType); + Service service = serviceTypes.get(serviceType); + + builder.append(String.format("\t%s [%s] - %d endpoints\n", service.getType(), service.getName(), //$NON-NLS-1$ + endpoints.size())); + for (Endpoint endpoint : endpoints) { + builder.append(String.format("\t\tRegion [%s], public URL [%s]\n", endpoint.getRegion(), //$NON-NLS-1$ + endpoint.getPublicURL())); + } + } + } finally { + lock.unlock(); + } + + return builder.toString(); + } + + /** + * Initializes the request state for the current requested service. + * <p> + * This method is used to track requests made to the various service implementations and to provide additional + * information for diagnostic purposes. The <code>RequestState</code> class stores the state in thread-local storage + * and is available to all code on that thread. + * </p> + * <p> + * This method first obtains the stack trace and scans the stack backward for the call to this method. It then backs + * up one more call and assumes that method is the request that we are "tracking". + * </p> + * + * @param states + * A variable argument list of additional state values that the caller wants to add to the request state + * thread-local object to track the context. + */ + protected void trackRequest(State... states) { + RequestState.clear(); + + for (State state : states) { + RequestState.put(state.getName(), state.getValue()); + } + + Thread currentThread = Thread.currentThread(); + StackTraceElement[] stack = currentThread.getStackTrace(); + if (stack != null && stack.length > 0) { + int index = 0; + StackTraceElement element = null; + for (; index < stack.length; index++) { + element = stack[index]; + if ("trackRequest".equals(element.getMethodName())) { //$NON-NLS-1$ + break; + } + } + index++; + + if (index < stack.length) { + element = stack[index]; + RequestState.put(RequestState.METHOD, element.getMethodName()); + RequestState.put(RequestState.CLASS, element.getClassName()); + RequestState.put(RequestState.LINE_NUMBER, Integer.toString(element.getLineNumber())); + RequestState.put(RequestState.THREAD, currentThread.getName()); + // RequestState.put(RequestState.PROVIDER, context.getProvider().getName()); + // RequestState.put(RequestState.TENANT, context.getTenantName()); + // RequestState.put(RequestState.PRINCIPAL, context.getPrincipal()); + } + } + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/TenantCache.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/TenantCache.java new file mode 100644 index 000000000..c0c114dc8 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/TenantCache.java @@ -0,0 +1,378 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.openecomp.appc.Constants; +import org.openecomp.appc.configuration.Configuration; +import org.openecomp.appc.configuration.ConfigurationFactory; +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.pool.Allocator; +import org.openecomp.appc.pool.Destructor; +import org.openecomp.appc.pool.Pool; +import org.openecomp.appc.pool.PoolSpecificationException; +import com.att.cdp.exceptions.ContextConnectionException; +import com.att.cdp.exceptions.ZoneException; +import com.att.cdp.zones.Context; +import com.att.cdp.zones.ContextFactory; +import com.att.cdp.zones.Provider; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import com.sun.jersey.api.client.ClientHandlerException; +import com.woorea.openstack.keystone.model.Access.Service.Endpoint; + +/** + * This class maintains a cache of tenants within a specific provider. + * <p> + * Providers may be multi-tenant, such as OpenStack, where the available services and resources vary from one tenant to + * another. Therefore, the provider cache maintains a cache of tenants and the service catalogs for each, as well as the + * credentials used to access the tenants, and a pool of Context objects for each tenant. The context pool allows use of + * the CDP abstraction layer to access the services of the provider within the specific tenant. + * </p> + */ +public class TenantCache implements Allocator<Context>, Destructor<Context> { + + public static final String POOL_PROVIDER_NAME = "pool.provider.name"; + public static final String POOL_TENANT_NAME = "pool.tenant.name"; + public static final String CLIENT_CONNECTOR_CLASS = "com.woorea.openstack.connector.JerseyConnector"; + + /** + * The provider we are part of + */ + private ProviderCache provider; + + /** + * The password used to authenticate + */ + private String password; + + /** + * The context pools by region used to access this tenant + */ + private Map<String /* region */, Pool<Context>> pools = new HashMap<>(); + + /** + * The tenant id + */ + private String tenantId; + + /** + * The tenant name + */ + private String tenantName; + + /** + * The user id used to authenticate + */ + private String userid; + + /** + * The configuration of this adapter + */ + private Configuration configuration; + + /** + * The service catalog for this provider + */ + private ServiceCatalog catalog; + + /** + * Set to true when the cache has been initialized + */ + private boolean initialized; + + /** + * The logger to use + */ + private EELFLogger logger; + + /** + * Construct the cache of tenants for the specified provider + * + * @param provider + * The provider + */ + public TenantCache(ProviderCache provider) { + configuration = ConfigurationFactory.getConfiguration(); + logger = EELFManager.getInstance().getLogger(getClass()); + this.provider = provider; + configuration = ConfigurationFactory.getConfiguration(); + } + + /** + * @return True when the cache has been initialized. A tenant cache is initialized when the service catalog for the + * tenant on the specified provider has been loaded and processed. + */ + public boolean isInitialized() { + return initialized; + } + + /** + * Initializes the tenant cache. + * <p> + * This method authenticates to the provider and obtains the service catalog. For the service catalog we can + * determine all supported regions for this provider, as well as all published services and their endpoints. We will + * cache and maintain a copy of the service catalog for later queries. + * </p> + * <p> + * Once the catalog has been obtained, we create a context pool for each region defined. The context allows access + * to services of a single region only, so we need a separate context by region. It is possible to operate on + * resources that span regions, but to do so will require acquiring a context for each region of interest. + * </p> + * <p> + * The context pool maintains the reusable context objects and allocates them as needed. This class is registered as + * the allocator and destructor for the pool, so that we can create a new context when needed, and close it when no + * longer used. + * </p> + */ + public void initialize() { + logger.debug("Initializing TenantCache"); + + int min = configuration.getIntegerProperty(Constants.PROPERTY_MIN_POOL_SIZE); + int max = configuration.getIntegerProperty(Constants.PROPERTY_MAX_POOL_SIZE); + int delay = configuration.getIntegerProperty(Constants.PROPERTY_RETRY_DELAY); + int limit = configuration.getIntegerProperty(Constants.PROPERTY_RETRY_LIMIT); + + String url = provider.getIdentityURL(); + String tenant = tenantName == null ? tenantId : tenantName; + Properties properties = configuration.getProperties(); + + int attempt = 1; + while (attempt <= limit) { + try { + catalog = new ServiceCatalog(url, tenant, userid, password, properties); + tenantId = catalog.getTenantId(); + tenantName = catalog.getTenantName(); + + for (String region : catalog.getRegions()) { + try { + Pool<Context> pool = new Pool<>(min, max); + pool.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, url); + pool.setProperty(ContextFactory.PROPERTY_TENANT, tenantName); + pool.setProperty(ContextFactory.PROPERTY_CLIENT_CONNECTOR_CLASS, CLIENT_CONNECTOR_CLASS); + pool.setProperty(ContextFactory.PROPERTY_RETRY_DELAY, + configuration.getProperty(Constants.PROPERTY_RETRY_DELAY)); + pool.setProperty(ContextFactory.PROPERTY_RETRY_LIMIT, + configuration.getProperty(Constants.PROPERTY_RETRY_LIMIT)); + pool.setProperty(ContextFactory.PROPERTY_REGION, region); + if (properties.getProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS) != null) { + pool.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, + properties.getProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS)); + } + pool.setAllocator(this); + pool.setDestructor(this); + pools.put(region, pool); + logger.debug(String.format("Put pool for region %s", region)); + } catch (PoolSpecificationException e) { + logger.error("Error creating pool", e); + e.printStackTrace(); + } + } + initialized = true; + break; + } catch (ContextConnectionException e) { + attempt++; + logger.error(Msg.CONNECTION_FAILED_RETRY, provider.getProviderName(), url, tenantName, tenantId, e.getMessage(), Integer.toString(delay), Integer.toString(attempt), + Integer.toString(limit)); + + try { + Thread.sleep(delay * 1000L); + } catch (InterruptedException ie) { + // ignore + } + } catch (ClientHandlerException | ZoneException e) { + logger.error(e.getMessage()); + break; + } + } + + if (!initialized) { + logger.error(Msg.CONNECTION_FAILED, provider.getProviderName(), url); + } + } + + /** + * This method accepts a fully qualified compute node URL and uses that to determine which region of the provider + * hosts that compute node. + * + * @param url + * The parsed URL of the compute node + * @return The region name, or null if no region of this tenant hosts that compute node. + */ + public String determineRegion(VMURL url) { + logger.debug(String.format("Attempting to determine VM region for %s", url)); + String region = null; + Pattern urlPattern = Pattern.compile("[^:]+://([^:/]+)(?::([0-9]+)).*"); + + if (url != null) { + for (Endpoint endpoint : catalog.getEndpoints(ServiceCatalog.COMPUTE_SERVICE)) { + String endpointUrl = endpoint.getPublicURL(); + Matcher matcher = urlPattern.matcher(endpointUrl); + if (matcher.matches()) { + if (url.getHost().equals(matcher.group(1))) { + if (url.getPort() != null) { + if (!url.getPort().equals(matcher.group(2))) { + continue; + } + } + + region = endpoint.getRegion(); + break; + } + } + } + } + logger.debug(String.format("Region for %s is %s", url, region)); + return region; + } + + /** + * @return the value of provider + */ + public ProviderCache getProvider() { + return provider; + } + + /** + * @param provider + * the value for provider + */ + public void setProvider(ProviderCache provider) { + this.provider = provider; + } + + /** + * @return the value of password + */ + public String getPassword() { + return password; + } + + /** + * @param password + * the value for password + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * @return the value of tenantId + */ + public String getTenantId() { + return tenantId; + } + + /** + * @param tenantId + * the value for tenantId + */ + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + + /** + * @return the value of tenantName + */ + public String getTenantName() { + return tenantName; + } + + /** + * @param tenantName + * the value for tenantName + */ + public void setTenantName(String tenantName) { + this.tenantName = tenantName; + } + + /** + * @return the value of userid + */ + public String getUserid() { + return userid; + } + + /** + * @param userid + * the value for userid + */ + public void setUserid(String userid) { + this.userid = userid; + } + + /** + * @return the value of pools + */ + public Map<String, Pool<Context>> getPools() { + return pools; + } + + /** + * @see org.openecomp.appc.pool.Allocator#allocate(org.openecomp.appc.pool.Pool) + */ + @SuppressWarnings("unchecked") + @Override + public Context allocate(Pool<Context> pool) { + logger.debug("Allocationg context for pool"); + Class<? extends Provider> providerClass; + try { + providerClass = (Class<? extends Provider>) Class.forName("com.att.cdp.openstack.OpenStackProvider"); + // String providerType = provider.getProviderType(); + + // Context context = ContextFactory.getContext(providerType, pool.getProperties()); + Context context = ContextFactory.getContext(providerClass, pool.getProperties()); + context.login(userid, password); + return context; + } catch (IllegalStateException | IllegalArgumentException | ZoneException | ClassNotFoundException e) { + logger.debug("Failed to allocate context for pool", e); + e.printStackTrace(); + } + return null; + } + + /** + * @see org.openecomp.appc.pool.Destructor#destroy(java.lang.Object, org.openecomp.appc.pool.Pool) + */ + @Override + public void destroy(Context context, Pool<Context> pool) { + try { + context.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * @return the service catalog for this provider + */ + public ServiceCatalog getServiceCatalog() { + return catalog; + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/VMURL.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/VMURL.java new file mode 100644 index 000000000..e9709fae0 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/iaas/impl/VMURL.java @@ -0,0 +1,138 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This class is used to parse the VM URL returned from OpenStack and extract all of the constituent parts. + */ +public class VMURL { + + /** + * The regular expression pattern used to parse the URL. Capturing groups are used to identify and extract the + * various component parts of the URL. + */ + private static Pattern pattern = Pattern + .compile("(\\p{Alnum}+)://([^/:]+)(?::([0-9]+))?/v2/([^/]+)/servers/([^/]+)"); + + /** + * The URL scheme or protocol, such as HTTP or HTTPS + */ + private String scheme; + + /** + * The host name or ip address + */ + private String host; + + /** + * The port number, or null if no port is defined + */ + private String port; + + /** + * The tenant UUID + */ + private String tenantId; + + /** + * The server UUID + */ + private String serverId; + + /** + * A private default constructor prevents instantiation by any method other than the factory method + * + * @see #parseURL(String) + */ + private VMURL() { + + } + + /** + * This static method is used to parse the provided server URL string and return a parse results object (VMURL) + * which represents the state of the parse. + * + * @param serverUrl + * The server URL to be parsed + * @return The VMURL parse results object, or null if the URL was not valid or null. + */ + public static VMURL parseURL(String serverUrl) { + VMURL obj = null; + if (serverUrl != null) { + Matcher matcher = pattern.matcher(serverUrl.trim()); + if (matcher.matches()) { + obj = new VMURL(); + obj.scheme = matcher.group(1); + obj.host = matcher.group(2); + obj.port = matcher.group(3); + obj.tenantId = matcher.group(4); + obj.serverId = matcher.group(5); + } + } + + return obj; + } + + /** + * @return The URL scheme + */ + public String getScheme() { + return scheme; + } + + /** + * @return The URL host + */ + public String getHost() { + return host; + } + + /** + * @return The URL port, or null if no port was defined + */ + public String getPort() { + return port; + } + + /** + * @return The tenant id + */ + public String getTenantId() { + return tenantId; + } + + /** + * @return The server ID + */ + public String getServerId() { + return serverId; + } + + @Override + public String toString() { + return String.format("%s://%s:%s/%s/servers/%s", scheme, host, port, tenantId, serverId); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/SnapshotResource.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/SnapshotResource.java new file mode 100644 index 000000000..47ac7ff9e --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/SnapshotResource.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat; + +import org.openecomp.appc.adapter.openstack.heat.model.CreateSnapshotParams; +import org.openecomp.appc.adapter.openstack.heat.model.Snapshot; + +import com.woorea.openstack.base.client.Entity; +import com.woorea.openstack.base.client.HttpMethod; +import com.woorea.openstack.base.client.OpenStackClient; +import com.woorea.openstack.base.client.OpenStackRequest; + + +public class SnapshotResource { + + private final OpenStackClient client; + + public SnapshotResource(OpenStackClient client) { + this.client = client; + } + + public CreateSnapshot create(String stackName, String stackID, CreateSnapshotParams params) { + return new CreateSnapshot(stackName, stackID, params); + } + + public RestoreSnapshot restore(String stackName, String stackID, String snapshotID) { + return new RestoreSnapshot(stackName, stackID, snapshotID); + } + + public ShowSnapshot show(String stackName, String stackID, String snapshotID) { + return new ShowSnapshot(stackName, stackID, snapshotID); + } + + public class CreateSnapshot extends OpenStackRequest<Snapshot> { + public CreateSnapshot(String stackName, String stackID, CreateSnapshotParams params) { + super(client, HttpMethod.POST, "/stacks/" + stackName + "/" + stackID + "/snapshots", Entity.json(params), Snapshot.class); + } + } + + public class RestoreSnapshot extends OpenStackRequest<Void> { + public RestoreSnapshot(String stackName, String stackID, String snapshotID) { + super(client, HttpMethod.POST, "/stacks/" + stackName + "/" + stackID + "/snapshots/" + snapshotID + "/restore", null, Void.class); + } + } + + public class ShowSnapshot extends OpenStackRequest<Snapshot> { + public ShowSnapshot(String stackName, String stackID, String snapshotID) { + super(client, HttpMethod.GET, "/stacks/" + stackName + "/" + stackID + "/snapshots/" + snapshotID, null, Snapshot.class); + } + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/StackResource.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/StackResource.java new file mode 100644 index 000000000..de4f9da56 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/StackResource.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat; + +import org.openecomp.appc.adapter.openstack.heat.model.CreateSnapshotParams; +import org.openecomp.appc.adapter.openstack.heat.model.Snapshot; + +import com.woorea.openstack.base.client.Entity; +import com.woorea.openstack.base.client.HttpMethod; +import com.woorea.openstack.base.client.OpenStackClient; +import com.woorea.openstack.base.client.OpenStackRequest; +import com.woorea.openstack.heat.model.Stack; + + +public class StackResource { + + private final OpenStackClient client; + + public StackResource(OpenStackClient client) { + this.client = client; + } + + public ShowStack show(String stackName, String stackID) { + return new ShowStack(stackName, stackID); + } + + public class ShowStack extends OpenStackRequest<Stack> { + public ShowStack(String stackName, String stackID) { + super(client, HttpMethod.GET, "/stacks/" + stackName + "/" + stackID, null, Stack.class); + } + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/CreateSnapshotParams.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/CreateSnapshotParams.java new file mode 100644 index 000000000..e748f716b --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/CreateSnapshotParams.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "name" +}) +public class CreateSnapshotParams { + + @JsonProperty("name") + private String name; + + /** + * + * @return + * The name + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * + * @param name + * The name + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Data.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Data.java new file mode 100644 index 000000000..6a984a4e6 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Data.java @@ -0,0 +1,253 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "status", + "name", + "stack_user_project_id", + "environment", + "template", + "action", + "project_id", + "id", + "resources" +}) +public class Data { + + @JsonProperty("status") + private String status; + @JsonProperty("name") + private String name; + @JsonProperty("stack_user_project_id") + private String stackUserProjectId; + @JsonProperty("environment") + @Valid + private Environment environment; + @JsonProperty("template") + @Valid + private Template template; + @JsonProperty("action") + private String action; + @JsonProperty("project_id") + private String projectId; + @JsonProperty("id") + private String id; + @JsonProperty("resources") + @Valid + private Resources__ resources; + + /** + * + * @return + * The status + */ + @JsonProperty("status") + public String getStatus() { + return status; + } + + /** + * + * @param status + * The status + */ + @JsonProperty("status") + public void setStatus(String status) { + this.status = status; + } + + /** + * + * @return + * The name + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * + * @param name + * The name + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * + * @return + * The stackUserProjectId + */ + @JsonProperty("stack_user_project_id") + public String getStackUserProjectId() { + return stackUserProjectId; + } + + /** + * + * @param stackUserProjectId + * The stack_user_project_id + */ + @JsonProperty("stack_user_project_id") + public void setStackUserProjectId(String stackUserProjectId) { + this.stackUserProjectId = stackUserProjectId; + } + + /** + * + * @return + * The environment + */ + @JsonProperty("environment") + public Environment getEnvironment() { + return environment; + } + + /** + * + * @param environment + * The environment + */ + @JsonProperty("environment") + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + /** + * + * @return + * The template + */ + @JsonProperty("template") + public Template getTemplate() { + return template; + } + + /** + * + * @param template + * The template + */ + @JsonProperty("template") + public void setTemplate(Template template) { + this.template = template; + } + + /** + * + * @return + * The action + */ + @JsonProperty("action") + public String getAction() { + return action; + } + + /** + * + * @param action + * The action + */ + @JsonProperty("action") + public void setAction(String action) { + this.action = action; + } + + /** + * + * @return + * The projectId + */ + @JsonProperty("project_id") + public String getProjectId() { + return projectId; + } + + /** + * + * @param projectId + * The project_id + */ + @JsonProperty("project_id") + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + /** + * + * @return + * The id + */ + @JsonProperty("id") + public String getId() { + return id; + } + + /** + * + * @param id + * The id + */ + @JsonProperty("id") + public void setId(String id) { + this.id = id; + } + + /** + * + * @return + * The resources + */ + @JsonProperty("resources") + public Resources__ getResources() { + return resources; + } + + /** + * + * @param resources + * The resources + */ + @JsonProperty("resources") + public void setResources(Resources__ resources) { + this.resources = resources; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Environment.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Environment.java new file mode 100644 index 000000000..94b7a1585 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Environment.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "parameters", + "resource_registry" +}) +public class Environment { + + @JsonProperty("parameters") + @Valid + private Parameters parameters; + @JsonProperty("resource_registry") + @Valid + private ResourceRegistry resourceRegistry; + + /** + * + * @return + * The parameters + */ + @JsonProperty("parameters") + public Parameters getParameters() { + return parameters; + } + + /** + * + * @param parameters + * The parameters + */ + @JsonProperty("parameters") + public void setParameters(Parameters parameters) { + this.parameters = parameters; + } + + /** + * + * @return + * The resourceRegistry + */ + @JsonProperty("resource_registry") + public ResourceRegistry getResourceRegistry() { + return resourceRegistry; + } + + /** + * + * @param resourceRegistry + * The resource_registry + */ + @JsonProperty("resource_registry") + public void setResourceRegistry(ResourceRegistry resourceRegistry) { + this.resourceRegistry = resourceRegistry; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Metadata.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Metadata.java new file mode 100644 index 000000000..6b4aa00eb --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Metadata.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + +}) +public class Metadata { + + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Parameters.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Parameters.java new file mode 100644 index 000000000..c46fded70 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Parameters.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + +}) +public class Parameters { + + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Properties.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Properties.java new file mode 100644 index 000000000..026daac69 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Properties.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "size" +}) +public class Properties { + + @JsonProperty("size") + private int size; + + /** + * + * @return + * The size + */ + @JsonProperty("size") + public int getSize() { + return size; + } + + /** + * + * @param size + * The size + */ + @JsonProperty("size") + public void setSize(int size) { + this.size = size; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/ResourceData.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/ResourceData.java new file mode 100644 index 000000000..8e3910b2b --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/ResourceData.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "backup_id" +}) +public class ResourceData { + + @JsonProperty("backup_id") + private String backupId; + + /** + * + * @return + * The backupId + */ + @JsonProperty("backup_id") + public String getBackupId() { + return backupId; + } + + /** + * + * @param backupId + * The backup_id + */ + @JsonProperty("backup_id") + public void setBackupId(String backupId) { + this.backupId = backupId; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/ResourceRegistry.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/ResourceRegistry.java new file mode 100644 index 000000000..799dc65b6 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/ResourceRegistry.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "resources" +}) +public class ResourceRegistry { + + @JsonProperty("resources") + @Valid + private Resources resources; + + /** + * + * @return + * The resources + */ + @JsonProperty("resources") + public Resources getResources() { + return resources; + } + + /** + * + * @param resources + * The resources + */ + @JsonProperty("resources") + public void setResources(Resources resources) { + this.resources = resources; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Resources.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Resources.java new file mode 100644 index 000000000..f8b2aeda2 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Resources.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + +}) +public class Resources { + + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Resources_.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Resources_.java new file mode 100644 index 000000000..3ac378aac --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Resources_.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "volume" +}) +public class Resources_ { + + @JsonProperty("volume") + @Valid + private Volume volume; + + /** + * + * @return + * The volume + */ + @JsonProperty("volume") + public Volume getVolume() { + return volume; + } + + /** + * + * @param volume + * The volume + */ + @JsonProperty("volume") + public void setVolume(Volume volume) { + this.volume = volume; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Resources__.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Resources__.java new file mode 100644 index 000000000..2072cf68b --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Resources__.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "volume" +}) +public class Resources__ { + + @JsonProperty("volume") + @Valid + private Volume_ volume; + + /** + * + * @return + * The volume + */ + @JsonProperty("volume") + public Volume_ getVolume() { + return volume; + } + + /** + * + * @param volume + * The volume + */ + @JsonProperty("volume") + public void setVolume(Volume_ volume) { + this.volume = volume; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Snapshot.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Snapshot.java new file mode 100644 index 000000000..47549fc60 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Snapshot.java @@ -0,0 +1,182 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "id", + "name", + "status", + "status_reason", + "creation_time", + "data" +}) +public class Snapshot { + + @JsonProperty("id") + private String id; + @JsonProperty("name") + private String name; + @JsonProperty("status") + private String status; + @JsonProperty("status_reason") + private String statusReason; + @JsonProperty("creation_time") + private String creationTime; + @JsonProperty("data") + @Valid + private Data data; + + /** + * + * @return + * The id + */ + @JsonProperty("id") + public String getId() { + return id; + } + + /** + * + * @param id + * The id + */ + @JsonProperty("id") + public void setId(String id) { + this.id = id; + } + + /** + * + * @return + * The name + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * + * @param name + * The name + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * + * @return + * The status + */ + @JsonProperty("status") + public String getStatus() { + return status; + } + + /** + * + * @param status + * The status + */ + @JsonProperty("status") + public void setStatus(String status) { + this.status = status; + } + + /** + * + * @return + * The statusReason + */ + @JsonProperty("status_reason") + public String getStatusReason() { + return statusReason; + } + + /** + * + * @param statusReason + * The status_reason + */ + @JsonProperty("status_reason") + public void setStatusReason(String statusReason) { + this.statusReason = statusReason; + } + + /** + * + * @return + * The creationTime + */ + @JsonProperty("creation_time") + public String getCreationTime() { + return creationTime; + } + + /** + * + * @param creationTime + * The creation_time + */ + @JsonProperty("creation_time") + public void setCreationTime(String creationTime) { + this.creationTime = creationTime; + } + + /** + * + * @return + * The data + */ + @JsonProperty("data") + public Data getData() { + return data; + } + + /** + * + * @param data + * The data + */ + @JsonProperty("data") + public void setData(Data data) { + this.data = data; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/SnapshotDetails.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/SnapshotDetails.java new file mode 100644 index 000000000..b88e569ef --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/SnapshotDetails.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "snapshot" +}) +public class SnapshotDetails { + + @JsonProperty("snapshot") + @Valid + private Snapshot snapshot; + + /** + * + * @return + * The snapshot + */ + @JsonProperty("snapshot") + public Snapshot getSnapshot() { + return snapshot; + } + + /** + * + * @param snapshot + * The snapshot + */ + @JsonProperty("snapshot") + public void setSnapshot(Snapshot snapshot) { + this.snapshot = snapshot; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/SnapshotRestoreResponse.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/SnapshotRestoreResponse.java new file mode 100644 index 000000000..8fa6e5272 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/SnapshotRestoreResponse.java @@ -0,0 +1,111 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "code", + "message", + "title" +}) +public class SnapshotRestoreResponse { + + @JsonProperty("code") + private String code; + @JsonProperty("message") + private String message; + @JsonProperty("title") + private String title; + + /** + * + * @return + * The code + */ + @JsonProperty("code") + public String getCode() { + return code; + } + + /** + * + * @param code + * The code + */ + @JsonProperty("code") + public void setCode(String code) { + this.code = code; + } + + /** + * + * @return + * The message + */ + @JsonProperty("message") + public String getMessage() { + return message; + } + + /** + * + * @param message + * The message + */ + @JsonProperty("message") + public void setMessage(String message) { + this.message = message; + } + + /** + * + * @return + * The title + */ + @JsonProperty("title") + public String getTitle() { + return title; + } + + /** + * + * @param title + * The title + */ + @JsonProperty("title") + public void setTitle(String title) { + this.title = title; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Template.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Template.java new file mode 100644 index 000000000..ef3aa473c --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Template.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "heat_template_version", + "resources" +}) +public class Template { + + @JsonProperty("heat_template_version") + private String heatTemplateVersion; + @JsonProperty("resources") + @Valid + private Resources_ resources; + + /** + * + * @return + * The heatTemplateVersion + */ + @JsonProperty("heat_template_version") + public String getHeatTemplateVersion() { + return heatTemplateVersion; + } + + /** + * + * @param heatTemplateVersion + * The heat_template_version + */ + @JsonProperty("heat_template_version") + public void setHeatTemplateVersion(String heatTemplateVersion) { + this.heatTemplateVersion = heatTemplateVersion; + } + + /** + * + * @return + * The resources + */ + @JsonProperty("resources") + public Resources_ getResources() { + return resources; + } + + /** + * + * @param resources + * The resources + */ + @JsonProperty("resources") + public void setResources(Resources_ resources) { + this.resources = resources; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Volume.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Volume.java new file mode 100644 index 000000000..26f4cd7e9 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Volume.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "type", + "properties" +}) +public class Volume { + + @JsonProperty("type") + private String type; + @JsonProperty("properties") + @Valid + private Properties properties; + + /** + * + * @return + * The type + */ + @JsonProperty("type") + public String getType() { + return type; + } + + /** + * + * @param type + * The type + */ + @JsonProperty("type") + public void setType(String type) { + this.type = type; + } + + /** + * + * @return + * The properties + */ + @JsonProperty("properties") + public Properties getProperties() { + return properties; + } + + /** + * + * @param properties + * The properties + */ + @JsonProperty("properties") + public void setProperties(Properties properties) { + this.properties = properties; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Volume_.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Volume_.java new file mode 100644 index 000000000..f36808a0d --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/openecomp/appc/adapter/openstack/heat/model/Volume_.java @@ -0,0 +1,206 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.openstack.heat.model; + +import javax.annotation.Generated; +import javax.validation.Valid; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.builder.ToStringBuilder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "status", + "name", + "resource_data", + "resource_id", + "action", + "type", + "metadata" +}) +public class Volume_ { + + @JsonProperty("status") + private String status; + @JsonProperty("name") + private String name; + @JsonProperty("resource_data") + @Valid + private ResourceData resourceData; + @JsonProperty("resource_id") + private String resourceId; + @JsonProperty("action") + private String action; + @JsonProperty("type") + private String type; + @JsonProperty("metadata") + @Valid + private Metadata metadata; + + /** + * + * @return + * The status + */ + @JsonProperty("status") + public String getStatus() { + return status; + } + + /** + * + * @param status + * The status + */ + @JsonProperty("status") + public void setStatus(String status) { + this.status = status; + } + + /** + * + * @return + * The name + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * + * @param name + * The name + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * + * @return + * The resourceData + */ + @JsonProperty("resource_data") + public ResourceData getResourceData() { + return resourceData; + } + + /** + * + * @param resourceData + * The resource_data + */ + @JsonProperty("resource_data") + public void setResourceData(ResourceData resourceData) { + this.resourceData = resourceData; + } + + /** + * + * @return + * The resourceId + */ + @JsonProperty("resource_id") + public String getResourceId() { + return resourceId; + } + + /** + * + * @param resourceId + * The resource_id + */ + @JsonProperty("resource_id") + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + /** + * + * @return + * The action + */ + @JsonProperty("action") + public String getAction() { + return action; + } + + /** + * + * @param action + * The action + */ + @JsonProperty("action") + public void setAction(String action) { + this.action = action; + } + + /** + * + * @return + * The type + */ + @JsonProperty("type") + public String getType() { + return type; + } + + /** + * + * @param type + * The type + */ + @JsonProperty("type") + public void setType(String type) { + this.type = type; + } + + /** + * + * @return + * The metadata + */ + @JsonProperty("metadata") + public Metadata getMetadata() { + return metadata; + } + + /** + * + * @param metadata + * The metadata + */ + @JsonProperty("metadata") + public void setMetadata(Metadata metadata) { + this.metadata = metadata; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/resources/com/att/cdp/default.properties b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/resources/com/att/cdp/default.properties new file mode 100644 index 000000000..6a11d7214 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/resources/com/att/cdp/default.properties @@ -0,0 +1,158 @@ +### +# ============LICENSE_START======================================================= +# openECOMP : APP-C +# ================================================================================ +# 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========================================================= +### + +# +# Default Properties - Configured for integration of CDP into APPC +# +#-------------------------------------------------------------------------------------------- +# The path and file used to load configuration settings, if any +com.att.cdp.bootstrap.path=${user.home},src/main/config,/etc/aft/scld/,/opt/app/aft/scld/etc/,/opt/app/aft/cdp/etc/,C:/Program Files/aft/scld/etc/,etc,../etc,. +com.att.cdp.bootstrap.file=cdp.properties +# com.att.cdp.system.admins= +# +# AFT properties for lat/long/environment and platform +# +AFT_LATITUDE=12.3456 +AFT_LONGITUDE=-12.3456 +AFT_ENVIRONMENT=AFT-ENVIRONMENT +SCLD_PLATFORM=OPEN-SOURCE +# +# The versions of CDP API, CDP itself, and the build number +# +API_VERSION=${version} +CDP_VERSION=${version} +CDP_BUILD=${buildNumber} +# +# The path to search for logging configuration document, and the name of the document +# +com.att.cdp.logging.path=${user.home},src/main/config,etc,../etc,. +com.att.cdp.logging.file=logback.xml +# +# The resource bundle base name to be loaded for message resources. This property can be a comma delimited list of resources to be +# loaded, allowing multiple resource bundles to be loaded simultaneously (for the same locale). +# +com.att.cdp.resources=com/att/cdp/StrategyServiceMessages +# +# Logger names used in the application +# +com.att.cdp.logger=org.openecomp.appc +com.att.cdp.security.logger=org.openecomp.appc.security +com.att.cdp.perf.logger=org.openecomp.appc.perf +com.att.cdp.gui.logger=org.openecomp.appc.gui +com.att.cdp.server.logger=org.openecomp.appc.server +com.att.cdp.coordinator.logger=org.openecomp.appc.coordinator +com.att.cdp.policy.logger=org.openecomp.appc.policy + +# +# This property allows to 'simulate' SSH processes within engine. +# By default, it is set to 'false' - So that it allows to actually execute SSH process. If 'true', it will 'simulate' SSH processes +# +com.att.cdp.ssh.simulate=false +# +# These properties are used to specify the default stack metadata path and file names written and read on each server node +# +com.att.cdp.metadata.path=/etc/cdp/metadata +com.att.cdp.metadata.export.filename=stack.xml +com.att.cdp.metadata.import.filename=stack.xml +# +#Below properties are to specify minimum and maximum bootstrap time in minutes. +#These properties are ONLY supposed to be used in tandem with SSH simulation.(testing purpose) +com.att.cdp.ssh.simulate.minBootstrapTime=6 +com.att.cdp.ssh.simulate.maxBootstrapTime=12 +# +# +# These properties are used to configure the AAF security interface +# +# com.att.cdp.aaf.connection.url = dme2 url to connect to aaf service +# com.att.cdp.aaf.connection.timeout = connection timeout, in seconds +# com.att.cdp.aaf.cache.flush = cache flush interval in minutes +# com.att.cdp.aaf.cache.size = the maximum number of cache entries +# com.att.cdp.aaf.auth.principal = The principal id we use to authenticate ourself to AAF +# com.att.cdp.aaf.auth.credentials = The credentials (password) we use to authenticate ourself to AAF +# +com.att.cdp.aaf.connection.url=https://DME2SITE/service=com.att.authz.AuthorizationService/version=2.0/envContext=TEST/routeOffer=BAU_SE +com.att.cdp.aaf.connection.timeout=10 +com.att.cdp.aaf.cache.flush=5 +com.att.cdp.aaf.cache.size=400 +com.att.cdp.aaf.auth.principal=emailaddress@example.com +com.att.cdp.aaf.auth.credentials=MyPassw0rd +# +# ---------------------------------------------------------------------------------------------------- +# These properties are used to configure the operation of the StackBuilder engine +# +# maximum number of build manager threads in the thread pool +com.att.cdp.engine.maxManagerPool=30 +# max number of worker threads in the pool for use by workers +com.att.cdp.engine.MaxWorkerPool=300 + +# max number of workers that can be created per build request (set to 1 to single-thread a build) +com.att.cdp.engine.maxWorkers=10 +# Maximum amount of time to wait for a provider to complete any requested operation, in minutes. Such +# as creating a server or a volume. +com.att.cdp.engine.maxWaitTime=15 +# +# ---------------------------------------------------------------------------------------------------- +# These properties are used to configure the managed node hostname generation/resolution process +# +com.att.cdp.managed.hostname.resolve.retry=3 +# ---------------------------------------------------------------------------------------------------- +# +# Cassandra Connection Configuration Properties +# +cassandra.userName=cassandra +cassandra.password=cassandra +#cassandra.dataCenter= +cassandra.hosts=127.0.0.1 +cassandra.port=9042 +cassandra.keyspace=cdp +cassandra.minPoolSize=8 +cassandra.maxPoolSize=8 +cassandra.readtimeout=180000 +# +# Cassandra data Migration toggle +com.att.cdp.db.migration=true +com.att.cdp.db.update=true + +#Default Values for Image Attributes Configuration.These SHOULD NOT be removed. +image.default.namepattern=.* +image.default.user=root +image.default.sudo=false + +# ---------------------------------------------------------------------------------------------------- +# +# The path OSSupport will search for OS configuration properties files +# +com.att.cdp.OSType.path=/etc/os/ +# ---------------------------------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------------------------------- +# +# The properties used in ConnectivityBuilder +internet_url=www.google.com +ubuntu_sat_access_url=example.com +grm_server_url=example.com +# +# ---------------------------------------------------------------------------------------------------- +com.att.cdp.ptr.cleanup=true + +# ---------------------------------------------------------------------------------------------------- +# The maximum amount of time in seconds that we should wait for input from the shell +com.att.cdp.ssh.timeout=1800 diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/resources/org/openecomp/appc/default.properties b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/resources/org/openecomp/appc/default.properties new file mode 100644 index 000000000..259cc1ba7 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/resources/org/openecomp/appc/default.properties @@ -0,0 +1,102 @@ +### +# ============LICENSE_START======================================================= +# openECOMP : APP-C +# ================================================================================ +# 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========================================================= +### + +# +# Default properties for the APP-C Provider Adapter +# +# ------------------------------------------------------------------------------------------------- +# +# Define the name and path of any user-provided configuration (bootstrap) file that can be loaded +# to supply configuration options +org.openecomp.appc.bootstrap.file=appc.properties +org.openecomp.appc.bootstrap.path=/opt/openecomp/appc/data/properties,${user.home},. + +appc.application.name=APPC + +# +# Define the message resource bundle name to be loaded +org.openecomp.appc.resources=org/openecomp/appc/i18n/MessageResources +# +# The name of the adapter. +org.openecomp.appc.provider.adaptor.name=org.openecomp.appc.appc_provider_adapter +# +# Set up the logging environment +# +org.openecomp.appc.logging.file=org/openecomp/appc/logback.xml +org.openecomp.appc.logging.path=${user.home};etc;../etc +org.openecomp.appc.logger=org.openecomp.appc +org.openecomp.appc.security.logger=org.openecomp.appc.security +# +# The minimum and maximum provider/tenant context pool sizes. Min=1 means that as soon +# as the provider/tenant is referenced a Context is opened and added to the pool. Max=0 +# means that the upper bound on the pool is unbounded. +org.openecomp.appc.provider.min.pool=1 +org.openecomp.appc.provider.max.pool=0 + +# +# The following properties are used to configure the retry logic for connection to the +# IaaS provider(s). The retry delay property is the amount of time, in seconds, the +# application waits between retry attempts. The retry limit is the number of retries +# that are allowed before the request is failed. +org.openecomp.appc.provider.retry.delay = 30 +org.openecomp.appc.provider.retry.limit = 10 + +# +# The trusted hosts list for SSL access when a certificate is not provided. +# +provider.trusted.hosts=* +# +# The amount of time, in seconds, to wait for a server state change (start->stop, stop->start, etc). +# If the server does not change state to a valid state within the alloted time, the operation +# fails. +org.openecomp.appc.server.state.change.timeout=300 +# +# The amount of time to wait, in seconds, between subsequent polls to the OpenStack provider +# to refresh the status of a resource we are waiting on. +# +org.openecomp.appc.openstack.poll.interval=20 + + # + #The amount of time, in seconds, that the application waits for a change of state of a stacj to a known valid + #sate before giving up and failing the request. + # +org.openecomp.appc.stack.state.change.timeout=100 + + + +# +# The connection information to connect to the provider we are using. These properties +# are "structured" properties, in that the name is a compound name, where the nodes +# of the name can be ordered (1, 2, 3, ...). All of the properties with the same ordinal +# position are defining the same entity. For example, provider1.type and provider1.name +# are defining the same provider, whereas provider2.name and provider2.type are defining +# the values for a different provider. Any number of providers can be defined in this +# way. +# +# Don't change these 2 right now since they are hard coded in the DG +provider1.type=appc +provider1.name=appc + +#These you can change +provider1.identity=appc +provider1.tenant1.name=appc +provider1.tenant1.userid=appc +provider1.tenant1.password=appc diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestIdentityUrl.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestIdentityUrl.java new file mode 100644 index 000000000..4f797f859 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestIdentityUrl.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import static org.junit.Assert.assertNotNull; + +import java.util.Properties; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.openecomp.appc.adapter.iaas.impl.IdentityURL; +import org.openecomp.appc.configuration.ConfigurationFactory; + +public class TestIdentityUrl { + + private static String URL; + + @BeforeClass + public static void before() { + Properties props = ConfigurationFactory.getConfiguration().getProperties(); + URL = props.getProperty(""); + } + + /** + * Test that we can parse and interpret valid URLs + */ + @Test + public void testValidURLs() { + URL = "http://192.168.1.1:5000/v2.0/"; + IdentityURL idurl = IdentityURL.parseURL(URL); + assertNotNull(idurl); + System.out.println(idurl.getVersion()); + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestProviderAdapterImpl.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestProviderAdapterImpl.java new file mode 100644 index 000000000..d83c18b04 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestProviderAdapterImpl.java @@ -0,0 +1,943 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.openecomp.appc.Constants; +import org.openecomp.appc.adapter.iaas.ProviderAdapter; +import org.openecomp.appc.adapter.iaas.impl.ProviderAdapterImpl; +import org.openecomp.appc.adapter.iaas.impl.ProviderCache; +import org.openecomp.appc.adapter.iaas.impl.ServiceCatalog; +import org.openecomp.appc.adapter.iaas.impl.TenantCache; +import org.openecomp.appc.adapter.iaas.impl.VMURL; +import org.openecomp.appc.configuration.ConfigurationFactory; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.exceptions.UnknownProviderException; +import com.att.cdp.exceptions.ZoneException; +import com.att.cdp.zones.ComputeService; +import com.att.cdp.zones.Context; +import com.att.cdp.zones.ContextFactory; +import com.att.cdp.zones.model.Image; +import com.att.cdp.zones.model.Server; +import com.att.cdp.zones.model.Server.Status; +import org.openecomp.sdnc.sli.SvcLogicContext; + +import com.woorea.openstack.keystone.model.Access.Service.Endpoint; + +/** + * Test the ProviderAdapter implementation. + */ +@Category(org.openecomp.appc.adapter.iaas.impl.TestProviderAdapterImpl.class) +public class TestProviderAdapterImpl { + + @SuppressWarnings("nls") + private static final String PROVIDER_NAME = "ILAB"; + + @SuppressWarnings("nls") + private static final String PROVIDER_TYPE = "OpenStackProvider"; + + private static String IDENTITY_URL; + + private static String PRINCIPAL; + + private static String CREDENTIAL; + + private static String TENANT_NAME; + + private static String TENANT_ID; + + private static String USER_ID; + + private static String REGION_NAME; + + private static String SERVER_URL; + + private static Class<?> providerAdapterImplClass; + private static Class<?> configurationFactoryClass; + private static Field providerCacheField; + private static Field configField; + + private ProviderAdapterImpl adapter; + + /** + * Use reflection to locate fields and methods so that they can be manipulated during the test to change the + * internal state accordingly. + * + * @throws NoSuchFieldException + * if the field(s) dont exist + * @throws SecurityException + * if reflective access is not allowed + * @throws NoSuchMethodException + * If the method(s) dont exist + */ + @SuppressWarnings("nls") + @BeforeClass + public static void once() throws NoSuchFieldException, SecurityException, NoSuchMethodException { + providerAdapterImplClass = ProviderAdapterImpl.class; + configurationFactoryClass = ConfigurationFactory.class; + + providerCacheField = providerAdapterImplClass.getDeclaredField("providerCache"); + providerCacheField.setAccessible(true); + + configField = configurationFactoryClass.getDeclaredField("config"); + configField.setAccessible(true); + + Properties props = ConfigurationFactory.getConfiguration().getProperties(); + IDENTITY_URL = props.getProperty("provider1.identity"); + PRINCIPAL = props.getProperty("provider1.tenant1.userid", "appc"); + CREDENTIAL = props.getProperty("provider1.tenant1.password", "appc"); + TENANT_NAME = props.getProperty("provider1.tenant1.name", "appc"); + TENANT_ID = props.getProperty("provider1.tenant1.id", "abcde12345fghijk6789lmnopq123rst"); + REGION_NAME = props.getProperty("provider1.tenant1.region", "RegionOne"); + SERVER_URL = props.getProperty("test.url"); + } + + /** + * Setup the test environment. + * + * @throws IllegalAccessException + * if this Field object is enforcing Java language access control and the underlying field is either + * inaccessible or final. + * @throws IllegalArgumentException + * if the specified object is not an instance of the class or interface declaring the underlying field + * (or a subclass or implementor thereof), or if an unwrapping conversion fails. + * @throws NullPointerException + * if the specified object is null and the field is an instance field. + * @throws ExceptionInInitializerError + * if the initialization provoked by this method fails. + */ + @Before + public void setup() throws IllegalArgumentException, IllegalAccessException { + configField.set(null, null); + Properties properties = new Properties(); + adapter = new ProviderAdapterImpl(properties); + } + + /** + * This method inspects the provider adapter implementation to make sure that the cache of providers and tenants, as + * well as the service catalog, and all pools of contexts have been set up correctly. + * + * @throws IllegalAccessException + * if this Field object is enforcing Java language access control and the underlying field is + * inaccessible. + * @throws IllegalArgumentException + * if the specified object is not an instance of the class or interface declaring the underlying field + * (or a subclass or implementor thereof). + */ + @SuppressWarnings({ + "unchecked" + }) + @Ignore + @Test + public void validateCacheIsCreatedCorrectly() throws IllegalArgumentException, IllegalAccessException { + Map<String, ProviderCache> providerCaches = (Map<String, ProviderCache>) providerCacheField.get(adapter); + + assertNotNull(providerCaches); + assertEquals(1, providerCaches.size()); + assertTrue(providerCaches.containsKey(PROVIDER_NAME)); + + ProviderCache providerCache = providerCaches.get(PROVIDER_NAME); + assertEquals(PROVIDER_NAME, providerCache.getProviderName()); + assertEquals(PROVIDER_TYPE, providerCache.getProviderType()); + + Map<String, TenantCache> tenantCaches = providerCache.getTenants(); + assertNotNull(tenantCaches); + assertEquals(1, tenantCaches.size()); + assertTrue(tenantCaches.containsKey(TENANT_NAME)); + + TenantCache tenantCache = tenantCaches.get(TENANT_NAME); + + assertEquals(TENANT_ID, tenantCache.getTenantId()); + assertEquals(TENANT_NAME, tenantCache.getTenantName()); + assertEquals(USER_ID, tenantCache.getUserid()); + + ServiceCatalog catalog = tenantCache.getServiceCatalog(); + assertNotNull(catalog); + + System.out.println(catalog.toString()); + List<String> serviceTypes = catalog.getServiceTypes(); + assertNotNull(serviceTypes); + assertEquals(12, serviceTypes.size()); + + assertEquals(TENANT_NAME, catalog.getTenantName()); + assertEquals(TENANT_ID, catalog.getTenantId()); + + Set<String> regionNames = catalog.getRegions(); + assertNotNull(regionNames); + assertEquals(1, regionNames.size()); + assertTrue(regionNames.contains(REGION_NAME)); + + List<Endpoint> endpoints = catalog.getEndpoints(ServiceCatalog.IDENTITY_SERVICE); + assertNotNull(endpoints); + assertEquals(1, endpoints.size()); + Endpoint endpoint = endpoints.get(0); + assertNotNull(endpoint); + assertEquals(REGION_NAME, endpoint.getRegion()); + assertEquals(IDENTITY_URL, endpoint.getPublicURL()); + + endpoints = catalog.getEndpoints(ServiceCatalog.COMPUTE_SERVICE); + assertNotNull(endpoints); + assertEquals(1, endpoints.size()); + endpoint = endpoints.get(0); + assertNotNull(endpoint); + assertEquals(REGION_NAME, endpoint.getRegion()); + + endpoints = catalog.getEndpoints(ServiceCatalog.VOLUME_SERVICE); + assertNotNull(endpoints); + assertEquals(1, endpoints.size()); + endpoint = endpoints.get(0); + assertNotNull(endpoint); + assertEquals(REGION_NAME, endpoint.getRegion()); + + endpoints = catalog.getEndpoints(ServiceCatalog.IMAGE_SERVICE); + assertNotNull(endpoints); + assertEquals(1, endpoints.size()); + endpoint = endpoints.get(0); + assertNotNull(endpoint); + assertEquals(REGION_NAME, endpoint.getRegion()); + + endpoints = catalog.getEndpoints(ServiceCatalog.NETWORK_SERVICE); + assertNotNull(endpoints); + assertEquals(1, endpoints.size()); + endpoint = endpoints.get(0); + assertNotNull(endpoint); + assertEquals(REGION_NAME, endpoint.getRegion()); + + assertTrue(catalog.isServicePublished(ServiceCatalog.IDENTITY_SERVICE)); + assertTrue(catalog.isServicePublished(ServiceCatalog.COMPUTE_SERVICE)); + assertTrue(catalog.isServicePublished(ServiceCatalog.VOLUME_SERVICE)); + assertTrue(catalog.isServicePublished(ServiceCatalog.IMAGE_SERVICE)); + assertTrue(catalog.isServicePublished(ServiceCatalog.NETWORK_SERVICE)); + } + + /** + * This test case is used to actually validate that a server has been restarted from an already running state + * + * @throws ZoneException + * If the login cannot be performed because the principal and/or credentials are invalid. + * @throws IllegalArgumentException + * If the principal and/or credential are null or empty, or if the expected argument(s) are not defined + * or are invalid + * @throws IllegalStateException + * If the identity service is not available or cannot be created + * @throws IOException + * if an I/O error occurs + * @throws UnknownProviderException + * If the provider cannot be found + */ + // @Ignore + @Test + public void testRestartRunningServer() + throws IllegalStateException, IllegalArgumentException, ZoneException, UnknownProviderException, IOException { + Properties properties = new Properties(); + properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, IDENTITY_URL); + properties.setProperty(ContextFactory.PROPERTY_REGION, REGION_NAME); + properties.setProperty(ContextFactory.PROPERTY_TENANT, TENANT_NAME); + properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + properties.setProperty(ContextFactory.PROPERTY_DISABLE_PROXY, "true"); + + try (Context context = ContextFactory.getContext(PROVIDER_TYPE, properties)) { + context.login(PRINCIPAL, CREDENTIAL); + VMURL vm = VMURL.parseURL(SERVER_URL); + + ComputeService computeService = context.getComputeService(); + Server server = computeService.getServer(vm.getServerId()); + if (!server.getStatus().equals(Status.RUNNING)) { + server.start(); + assertTrue(waitForStateChange(server, Status.RUNNING)); + } + + Map<String, String> params = new HashMap<>(); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, SERVER_URL); + params.put(ProviderAdapter.PROPERTY_PROVIDER_NAME, PROVIDER_NAME); + SvcLogicContext svcContext = new SvcLogicContext(); + + server = adapter.restartServer(params, svcContext); + + assertEquals(Server.Status.RUNNING, server.getStatus()); + } + } + + + /****************************************/ + /** + * Tests that the vmStatuschecker method works and returns the correct status of the VM requested + * + * @throws ZoneException + * If the login cannot be performed because the principal and/or credentials are invalid. + * @throws IllegalArgumentException + * If the principal and/or credential are null or empty, or if the expected argument(s) are not defined + * or are invalid + * @throws IllegalStateException + * If the identity service is not available or cannot be created + * @throws IOException + * if an I/O error occurs + * @throws UnknownProviderException + * If the provider cannot be found + */ + // @Ignore + @Test + public void testVmStatuschecker() throws IllegalStateException, IllegalArgumentException, ZoneException, + UnknownProviderException, IOException { + Properties properties = new Properties(); + properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, IDENTITY_URL); + properties.setProperty(ContextFactory.PROPERTY_REGION, REGION_NAME); + properties.setProperty(ContextFactory.PROPERTY_TENANT, TENANT_NAME); + properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + properties.setProperty(ContextFactory.PROPERTY_DISABLE_PROXY, "true"); + + try (Context context = ContextFactory.getContext(PROVIDER_TYPE, properties)) { + context.login(PRINCIPAL, CREDENTIAL); + VMURL vm = VMURL.parseURL(SERVER_URL); + + ComputeService computeService = context.getComputeService(); + Server server = computeService.getServer(vm.getServerId()); + if (!server.getStatus().equals(Status.RUNNING)) { + server.start(); + assertTrue(waitForStateChange(server, Status.RUNNING));} + //or instead of the if-block, can ensureRunning(server) be used? + ensureRunning(server); + assertEquals(Server.Status.RUNNING, server.getStatus()); + } + } + /****************************************/ + + + /** + * Tests that we can restart a server that is already stopped + * + * @throws ZoneException + * If the login cannot be performed because the principal and/or credentials are invalid. + * @throws IllegalArgumentException + * If the principal and/or credential are null or empty, or if the expected argument(s) are not defined + * or are invalid. + * @throws IllegalStateException + * If the identity service is not available or cannot be created + * @throws UnknownProviderException + * If the provider cannot be found + * @throws IOException + * if an I/O error occurs + */ + // @Ignore + @Test + public void testRestartStoppedServer() + throws IllegalStateException, IllegalArgumentException, ZoneException, UnknownProviderException, IOException { + Properties properties = new Properties(); + properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, IDENTITY_URL); + properties.setProperty(ContextFactory.PROPERTY_REGION, REGION_NAME); + properties.setProperty(ContextFactory.PROPERTY_TENANT, TENANT_NAME); + properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + + try (Context context = ContextFactory.getContext(PROVIDER_TYPE, properties)) { + context.login(PRINCIPAL, CREDENTIAL); + VMURL vm = VMURL.parseURL(SERVER_URL); + + ComputeService computeService = context.getComputeService(); + Server server = computeService.getServer(vm.getServerId()); + if (!server.getStatus().equals(Status.READY)) { + server.stop(); + assertTrue(waitForStateChange(server, Status.READY)); + } + + Map<String, String> params = new HashMap<>(); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, SERVER_URL); + params.put(ProviderAdapter.PROPERTY_PROVIDER_NAME, PROVIDER_NAME); + SvcLogicContext svcContext = new SvcLogicContext(); + + server = adapter.restartServer(params, svcContext); + + assertEquals(Server.Status.RUNNING, server.getStatus()); + + } + } + + /** + * Tests that we can rebuild a running server (not created from a bootable volume) + * + * @throws ZoneException + * If the login cannot be performed because the principal and/or credentials are invalid. + * @throws IllegalArgumentException + * If the principal and/or credential are null or empty, or if the expected argument(s) are not defined + * or are invalid. + * @throws IllegalStateException + * If the identity service is not available or cannot be created + * @throws UnknownProviderException + * If the provider cannot be found + * @throws IOException + * if an I/O error occurs + * @throws APPCException + * If the server cannot be rebuilt for some reason + */ + // @Ignore + @Test + public void testRebuildRunningServer() + throws IOException, IllegalStateException, IllegalArgumentException, ZoneException, APPCException { + Properties properties = new Properties(); + properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, IDENTITY_URL); + properties.setProperty(ContextFactory.PROPERTY_REGION, REGION_NAME); + properties.setProperty(ContextFactory.PROPERTY_TENANT, TENANT_NAME); + properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + + try (Context context = ContextFactory.getContext(PROVIDER_TYPE, properties)) { + context.login(PRINCIPAL, CREDENTIAL); + VMURL vm = VMURL.parseURL(SERVER_URL); + + ComputeService computeService = context.getComputeService(); + Server server = computeService.getServer(vm.getServerId()); + ensureRunning(server); + + Map<String, String> params = new HashMap<>(); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, SERVER_URL); + params.put(ProviderAdapter.PROPERTY_PROVIDER_NAME, PROVIDER_NAME); + SvcLogicContext svcContext = new SvcLogicContext(); + + server = adapter.rebuildServer(params, svcContext); + assertTrue(waitForStateChange(server, Status.RUNNING)); + + } + } + + /** + * Tests that we can rebuild a paused server (not created from a bootable volume) + * + * @throws ZoneException + * If the login cannot be performed because the principal and/or credentials are invalid. + * @throws IllegalArgumentException + * If the principal and/or credential are null or empty, or if the expected argument(s) are not defined + * or are invalid. + * @throws IllegalStateException + * If the identity service is not available or cannot be created + * @throws UnknownProviderException + * If the provider cannot be found + * @throws IOException + * if an I/O error occurs + * @throws APPCException + * If the server cannot be rebuilt for some reason + */ + // @Ignore + @Test + public void testRebuildPausedServer() + throws IOException, IllegalStateException, IllegalArgumentException, ZoneException, APPCException { + Properties properties = new Properties(); + properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, IDENTITY_URL); + properties.setProperty(ContextFactory.PROPERTY_REGION, REGION_NAME); + properties.setProperty(ContextFactory.PROPERTY_TENANT, TENANT_NAME); + properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + + try (Context context = ContextFactory.getContext(PROVIDER_TYPE, properties)) { + context.login(PRINCIPAL, CREDENTIAL); + VMURL vm = VMURL.parseURL(SERVER_URL); + + ComputeService computeService = context.getComputeService(); + Server server = computeService.getServer(vm.getServerId()); + ensurePaused(server); + + Map<String, String> params = new HashMap<>(); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, SERVER_URL); + params.put(ProviderAdapter.PROPERTY_PROVIDER_NAME, PROVIDER_NAME); + SvcLogicContext svcContext = new SvcLogicContext(); + + server = adapter.rebuildServer(params, svcContext); + assertTrue(waitForStateChange(server, Status.RUNNING)); + } + } + + /** + * Tests that we can rebuild a paused server (not created from a bootable volume) + * + * @throws ZoneException + * If the login cannot be performed because the principal and/or credentials are invalid. + * @throws IllegalArgumentException + * If the principal and/or credential are null or empty, or if the expected argument(s) are not defined + * or are invalid. + * @throws IllegalStateException + * If the identity service is not available or cannot be created + * @throws UnknownProviderException + * If the provider cannot be found + * @throws IOException + * if an I/O error occurs + * @throws APPCException + * If the server cannot be rebuilt for some reason + */ + // @Ignore + @Test + public void testRebuildSuspendedServer() + throws IOException, IllegalStateException, IllegalArgumentException, ZoneException, APPCException { + Properties properties = new Properties(); + properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, IDENTITY_URL); + properties.setProperty(ContextFactory.PROPERTY_REGION, REGION_NAME); + properties.setProperty(ContextFactory.PROPERTY_TENANT, TENANT_NAME); + properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + + try (Context context = ContextFactory.getContext(PROVIDER_TYPE, properties)) { + context.login(PRINCIPAL, CREDENTIAL); + VMURL vm = VMURL.parseURL(SERVER_URL); + + ComputeService computeService = context.getComputeService(); + Server server = computeService.getServer(vm.getServerId()); + ensureSuspended(server); + + Map<String, String> params = new HashMap<>(); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, SERVER_URL); + params.put(ProviderAdapter.PROPERTY_PROVIDER_NAME, PROVIDER_NAME); + SvcLogicContext svcContext = new SvcLogicContext(); + + server = adapter.rebuildServer(params, svcContext); + assertTrue(waitForStateChange(server, Status.RUNNING)); + } + } + + /** + * Tests that we can rebuild a paused server (not created from a bootable volume) + * + * @throws ZoneException + * If the login cannot be performed because the principal and/or credentials are invalid. + * @throws IllegalArgumentException + * If the principal and/or credential are null or empty, or if the expected argument(s) are not defined + * or are invalid. + * @throws IllegalStateException + * If the identity service is not available or cannot be created + * @throws UnknownProviderException + * If the provider cannot be found + * @throws IOException + * if an I/O error occurs + * @throws APPCException + * If the server cannot be rebuilt for some reason + */ + // @Ignore + @Test + public void testRebuildStoppedServer() + throws IOException, IllegalStateException, IllegalArgumentException, ZoneException, APPCException { + Properties properties = new Properties(); + properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, IDENTITY_URL); + properties.setProperty(ContextFactory.PROPERTY_REGION, REGION_NAME); + properties.setProperty(ContextFactory.PROPERTY_TENANT, TENANT_NAME); + properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + + try (Context context = ContextFactory.getContext(PROVIDER_TYPE, properties)) { + context.login(PRINCIPAL, CREDENTIAL); + VMURL vm = VMURL.parseURL(SERVER_URL); + + ComputeService computeService = context.getComputeService(); + Server server = computeService.getServer(vm.getServerId()); + ensureStopped(server); + + Map<String, String> params = new HashMap<>(); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, SERVER_URL); + params.put(ProviderAdapter.PROPERTY_PROVIDER_NAME, PROVIDER_NAME); + SvcLogicContext svcContext = new SvcLogicContext(); + + server = adapter.rebuildServer(params, svcContext); + assertTrue(waitForStateChange(server, Status.RUNNING)); + } + } + + /** + * Test subsequent action on second vm in different Tenant resulting in {"itemNotFound": {"message": "Instance could not be found", "code": 404}} + * + * @throws ZoneException + * If the login cannot be performed because the principal and/or credentials are invalid. + * @throws IllegalArgumentException + * If the principal and/or credential are null or empty, or if the expected argument(s) are not defined + * or are invalid + * @throws IllegalStateException + * If the identity service is not available or cannot be created + * @throws IOException + * if an I/O error occurs + * @throws APPCException + */ + + @Test + public void testTenantVerification() throws IllegalStateException, IllegalArgumentException, ZoneException, + IOException, APPCException { + + Properties properties = new Properties(); + properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, "http://example.com:5000"); + properties.setProperty(ContextFactory.PROPERTY_TENANT, "APP-C"); + properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + + String vmUrl = + "http://192.168.1.2:8774/v2/abcde12345fghijk6789lmnopq123rst/servers/abc12345-1234-5678-890a-abcdefg12345"; + + //try (Context context = ContextFactory.getContext(PROVIDER_TYPE, properties)) { + // context.login("AppC", "AppC"); + + // call lookupServer on vm in defined tenant "APP-C_TLV" + VMURL vm = VMURL.parseURL(vmUrl); + + Map<String, String> params = new HashMap<>(); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, vmUrl); + params.put(ProviderAdapter.PROPERTY_IDENTITY_URL, "http://example.com:5000/v2.0"); + params.put(ProviderAdapter.PROPERTY_PROVIDER_NAME, "http://example.com:5000/v2.0"); + SvcLogicContext svcContext = new SvcLogicContext(); + + long start, end = 0; + + System.out.println("\n--------------------Begin lookupServer on tenant 1--------------------"); + start = System.currentTimeMillis(); + Server server = adapter.lookupServer(params, svcContext); + end = System.currentTimeMillis(); + + System.out.println(String.format("lookupServer on tenant 1 took %ds", (end - start) / 1000)); + System.out.println("----------------------------------------------------------------------\n"); + assertNotNull(server); + + //repeat to show that context is reused for second request + System.out.println("\n-----------------Begin repeat lookupServer on tenant 1----------------"); + start = System.currentTimeMillis(); + server = adapter.lookupServer(params, svcContext); + end = System.currentTimeMillis(); + + System.out.println(String.format("Repeat lookupServer on tenant 1 took %ds", (end - start) / 1000)); + System.out.println("----------------------------------------------------------------------\n"); + assertNotNull(server); + + // call lookupServer on vm in second tenant "Play" + // This is where we would fail due to using the previous + // tenants context + vmUrl = "http://192.168.1.2:8774/v2/abcde12345fghijk6789lmnopq123rst/servers/abc12345-1234-5678-890a-abcdefg12345"; + vm = VMURL.parseURL(vmUrl); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, vmUrl); + + System.out.println("\n--------------------Begin lookupServer on tenant 2--------------------"); + start = System.currentTimeMillis(); + server = adapter.lookupServer(params, svcContext); + end = System.currentTimeMillis(); + System.out.println(String.format("\nlookupServer on tenant 2 took %ds", (end - start) / 1000)); + System.out.println("----------------------------------------------------------------------\n"); + assertNotNull(server); + + // call lookupServer on vm in non-existing tenant + vmUrl = "http://192.168.1.2:8774/v2/abcde12345fghijk6789lmnopq123rst/servers/abc12345-1234-5678-890a-abcdefg12345"; + vm = VMURL.parseURL(vmUrl); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, vmUrl); + + System.out.println("\n--------------Begin lookupServer on non-existant tenant--------------"); + start = System.currentTimeMillis(); + server = adapter.lookupServer(params, svcContext); + end = System.currentTimeMillis(); + System.out.println(String.format("\nlookupServer on tenant 3 took %ds", (end - start) / 1000)); + System.out.println("----------------------------------------------------------------------\n"); + assertNull(server); + + //} + } + /****************************************/ + + + @Test + public void testSnapshotServer() throws Exception { + Properties properties = new Properties(); + properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, "http://example.com:5000"); + // properties.setProperty(ContextFactory.PROPERTY_REGION, ""); + properties.setProperty(ContextFactory.PROPERTY_TENANT, "Play"); + properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + + String vmUrl = + "http://192.168.1.2:8774/v2/abcde12345fghijk6789lmnopq123rst/servers/abc12345-1234-5678-890a-abcdefg12345"; + + try (Context context = ContextFactory.getContext(PROVIDER_TYPE, properties)) { + context.login("AppC", "AppC"); + VMURL vm = VMURL.parseURL(vmUrl); + + Map<String, String> params = new HashMap<>(); + params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, vmUrl); + params.put(ProviderAdapter.PROPERTY_IDENTITY_URL, "http://example.com:5000/v2.0"); + params.put(ProviderAdapter.PROPERTY_PROVIDER_NAME, "http://example.com:5000/v2.0"); + SvcLogicContext svcContext = new SvcLogicContext(); + + long start, end = 0; + + start = System.currentTimeMillis(); + Image image = adapter.createSnapshot(params, svcContext); + end = System.currentTimeMillis(); + + System.out.println(String.format("Image ID: %s", image.getId())); + System.out.println(String.format("Snapshot took %ds", (end - start) / 1000)); + + start = System.currentTimeMillis(); + adapter.rebuildServer(params, svcContext); + end = System.currentTimeMillis(); + System.out.println(String.format("Rebuild took %ds", (end - start) / 1000)); + } + + } + + /** + * Ensures that the server is in stopped (shutdown) state prior to test + * + * @param server + * The server to ensure is stopped + * @throws ZoneException + * If the server can't be operated upon for some reason + */ + @SuppressWarnings("nls") + private static void ensureStopped(Server server) throws ZoneException { + switch (server.getStatus()) { + case READY: + break; + + case PENDING: + waitForStateChange(server, Server.Status.READY, Server.Status.RUNNING, Server.Status.PAUSED, + Server.Status.SUSPENDED, Server.Status.ERROR); + ensureSuspended(server); + break; + + case PAUSED: + server.unpause(); + waitForStateChange(server, Server.Status.RUNNING); + server.stop(); + waitForStateChange(server, Server.Status.READY); + break; + + case SUSPENDED: + server.resume(); + waitForStateChange(server, Server.Status.RUNNING); + server.stop(); + waitForStateChange(server, Server.Status.READY); + break; + + case RUNNING: + server.stop(); + waitForStateChange(server, Server.Status.READY); + break; + + case DELETED: + case ERROR: + default: + fail("Server state is not valid for test - " + server.getStatus().name()); + } + } + + /** + * Ensures that the server is in suspended state prior to test + * + * @param server + * The server to ensure is suspended + * @throws ZoneException + * If the server can't be operated upon for some reason + */ + @SuppressWarnings("nls") + private static void ensureSuspended(Server server) throws ZoneException { + switch (server.getStatus()) { + case SUSPENDED: + break; + + case PENDING: + waitForStateChange(server, Server.Status.READY, Server.Status.RUNNING, Server.Status.PAUSED, + Server.Status.SUSPENDED, Server.Status.ERROR); + ensureSuspended(server); + break; + + case PAUSED: + server.unpause(); + waitForStateChange(server, Server.Status.RUNNING); + server.suspend(); + waitForStateChange(server, Server.Status.SUSPENDED); + break; + + case READY: + server.start(); + waitForStateChange(server, Server.Status.RUNNING); + server.suspend(); + waitForStateChange(server, Server.Status.SUSPENDED); + break; + + case RUNNING: + server.suspend(); + waitForStateChange(server, Server.Status.SUSPENDED); + break; + + case DELETED: + case ERROR: + default: + fail("Server state is not valid for test - " + server.getStatus().name()); + } + } + + /** + * This method makes sure that the indicated server is running before performing a test + * + * @param server + * The server to ensure is running + * @throws ZoneException + * If the server can't be operated upon + */ + @SuppressWarnings("nls") + private static void ensureRunning(Server server) throws ZoneException { + switch (server.getStatus()) { + case RUNNING: + break; + + case PENDING: + waitForStateChange(server, Server.Status.READY, Server.Status.RUNNING, Server.Status.PAUSED, + Server.Status.SUSPENDED, Server.Status.ERROR); + ensureRunning(server); + break; + + case PAUSED: + server.unpause(); + waitForStateChange(server, Server.Status.RUNNING); + break; + + case SUSPENDED: + server.resume(); + waitForStateChange(server, Server.Status.RUNNING); + break; + + case READY: + server.start(); + waitForStateChange(server, Server.Status.RUNNING); + break; + + case DELETED: + case ERROR: + default: + fail("Server state is not valid for test - " + server.getStatus().name()); + } + } + + /** + * This method will make sure that the server we are testing is paused + * + * @param server + * The server to make sure is paused for the test + * @throws ZoneException + * If anything fails + */ + @SuppressWarnings("nls") + private static void ensurePaused(Server server) throws ZoneException { + switch (server.getStatus()) { + case PAUSED: + break; + + case PENDING: + waitForStateChange(server, Server.Status.READY, Server.Status.RUNNING, Server.Status.PAUSED, + Server.Status.SUSPENDED, Server.Status.ERROR); + ensurePaused(server); + break; + + case READY: + server.start(); + waitForStateChange(server, Server.Status.RUNNING); + server.pause(); + waitForStateChange(server, Server.Status.PAUSED); + break; + + case RUNNING: + server.pause(); + waitForStateChange(server, Server.Status.PAUSED); + break; + + case SUSPENDED: + server.resume(); + waitForStateChange(server, Server.Status.RUNNING); + server.pause(); + waitForStateChange(server, Server.Status.PAUSED); + break; + + case ERROR: + case DELETED: + default: + fail("Server state is not valid for test - " + server.getStatus().name()); + } + } + + /** + * Enter a pool-wait loop checking the server state to see if it has entered one of the desired states or not. + * <p> + * This method checks the state of the server periodically for one of the desired states. When the server enters one + * of the desired states, the method returns a successful indication (true). If the server never enters one of the + * desired states within the alloted timeout period, then the method returns a failed response (false). No + * exceptions are thrown from this method. + * </p> + * + * @param server + * The server to wait on + * @param desiredStates + * A variable list of desired states, any one of which is allowed. + * @return True if the server entered one of the desired states, and false if not and the wait loop timed out. + */ + private static boolean waitForStateChange(Server server, Server.Status... desiredStates) { + int timeout = + ConfigurationFactory.getConfiguration().getIntegerProperty(Constants.PROPERTY_SERVER_STATE_CHANGE_TIMEOUT); + long limit = System.currentTimeMillis() + (timeout * 1000); + Server vm = server; + + try { + while (limit > System.currentTimeMillis()) { + vm.refresh(); + for (Server.Status desiredState : desiredStates) { + if (server.getStatus().equals(desiredState)) { + return true; + } + } + + try { + Thread.sleep(10000L); + } catch (InterruptedException e) { + // ignore + } + } + } catch (ZoneException e) { + e.printStackTrace(); + } + + return false; + } + + /* + * @Test public void testTerminateStack() throws IllegalStateException, IllegalArgumentException, ZoneException, + * UnknownProviderException, IOException { Properties properties = new Properties(); + * properties.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, IDENTITY_URL); + * properties.setProperty(ContextFactory.PROPERTY_REGION, REGION_NAME); + * properties.setProperty(ContextFactory.PROPERTY_TENANT, TENANT_NAME); + * properties.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS, "*"); + * properties.setProperty(ContextFactory.PROPERTY_DISABLE_PROXY, "true"); try (Context context = + * ContextFactory.getContext(PROVIDER_TYPE, properties)) { context.login(PRINCIPAL, CREDENTIAL); VMURL vm = + * VMURL.parseURL(SERVER_URL); ComputeService computeService = context.getComputeService(); Server server = + * computeService.getServer(vm.getServerId()); if (!server.getStatus().equals(Status.RUNNING)) { server.start(); + * assertTrue(waitForStateChange(server, Status.RUNNING)); } Map<String, String> params = new HashMap<>(); + * params.put(ProviderAdapter.PROPERTY_INSTANCE_URL, SERVER_URL); params.put(ProviderAdapter.PROPERTY_PROVIDER_NAME, + * PROVIDER_NAME); SvcLogicContext svcContext = new SvcLogicContext(); Stack stack = adapter.terminateStack(params, + * svcContext); assertNotNull(stack); } } + */ + +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestProviderAdapterImplNoConnection.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestProviderAdapterImplNoConnection.java new file mode 100644 index 000000000..d4683aa80 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestProviderAdapterImplNoConnection.java @@ -0,0 +1,170 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import java.lang.reflect.Field; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openecomp.appc.adapter.iaas.impl.ProviderAdapterImpl; +import org.openecomp.appc.adapter.iaas.impl.RequestContext; +import org.openecomp.appc.adapter.iaas.impl.RequestFailedException; +import org.openecomp.appc.adapter.iaas.impl.VMURL; +import org.openecomp.appc.configuration.ConfigurationFactory; +import org.openecomp.sdnc.sli.SvcLogicContext; +import org.slf4j.MDC; + +/** + * This class is used to test methods and functions of the adapter implementation that do not require and do not set up + * connections to any providers. + */ + +public class TestProviderAdapterImplNoConnection { + + private static Class<?> providerAdapterImplClass; + private static Class<?> configurationFactoryClass; + private static Field providerCacheField; + private static Field configField; + + private ProviderAdapterImpl adapter; + + /** + * Use reflection to locate fields and methods so that they can be manipulated during the test to change the + * internal state accordingly. + * + * @throws NoSuchFieldException + * if the field(s) dont exist + * @throws SecurityException + * if reflective access is not allowed + * @throws NoSuchMethodException + * If the method(s) dont exist + */ + @SuppressWarnings("nls") + @BeforeClass + public static void once() throws NoSuchFieldException, SecurityException, NoSuchMethodException { + providerAdapterImplClass = ProviderAdapterImpl.class; + configurationFactoryClass = ConfigurationFactory.class; + + providerCacheField = providerAdapterImplClass.getDeclaredField("providerCache"); + providerCacheField.setAccessible(true); + + configField = configurationFactoryClass.getDeclaredField("config"); + configField.setAccessible(true); + } + + /** + * initialize the test cases + */ + @Before + public void setup() { + adapter = new ProviderAdapterImpl(false); + } + + /** + * This test expects a failure because the value to be validated is a null URL + * + * @throws RequestFailedException + * Expected + */ + @SuppressWarnings("nls") + @Test(expected = RequestFailedException.class) + public void testValidateParameterPatternExpectFailNullValue() throws RequestFailedException { + MDC.put(ProviderAdapterImpl.MDC_SERVICE, "junit"); + SvcLogicContext svcContext = new SvcLogicContext(); + RequestContext rc = new RequestContext(svcContext); + String link = null; + + adapter.validateVMURL(VMURL.parseURL(link)); + } + + /** + * This test expects a failure because the value to be validated is an empty URL + * + * @throws RequestFailedException + * Expected + */ + @SuppressWarnings("nls") + @Test(expected = RequestFailedException.class) + public void testValidateParameterPatternExpectFailEmptyValue() throws RequestFailedException { + MDC.put(ProviderAdapterImpl.MDC_SERVICE, "junit"); + SvcLogicContext svcContext = new SvcLogicContext(); + RequestContext rc = new RequestContext(svcContext); + String link = ""; + + adapter.validateVMURL(VMURL.parseURL(link)); + } + + /** + * This test expects a failure because the value to be validated is a blank URL + * + * @throws RequestFailedException + * Expected + */ + @SuppressWarnings("nls") + @Test(expected = RequestFailedException.class) + public void testValidateParameterPatternExpectFailBlankValue() throws RequestFailedException { + MDC.put(ProviderAdapterImpl.MDC_SERVICE, "junit"); + SvcLogicContext svcContext = new SvcLogicContext(); + RequestContext rc = new RequestContext(svcContext); + String link = " "; + + adapter.validateVMURL(VMURL.parseURL(link)); + } + + /** + * This test expects a failure because the value to be validated is a bad URL + * + * @throws RequestFailedException + * Expected + */ + @SuppressWarnings("nls") + @Test(expected = RequestFailedException.class) + public void testValidateParameterPatternExpectFailBadURL() throws RequestFailedException { + MDC.put(ProviderAdapterImpl.MDC_SERVICE, "junit"); + SvcLogicContext svcContext = new SvcLogicContext(); + RequestContext rc = new RequestContext(svcContext); + String link = "http://some.host:1234/01d82c08594a4b23a0f9260c94be0c4d/"; + + adapter.validateVMURL(VMURL.parseURL(link)); + } + + /** + * This test expects to pass + * + * @throws RequestFailedException + * Un-Expected + */ + @SuppressWarnings("nls") + @Test + public void testValidateParameterPatternValidURL() throws RequestFailedException { + MDC.put(ProviderAdapterImpl.MDC_SERVICE, "junit"); + SvcLogicContext svcContext = new SvcLogicContext(); + RequestContext rc = new RequestContext(svcContext); + String link = + "http://some.host:1234/v2/01d82c08594a4b23a0f9260c94be0c4d/servers/f888f89f-096b-421e-ba36-34f714071551"; + + adapter.validateVMURL(VMURL.parseURL(link)); + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestRequestContext.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestRequestContext.java new file mode 100644 index 000000000..a7cc5dc3c --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestRequestContext.java @@ -0,0 +1,159 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.openecomp.appc.Constants; +import org.openecomp.appc.adapter.iaas.impl.RequestContext; +import org.openecomp.appc.configuration.Configuration; +import org.openecomp.appc.configuration.ConfigurationFactory; + +/** + * Test the RequestContext object + * <p> + * The request context is used to track retries, recovery attempts, and time to live of the processing of a request. + * </p> + */ + +public class TestRequestContext { + + private RequestContext rc; + private Configuration config = ConfigurationFactory.getConfiguration(); + + /** + * Set up the test environment by forcing the retry delay and limit to small values for the test and setting up the + * request context object. + */ + @Before + public void setup() { + config.setProperty(Constants.PROPERTY_RETRY_DELAY, "1"); + config.setProperty(Constants.PROPERTY_RETRY_LIMIT, "3"); + rc = new RequestContext(null); + rc.setTimeToLiveSeconds(2); + } + + /** + * Ensure that we set up the property correctly + */ + @Test + public void testRetryDelayProperty() { + assertEquals(1, rc.getRetryDelay()); + } + + /** + * Ensure that we set up the property correctly + */ + @Test + public void testRetryLimitProperty() { + assertEquals(3, rc.getRetryLimit()); + } + + /** + * This test ensures that the retry attempt counter is zero on a new context + */ + @Test + public void testRetryCountNoRetries() { + assertEquals(0, rc.getAttempts()); + } + + /** + * Test that the delay is accurate + */ + @Test + public void testDelay() { + long future = System.currentTimeMillis() + (rc.getRetryDelay() * 1000L); + + rc.delay(); + + assertTrue(System.currentTimeMillis() >= future); + } + + /** + * The RequestContext tracks the number of retry attempts against the limit. This test verifies that tracking logic + * works correctly. + */ + @Test + public void testCanRetry() { + assertEquals(0, rc.getAttempts()); + assertTrue(rc.attempt()); + assertEquals(1, rc.getAttempts()); + assertTrue(rc.attempt()); + assertEquals(2, rc.getAttempts()); + assertTrue(rc.attempt()); + assertEquals(3, rc.getAttempts()); + assertFalse(rc.attempt()); + assertEquals(3, rc.getAttempts()); + assertFalse(rc.attempt()); + assertEquals(3, rc.getAttempts()); + assertFalse(rc.attempt()); + assertEquals(3, rc.getAttempts()); + } + + /** + * The same RequestContext is used throughout the processing, and retries need to be reset once successfully + * connected so that any earlier (successful) recoveries are not considered when performing any new future + * recoveries. This test ensures that a reset clears the retry counter and that we can attempt retries again up to + * the limit. + */ + @Test + public void testResetAndCanRetry() { + assertTrue(rc.attempt()); + assertTrue(rc.attempt()); + assertTrue(rc.attempt()); + rc.reset(); + + assertTrue(rc.attempt()); + assertTrue(rc.attempt()); + assertTrue(rc.attempt()); + assertFalse(rc.attempt()); + assertFalse(rc.attempt()); + assertFalse(rc.attempt()); + } + + /** + * This test is used to test tracking of time to live for the request context. Because time is inexact, the + * assertions can only be ranges of values, such as at least some value or greater. The total duration tracking in + * the request context is only updated on each call to {@link RequestContext#isAlive()}. Also, durations are NOT + * affected by calls to reset. + */ + @Test + public void testTimeToLive() { + assertTrue(rc.getTotalDuration() == 0L); + assertTrue(rc.isAlive()); + rc.reset(); + rc.delay(); + assertTrue(rc.isAlive()); + assertTrue(rc.getTotalDuration() >= 1000L); + rc.reset(); + rc.delay(); + rc.isAlive(); + assertTrue(rc.getTotalDuration() >= 2000L); + rc.reset(); + rc.delay(); + assertFalse(rc.isAlive()); + assertTrue(rc.getTotalDuration() >= 3000L); + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestServiceCatalog.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestServiceCatalog.java new file mode 100644 index 000000000..ac8cde31a --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestServiceCatalog.java @@ -0,0 +1,147 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Properties; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.openecomp.appc.adapter.iaas.impl.ServiceCatalog; +import org.openecomp.appc.configuration.ConfigurationFactory; +import com.att.cdp.exceptions.ZoneException; + +import com.woorea.openstack.keystone.model.Access.Service; + +/** + * This class tests the service catalog against a known provider. + */ +@Ignore +public class TestServiceCatalog { + + // Number + private static int EXPECTED_REGIONS = 1; + private static int EXPECTED_ENDPOINTS = 1; + + private static String PRINCIPAL; + private static String CREDENTIAL; + private static String TENANT_NAME; + private static String TENANT_ID; + private static String IDENTITY_URL; + private static String REGION_NAME; + + private ServiceCatalog catalog; + + private Properties properties; + + @BeforeClass + public static void before() { + Properties props = ConfigurationFactory.getConfiguration().getProperties(); + IDENTITY_URL = props.getProperty("provider1.identity"); + PRINCIPAL = props.getProperty("provider1.tenant1.userid", "appc"); + CREDENTIAL = props.getProperty("provider1.tenant1.password", "appc"); + TENANT_NAME = props.getProperty("provider1.tenant1.name", "appc"); + TENANT_ID = + props.getProperty("provider1.tenant1.id", + props.getProperty("test.tenantid", "abcde12345fghijk6789lmnopq123rst")); + REGION_NAME = props.getProperty("provider1.tenant1.region", "RegionOne"); + + EXPECTED_REGIONS = Integer.valueOf(props.getProperty("test.expected-regions", "0")); + EXPECTED_ENDPOINTS = Integer.valueOf(props.getProperty("test.expected-endpoints", "0")); + } + + /** + * Setup the test environment by loading a new service catalog for each test + * + * @throws ZoneException + */ + @Before + public void setup() throws ZoneException { + properties = new Properties(); + catalog = new ServiceCatalog(IDENTITY_URL, TENANT_NAME, PRINCIPAL, CREDENTIAL, properties); + } + + /** + * Test that the tenant name and ID are returned correctly + */ + @Test + public void testKnownTenant() { + assertEquals(TENANT_NAME, catalog.getTenantName()); + assertEquals(TENANT_ID, catalog.getTenantId()); + } + + /** + * Test that we find all of the expected region(s) + */ + @Test + public void testKnownRegions() { + assertEquals(EXPECTED_REGIONS, catalog.getRegions().size()); + // assertEquals(REGION_NAME, catalog.getRegions().toArray()[0]); + } + + /** + * Test that we can check for published services correctly + */ + @Test + public void testServiceTypesPublished() { + assertTrue(catalog.isServicePublished("compute")); + assertFalse(catalog.isServicePublished("bogus")); + } + + /** + * Check that we can get the list of published services + */ + @Test + public void testPublishedServicesList() { + List<String> services = catalog.getServiceTypes(); + + assertTrue(services.contains(ServiceCatalog.COMPUTE_SERVICE)); + assertTrue(services.contains(ServiceCatalog.IDENTITY_SERVICE)); + assertTrue(services.contains(ServiceCatalog.IMAGE_SERVICE)); + assertTrue(services.contains(ServiceCatalog.NETWORK_SERVICE)); + assertTrue(services.contains(ServiceCatalog.VOLUME_SERVICE)); + } + + /** + * Test that we can get the endpoint(s) for a service + */ + @Test + public void testEndpointList() { + List<Service.Endpoint> endpoints = catalog.getEndpoints(ServiceCatalog.COMPUTE_SERVICE); + + assertNotNull(endpoints); + assertFalse(endpoints.isEmpty()); + assertEquals(EXPECTED_ENDPOINTS, endpoints.size()); + + Service.Endpoint endpoint = endpoints.get(0); + // assertEquals(REGION_NAME, endpoint.getRegion()); + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestVMURL.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestVMURL.java new file mode 100644 index 000000000..852bb4137 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/adapter/iaas/impl/TestVMURL.java @@ -0,0 +1,107 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.adapter.iaas.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.Properties; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.openecomp.appc.adapter.iaas.impl.VMURL; +import org.openecomp.appc.configuration.ConfigurationFactory; + +public class TestVMURL { + + private static String IP; + private static String PORT; + private static String TENANTID; + private static String VMID; + private static String URL; + + @BeforeClass + public static void before() { + Properties props = ConfigurationFactory.getConfiguration().getProperties(); + IP = props.getProperty("test.ip"); + PORT = props.getProperty("test.port"); + TENANTID = props.getProperty("test.tenantid"); + VMID = props.getProperty("test.vmid"); + URL = String.format("http://%s:%s/v2/%s/servers/%s", IP, PORT, TENANTID, VMID); + } + + /** + * Test that we can parse and interpret valid URLs + */ + @Test + public void testValidURLs() { + VMURL url = VMURL.parseURL(URL); + + assertEquals("http", url.getScheme()); + assertEquals(IP, url.getHost()); + assertEquals(PORT, url.getPort()); + assertEquals(TENANTID, url.getTenantId()); + assertEquals(VMID, url.getServerId()); + + url = VMURL.parseURL(String.format("http://%s/v2/%s/servers/%s", IP, TENANTID, VMID)); + assertEquals("http", url.getScheme()); + assertEquals(IP, url.getHost()); + assertNull(url.getPort()); + assertEquals(TENANTID, url.getTenantId()); + assertEquals(VMID, url.getServerId()); + } + + /** + * Test that we ignore and return null for invalid URLs + */ + @Test + public void testInvalidURLs() { + VMURL url = VMURL.parseURL(null); + assertNull(url); + + url = VMURL.parseURL(String.format("%s:%s/v2/%s/servers/%s", IP, PORT, TENANTID, VMID)); + assertNull(url); + + url = VMURL.parseURL(String.format("http:/%s:%s/v2/%s/servers/%s", IP, PORT, TENANTID, VMID)); + assertNull(url); + + url = VMURL.parseURL(String.format("http:///%s:%s/v2/%s/servers/%s", IP, PORT, TENANTID, VMID)); + assertNull(url); + + url = VMURL.parseURL(String.format("http://v2/%s/servers/%s", TENANTID, VMID)); + assertNull(url); + + url = VMURL.parseURL(String.format("%s:%s/%s/servers/%s", IP, PORT, TENANTID, VMID)); + assertNull(url); + + url = VMURL.parseURL(String.format("%s:%s/v2/servers/%s", IP, PORT, VMID)); + assertNull(url); + + url = VMURL.parseURL(String.format("%s:%s/v2/%s/%s", IP, PORT, TENANTID, VMID)); + assertNull(url); + + url = VMURL.parseURL(String.format("%s:%s/v2/%s/servers", IP, PORT, TENANTID)); + assertNull(url); + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/test/ExecutorHarness.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/test/ExecutorHarness.java new file mode 100644 index 000000000..d552edccf --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/test/ExecutorHarness.java @@ -0,0 +1,181 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.test; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.appc.test.InterceptLogger; + +import org.openecomp.sdnc.sli.SvcLogicContext; +import org.openecomp.sdnc.sli.SvcLogicJavaPlugin; + +/** + * This class is used as a test harness to wrap the call to an executor node. + */ + +public class ExecutorHarness { + + /** + * The executor to be tested + */ + private SvcLogicJavaPlugin executor; + + /** + * The collection of all exec methods found on the class + */ + private Map<String, Method> methods; + + /** + * The field of the class being tested that contains the reference to the logger to be used. This is modified to + * point to our interception logger for the test. + */ + private Field contextLogger; + + /** + * The interception logger that buffers all messages logged and allows us to look at them as part of the test case. + */ + private InterceptLogger logger; + + /** + * Create the harness and initialize it + * + * @throws SecurityException + * If a security manager, s, is present and any of the following conditions is met: + * <ul> + * <li>invocation of s.checkMemberAccess(this, Member.DECLARED) denies access to the declared field</li> + * <li>the caller's class loader is not the same as or an ancestor of the class loader for the current + * class and invocation of s.checkPackageAccess() denies access to the package of this class</li> + * </ul> + * @throws NoSuchFieldException + * if a field with the specified name is not found. + * @throws IllegalAccessException + * if this Field object is enforcing Java language access control and the underlying field is either + * inaccessible or final. + * @throws IllegalArgumentException + * if the specified object is not an instance of the class or interface declaring the underlying field + * (or a subclass or implementor thereof), or if an unwrapping conversion fails. + */ + @SuppressWarnings("nls") + public ExecutorHarness() throws NoSuchFieldException, SecurityException, IllegalArgumentException, + IllegalAccessException { + methods = new HashMap<>(); + new SvcLogicContext(); + + Class<?> contextClass = SvcLogicContext.class; + contextLogger = contextClass.getDeclaredField("LOG"); + contextLogger.setAccessible(true); + logger = new InterceptLogger(); + contextLogger.set(null, logger); + } + + /** + * Convenience constructor + * + * @param executor + * The executor to be tested by the harness + * @throws SecurityException + * If a security manager, s, is present and any of the following conditions is met: + * <ul> + * <li>invocation of s.checkMemberAccess(this, Member.DECLARED) denies access to the declared field</li> + * <li>the caller's class loader is not the same as or an ancestor of the class loader for the current + * class and invocation of s.checkPackageAccess() denies access to the package of this class</li> + * </ul> + * @throws NoSuchFieldException + * if a field with the specified name is not found. + * @throws IllegalAccessException + * if this Field object is enforcing Java language access control and the underlying field is either + * inaccessible or final. + * @throws IllegalArgumentException + * if the specified object is not an instance of the class or interface declaring the underlying field + * (or a subclass or implementor thereof), or if an unwrapping conversion fails. + */ + public ExecutorHarness(SvcLogicJavaPlugin executor) throws NoSuchFieldException, SecurityException, + IllegalArgumentException, IllegalAccessException { + this(); + setExecutor(executor); + } + + /** + * @param executor + * The java plugin class to be executed + */ + public void setExecutor(SvcLogicJavaPlugin executor) { + this.executor = executor; + scanExecutor(); + } + + /** + * @return The java plugin class to be executed + */ + public SvcLogicJavaPlugin getExecutor() { + return executor; + } + + /** + * @return The set of all methods that meet the signature requirements + */ + public List<String> getExecMethodNames() { + List<String> names = new ArrayList<>(); + names.addAll(methods.keySet()); + return names; + } + + /** + * Returns an indication if the named method is a valid executor method that could be called from a DG execute node + * + * @param methodName + * The method name to be validated + * @return True if the method name meets the signature requirements, false if the method either does not exist or + * does not meet the requirements. + */ + public boolean isExecMethod(String methodName) { + return methods.containsKey(methodName); + } + + /** + * This method scans the executor class hierarchy to locate all methods that match the required signature of the + * executor and records these methods in a map. + */ + private void scanExecutor() { + methods.clear(); + Class<?> executorClass = executor.getClass(); + Method[] publicMethods = executorClass.getMethods(); + for (Method method : publicMethods) { + if (method.getReturnType().equals(Void.class)) { + Class<?>[] paramTypes = method.getParameterTypes(); + if (paramTypes.length == 2) { + if (Map.class.isAssignableFrom(paramTypes[0]) + && SvcLogicContext.class.isAssignableFrom(paramTypes[1])) { + methods.put(method.getName(), method); + } + } + } + } + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/test/InterceptLogger.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/test/InterceptLogger.java new file mode 100644 index 000000000..394352136 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/java/org/openecomp/appc/test/InterceptLogger.java @@ -0,0 +1,451 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * 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.openecomp.appc.test; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Marker; + +import ch.qos.logback.classic.Level; + +/** + * This class is used as an intercept logger that can be used in testing to intercept and record all messages that are + * logged, thus allowing a junit test case to examine the log output and make assertions. + */ +public class InterceptLogger implements org.slf4j.Logger { + + /** + * This inner class represents an intercepted log event. + */ + public class LogRecord { + private Level level; + private String message; + private long timestamp; + private Throwable t; + + public LogRecord(Level level, String message) { + setLevel(level); + setTimestamp(System.currentTimeMillis()); + setMessage(message); + } + + public LogRecord(Level level, String message, Throwable t) { + this(level, message); + setThrowable(t); + } + + /** + * @return the value of level + */ + public Level getLevel() { + return level; + } + + /** + * @return the value of message + */ + public String getMessage() { + return message; + } + + /** + * @return the value of timestamp + */ + public long getTimestamp() { + return timestamp; + } + + /** + * @param level + * the value for level + */ + public void setLevel(Level level) { + this.level = level; + } + + /** + * @param message + * the value for message + */ + public void setMessage(String message) { + this.message = message; + } + + /** + * @param timestamp + * the value for timestamp + */ + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + /** + * @return the value of t + */ + public Throwable getThrowable() { + return t; + } + + /** + * @param t + * the value for t + */ + public void setThrowable(Throwable t) { + this.t = t; + } + + } + + /** + * The list of all intercepted log events + */ + private List<LogRecord> events; + + /** + * Create the intercept logger + */ + public InterceptLogger() { + events = new ArrayList<LogRecord>(1000); + } + + /** + * @return Returns all intercepted log events + */ + public List<LogRecord> getLogRecords() { + return events; + } + + /** + * Clears all log events + */ + public void clear() { + events.clear(); + } + + @Override + public void debug(Marker marker, String msg) { + debug(msg); + } + + @Override + public void debug(Marker marker, String format, Object arg) { + debug(MessageFormat.format(format, arg)); + } + + @Override + public void debug(Marker marker, String format, Object... arguments) { + debug(MessageFormat.format(format, arguments)); + } + + @Override + public void debug(Marker marker, String format, Object arg1, Object arg2) { + debug(MessageFormat.format(format, arg1, arg2)); + } + + @Override + public void debug(Marker marker, String msg, Throwable t) { + debug(msg, t); + } + + @Override + public void debug(String msg) { + events.add(new LogRecord(Level.DEBUG, msg)); + } + + @Override + public void debug(String format, Object arg) { + events.add(new LogRecord(Level.DEBUG, MessageFormat.format(format, arg))); + } + + @Override + public void debug(String format, Object... arguments) { + events.add(new LogRecord(Level.DEBUG, MessageFormat.format(format, arguments))); + } + + @Override + public void debug(String format, Object arg1, Object arg2) { + events.add(new LogRecord(Level.DEBUG, MessageFormat.format(format, arg1, arg2))); + } + + @Override + public void debug(String msg, Throwable t) { + events.add(new LogRecord(Level.DEBUG, msg, t)); + } + + @Override + public void error(Marker marker, String msg) { + error(msg); + } + + @Override + public void error(Marker marker, String format, Object arg) { + error(format, arg); + } + + @Override + public void error(Marker marker, String format, Object... arguments) { + error(format, arguments); + } + + @Override + public void error(Marker marker, String format, Object arg1, Object arg2) { + error(format, arg1, arg2); + } + + @Override + public void error(Marker marker, String msg, Throwable t) { + events.add(new LogRecord(Level.ERROR, msg, t)); + } + + @Override + public void error(String msg) { + events.add(new LogRecord(Level.ERROR, msg)); + } + + @Override + public void error(String format, Object arg) { + events.add(new LogRecord(Level.ERROR, MessageFormat.format(format, arg))); + } + + @Override + public void error(String format, Object... arguments) { + events.add(new LogRecord(Level.ERROR, MessageFormat.format(format, arguments))); + } + + @Override + public void error(String format, Object arg1, Object arg2) { + events.add(new LogRecord(Level.ERROR, MessageFormat.format(format, arg1, arg2))); + } + + @Override + public void error(String msg, Throwable t) { + events.add(new LogRecord(Level.ERROR, msg, t)); + } + + @Override + public String getName() { + return null; + } + + @Override + public void info(Marker marker, String msg) { + info(msg); + } + + @Override + public void info(Marker marker, String format, Object arg) { + info(format, arg); + } + + @Override + public void info(Marker marker, String format, Object... arguments) { + info(format, arguments); + } + + @Override + public void info(Marker marker, String format, Object arg1, Object arg2) { + info(format, arg1, arg2); + } + + @Override + public void info(Marker marker, String msg, Throwable t) { + events.add(new LogRecord(Level.INFO, msg, t)); + } + + @Override + public void info(String msg) { + events.add(new LogRecord(Level.INFO, msg)); + } + + @Override + public void info(String format, Object arg) { + events.add(new LogRecord(Level.INFO, MessageFormat.format(format, arg))); + } + + @Override + public void info(String format, Object... arguments) { + events.add(new LogRecord(Level.INFO, MessageFormat.format(format, arguments))); + } + + @Override + public void info(String format, Object arg1, Object arg2) { + events.add(new LogRecord(Level.INFO, MessageFormat.format(format, arg1, arg2))); + } + + @Override + public void info(String msg, Throwable t) { + events.add(new LogRecord(Level.INFO, msg, t)); + } + + @Override + public boolean isDebugEnabled() { + return true; + } + + @Override + public boolean isDebugEnabled(Marker marker) { + return true; + } + + @Override + public boolean isErrorEnabled() { + return true; + } + + @Override + public boolean isErrorEnabled(Marker marker) { + return true; + } + + @Override + public boolean isInfoEnabled() { + return true; + } + + @Override + public boolean isInfoEnabled(Marker marker) { + return true; + } + + @Override + public boolean isTraceEnabled() { + return true; + } + + @Override + public boolean isTraceEnabled(Marker marker) { + return true; + } + + @Override + public boolean isWarnEnabled() { + return true; + } + + @Override + public boolean isWarnEnabled(Marker marker) { + return true; + } + + @Override + public void trace(Marker marker, String msg) { + trace(msg); + } + + @Override + public void trace(Marker marker, String format, Object arg) { + trace(format, arg); + } + + @Override + public void trace(Marker marker, String format, Object... argArray) { + trace(format, argArray); + } + + @Override + public void trace(Marker marker, String format, Object arg1, Object arg2) { + trace(format, arg1, arg2); + } + + @Override + public void trace(Marker marker, String msg, Throwable t) { + trace(msg, t); + } + + @Override + public void trace(String msg) { + events.add(new LogRecord(Level.TRACE, msg)); + } + + @Override + public void trace(String format, Object arg) { + events.add(new LogRecord(Level.TRACE, MessageFormat.format(format, arg))); + } + + @Override + public void trace(String format, Object... arguments) { + events.add(new LogRecord(Level.TRACE, MessageFormat.format(format, arguments))); + } + + @Override + public void trace(String format, Object arg1, Object arg2) { + events.add(new LogRecord(Level.TRACE, MessageFormat.format(format, arg1, arg2))); + } + + @Override + public void trace(String msg, Throwable t) { + events.add(new LogRecord(Level.TRACE, msg, t)); + } + + @Override + public void warn(Marker marker, String msg) { + warn(msg); + } + + @Override + public void warn(Marker marker, String format, Object arg) { + warn(format, arg); + } + + @Override + public void warn(Marker marker, String format, Object... arguments) { + warn(format, arguments); + } + + @Override + public void warn(Marker marker, String format, Object arg1, Object arg2) { + warn(format, arg1, arg2); + } + + @Override + public void warn(Marker marker, String msg, Throwable t) { + events.add(new LogRecord(Level.WARN, msg, t)); + } + + @Override + public void warn(String msg) { + events.add(new LogRecord(Level.WARN, msg)); + } + + @Override + public void warn(String format, Object arg) { + events.add(new LogRecord(Level.WARN, MessageFormat.format(format, arg))); + } + + @Override + public void warn(String format, Object... arguments) { + events.add(new LogRecord(Level.WARN, MessageFormat.format(format, arguments))); + } + + @Override + public void warn(String format, Object arg1, Object arg2) { + events.add(new LogRecord(Level.WARN, MessageFormat.format(format, arg1, arg2))); + } + + @Override + public void warn(String msg, Throwable t) { + events.add(new LogRecord(Level.WARN, msg, t)); + } +} diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/resources/org/openecomp/appc/default.properties b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/resources/org/openecomp/appc/default.properties new file mode 100644 index 000000000..2daa085ad --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/test/resources/org/openecomp/appc/default.properties @@ -0,0 +1,109 @@ +### +# ============LICENSE_START======================================================= +# openECOMP : APP-C +# ================================================================================ +# 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========================================================= +### + +# +# Default properties for the APP-C Provider Adapter +# +# ------------------------------------------------------------------------------------------------- +# +# Define the name and path of any user-provided configuration (bootstrap) file that can be loaded +# to supply configuration options +org.openecomp.appc.bootstrap.file=appc.properties +org.openecomp.appc.bootstrap.path=/opt/openecomp/appc/data/properties,${user.home},. + +appc.application.name=APPC + +# +# Define the message resource bundle name to be loaded +org.openecomp.appc.resources=org/openecomp/appc/i18n/MessageResources +# +# The name of the adapter. +org.openecomp.appc.provider.adaptor.name=org.openecomp.appc.appc_provider_adapter +# +# Set up the logging environment +# +org.openecomp.appc.logging.file=org/openecomp/appc/logback.xml +org.openecomp.appc.logging.path=${user.home};etc;../etc +org.openecomp.appc.logger=org.openecomp.appc +org.openecomp.appc.security.logger=org.openecomp.appc.security +# +# The minimum and maximum provider/tenant context pool sizes. Min=1 means that as soon +# as the provider/tenant is referenced a Context is opened and added to the pool. Max=0 +# means that the upper bound on the pool is unbounded. +org.openecomp.appc.provider.min.pool=1 +org.openecomp.appc.provider.max.pool=0 + +# +# The following properties are used to configure the retry logic for connection to the +# IaaS provider(s). The retry delay property is the amount of time, in seconds, the +# application waits between retry attempts. The retry limit is the number of retries +# that are allowed before the request is failed. +org.openecomp.appc.provider.retry.delay = 30 +org.openecomp.appc.provider.retry.limit = 10 + +# +# The trusted hosts list for SSL access when a certificate is not provided. +# +provider.trusted.hosts=* +# +# The amount of time, in seconds, to wait for a server state change (start->stop, stop->start, etc). +# If the server does not change state to a valid state within the alloted time, the operation +# fails. +org.openecomp.appc.server.state.change.timeout=300 +# +# The amount of time to wait, in seconds, between subsequent polls to the OpenStack provider +# to refresh the status of a resource we are waiting on. +# +org.openecomp.appc.openstack.poll.interval=20 +# +# The connection information to connect to the provider we are using. These properties +# are "structured" properties, in that the name is a compound name, where the nodes +# of the name can be ordered (1, 2, 3, ...). All of the properties with the same ordinal +# position are defining the same entity. For example, provider1.type and provider1.name +# are defining the same provider, whereas provider2.name and provider2.type are defining +# the values for a different provider. Any number of providers can be defined in this +# way. +# + + +# Don't change these 2 right now since they are hard coded in the DG +provider1.type=appc +provider1.name=appc + +#These you can change +provider1.identity=appc +provider1.tenant1.name=appc +provider1.tenant1.userid=appc +provider1.tenant1.password=appc + +# After a change to the provider make sure to recheck these values with an api call to provider1.identity/tokens +test.expected-regions=1 +test.expected-endpoints=1 + +#Your OpenStack IP +test.ip=192.168.1.2 +# Your OpenStack Platform's Keystone Port (default is 5000) +test.port=5000 +test.tenantid=abcde12345fghijk6789lmnopq123rst +test.vmid=abc12345-1234-5678-890a-abcdefg12345 +# Port 8774 below is default port for OpenStack's Nova API Service +test.url=http://192.168.1.2:8774/v2/abcde12345fghijk6789lmnopq123rst/servers/abc12345-1234-5678-890a-abcdefg12345 + diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-features/.gitignore b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-features/.gitignore new file mode 100644 index 000000000..615a76bbc --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-features/.gitignore @@ -0,0 +1,4 @@ +/target/ +/bin/ +/classes/ +/.settings/ diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-features/pom.xml b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-features/pom.xml new file mode 100644 index 000000000..48588a6fb --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-features/pom.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>appc-iaas-adapter</artifactId> + <groupId>org.openecomp.appc</groupId> + <version>1.0.0</version> + </parent> + <artifactId>appc-iaas-adapter-features</artifactId> + <name>IaaS Adaptor - Features</name> + + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-iaas-adapter-bundle</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>features-mdsal</artifactId> + <classifier>features</classifier> + <type>xml</type> + <scope>runtime</scope> + </dependency> + + <!-- dependency for opendaylight-karaf-empty for use by testing --> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>opendaylight-karaf-empty</artifactId> + <type>zip</type> + </dependency> + +<!-- <dependency> --> +<!-- Required for launching the feature tests --> +<!-- <groupId>org.opendaylight.yangtools</groupId> --> +<!-- <artifactId>features-test</artifactId> --> +<!-- <scope>test</scope> --> +<!-- </dependency> --> + + <dependency> + <groupId>org.opendaylight.yangtools</groupId> + <artifactId>features-yangtools</artifactId> + <classifier>features</classifier> + <type>xml</type> + <scope>runtime</scope> + </dependency> + </dependencies> + + <build> + <resources> + <resource> + <filtering>true</filtering> + <directory>src/main/resources</directory> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <executions> + <execution> + <id>filter</id> + <goals> + <goal>resources</goal> + </goals> + <phase>generate-resources</phase> + </execution> + </executions> + </plugin> + <!-- launches the feature test, which validates that your karaf feature + can be installed inside of a karaf container. It doesn't validate that your + functionality works correctly, just that you have all of the dependent bundles + defined correctly. --> + <!-- <plugin> --> + <!-- <groupId>org.apache.maven.plugins</groupId> --> + <!-- <artifactId>maven-surefire-plugin</artifactId> --> + <!-- <version>2.16</version> --> + <!-- <configuration> --> + <!-- <systemPropertyVariables> --> + <!-- <karaf.distro.groupId>org.opendaylight.controller</karaf.distro.groupId> --> + <!-- <karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId> --> + <!-- <karaf.distro.version>${odl.karaf.empty.distro.version}</karaf.distro.version> --> + <!-- </systemPropertyVariables> --> + <!-- <dependenciesToScan> --> + <!-- <dependency>org.opendaylight.yangtools:features-test</dependency> --> + <!-- </dependenciesToScan> --> + <!-- </configuration> --> + <!-- </plugin> --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <id>attach-artifacts</id> + <goals> + <goal>attach-artifact</goal> + </goals> + <phase>package</phase> + <configuration> + <artifacts> + <artifact> + <file>${project.build.directory}/classes/${features.file}</file> + <type>xml</type> + <classifier>features</classifier> + </artifact> + </artifacts> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-features/src/main/resources/features.xml b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-features/src/main/resources/features.xml new file mode 100644 index 000000000..f68027e90 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-features/src/main/resources/features.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + openECOMP : APP-C + ================================================================================ + 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========================================================= + --> + + +<features name="appc-iaas-adapter-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0"> + +<!-- <repository>mvn:org.opendaylight.mdsal/features-mdsal/${odl.mdsal.version}/xml/features</repository> --> + <repository>mvn:org.opendaylight.mdsal/features-mdsal/${features-mdsal.version}/xml/features</repository> + + + <feature name='appc-iaas-adapter' description="appc-iaas-adapter" version='${project.version}'> + <!-- Most applications will have a dependency on the ODL MD-SAL Broker --> +<!-- <feature version="${broker-mdsal.version}">odl-mdsal-broker</feature> --> + <feature version="${broker-mdsal.version}">odl-mdsal-broker</feature> + <feature>sdnc-sli</feature> + <bundle>mvn:org.openecomp.appc/appc-iaas-adapter-bundle/${project.version}</bundle> + </feature> + +</features> diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/.gitignore b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/.gitignore new file mode 100644 index 000000000..731eb433c --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/.gitignore @@ -0,0 +1,2 @@ +/target/ +/.settings/ diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/pom.xml b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/pom.xml new file mode 100644 index 000000000..376196e42 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/pom.xml @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>appc-iaas-adapter</artifactId> + <groupId>org.openecomp.appc</groupId> + <version>1.0.0</version> + </parent> + <artifactId>appc-iaas-adapter-installer</artifactId> + <name>IaaS Adapter - Karaf Installer</name> + <packaging>pom</packaging> + + <properties> + <application.name>appc-iaas-adapter</application.name> + <features.boot>appc-iaas-adapter</features.boot> + <features.repositories>mvn:org.openecomp.appc/appc-iaas-adapter-features/${project.version}/xml/features</features.repositories> + <include.transitive.dependencies>false</include.transitive.dependencies> + </properties> + + <dependencies> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-iaas-adapter-features</artifactId> + <classifier>features</classifier> + <type>xml</type> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-iaas-adapter-bundle</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <id>mvn-repo-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <appendAssemblyId>false</appendAssemblyId> + <attach>false</attach> + <finalName>stage/${application.name}-${project.version}</finalName> + <descriptors> + <descriptor>src/assembly/assemble_mvnrepo_zip.xml</descriptor> + </descriptors> + </configuration> + </execution> + <execution> + <id>installer-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <appendAssemblyId>false</appendAssemblyId> + <attach>true</attach> + <finalName>${application.name}-${project.version}</finalName> + <descriptors> + <descriptor>src/assembly/assemble_installer_zip.xml</descriptor> + </descriptors> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-dependencies</id> + <goals> + <goal>copy-dependencies</goal> + </goals> + <phase>prepare-package</phase> + <configuration> + <transitive>false</transitive> + <outputDirectory>${project.build.directory}/assembly/system</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + <useRepositoryLayout>true</useRepositoryLayout> + <addParentPoms>false</addParentPoms> + <copyPom>false</copyPom> + <excludeGroupIds>org.opendaylight</excludeGroupIds> + <scope>provided</scope> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <executions> + <execution> + <id>copy-version</id> + <goals> + <goal>copy-resources</goal> + </goals> + <!-- here the phase you need --> + <phase>validate</phase> + <configuration> + <outputDirectory>${basedir}/target/stage</outputDirectory> + <resources> + <resource> + <directory>src/main/resources/scripts</directory> + <includes> + <include>install-feature.sh</include> + </includes> + <filtering>true</filtering> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> + + </plugins> + </build> + +</project> diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/src/assembly/assemble_installer_zip.xml b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/src/assembly/assemble_installer_zip.xml new file mode 100644 index 000000000..9fbaad8c5 --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/src/assembly/assemble_installer_zip.xml @@ -0,0 +1,59 @@ +<!-- + ============LICENSE_START======================================================= + openECOMP : APP-C + ================================================================================ + 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========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>adapter</id> + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>755</fileMode> + <includes> + <include>*.sh</include> + </includes> + </fileSet> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>644</fileMode> + <excludes> + <exclude>*.sh</exclude> + </excludes> + </fileSet> + </fileSets> + + + +</assembly> diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/src/assembly/assemble_mvnrepo_zip.xml b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/src/assembly/assemble_mvnrepo_zip.xml new file mode 100644 index 000000000..1ac5a82bc --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/src/assembly/assemble_mvnrepo_zip.xml @@ -0,0 +1,47 @@ +<!-- + ============LICENSE_START======================================================= + openECOMP : APP-C + ================================================================================ + 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========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>adapter</id> + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/assembly/</directory> + <outputDirectory>.</outputDirectory> + <excludes> + </excludes> + </fileSet> + </fileSets> + +</assembly> diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/src/main/resources/scripts/install-feature.sh b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/src/main/resources/scripts/install-feature.sh new file mode 100644 index 000000000..1d769fada --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-installer/src/main/resources/scripts/install-feature.sh @@ -0,0 +1,40 @@ +### +# ============LICENSE_START======================================================= +# openECOMP : APP-C +# ================================================================================ +# 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========================================================= +### + +#!/bin/bash + +ODL_HOME=${ODL_HOME:-/opt/opendaylight/current} +ODL_KARAF_CLIENT=${ODL_KARAF_CLIENT:-${ODL_HOME}/bin/client} +ODL_KARAF_CLIENT_OPTS=${ODL_KARAF_CLIENT_OPTS:-"-u karaf"} +INSTALLERDIR=$(dirname $0) + +REPOZIP=${INSTALLERDIR}/${features.boot}-${project.version}.zip + +if [ -f ${REPOZIP} ] +then + unzip -n -d ${ODL_HOME} ${REPOZIP} +else + echo "ERROR : repo zip ($REPOZIP) not found" + exit 1 +fi + +${ODL_KARAF_CLIENT} ${ODL_KARAF_CLIENT_OPTS} feature:repo-add ${features.repositories} +${ODL_KARAF_CLIENT} ${ODL_KARAF_CLIENT_OPTS} feature:install ${features.boot} diff --git a/appc-adapters/appc-iaas-adapter/pom.xml b/appc-adapters/appc-iaas-adapter/pom.xml new file mode 100644 index 000000000..27ae766fc --- /dev/null +++ b/appc-adapters/appc-iaas-adapter/pom.xml @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-adapters</artifactId> + <version>1.0.0</version> + </parent> + + <artifactId>appc-iaas-adapter</artifactId> + <name>IaaS Adaptor</name> + <description>Abstraction to connect to and utilize the services of cloud providers such as OpenStack or VMWare.</description> + <packaging>pom</packaging> + + <reporting> + <plugins> + <plugin> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <additionalDependencies> + <additionalDependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + </additionalDependency> + <additionalDependency> + <groupId>org.antlr</groupId> + <artifactId>antlr4</artifactId> + <version>${antlr.version}</version> + </additionalDependency> + <additionalDependency> + <groupId>org.antlr</groupId> + <artifactId>antlr4-runtime</artifactId> + <version>4.3</version> + </additionalDependency> + </additionalDependencies> + </configuration> + <reportSets> + <reportSet> + <reports> + <report>javadoc-no-fork</report> + <report>test-javadoc-no-fork</report> + </reports> + </reportSet> + <reportSet> + <id>aggregate</id> + <reports> + <report>aggregate</report> + <report>test-aggregate</report> + </reports> + </reportSet> + </reportSets> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jxr-plugin</artifactId> + <version>2.3</version> + <reportSets> + <reportSet> + <id>aggregate</id> + <reports> + <report>aggregate</report> + <report>test-aggregate</report> + </reports> + </reportSet> + </reportSets> + </plugin> + + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-changelog-plugin</artifactId> + <version>2.3</version> + <reportSets> + <reportSet> + <id>dual-report</id> + <configuration> + <type>range</type> + <range>30</range> + </configuration> + <reports> + <report>changelog</report> + <report>file-activity</report> + </reports> + </reportSet> + </reportSets> + </plugin> + + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>taglist-maven-plugin</artifactId> + <version>2.4</version> + </plugin> + </plugins> + </reporting> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-iaas-adapter-features</artifactId> + <classifier>features</classifier> + <type>xml</type> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-iaas-adapter-provider</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + + </dependencyManagement> + + <modules> + <module>appc-iaas-adapter-bundle</module> + <module>appc-iaas-adapter-features</module> + <module>appc-iaas-adapter-installer</module> + </modules> +</project> |