/*-
* ============LICENSE_START=======================================================
* ONAP : APPC
* ================================================================================
* Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
* ================================================================================
* Copyright (C) 2017 Amdocs
* =============================================================================
* 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.
*
* ECOMP is a trademark and service mark of AT&T Intellectual Property.
* ============LICENSE_END=========================================================
*/
package org.onap.appc.adapter.iaas.provider.operation.impl.base;
import org.onap.appc.Constants;
import org.onap.appc.adapter.iaas.impl.*;
import org.onap.appc.i18n.Msg;
import com.att.cdp.exceptions.ContextConnectionException;
import com.att.cdp.exceptions.NotLoggedInException;
import com.att.cdp.exceptions.TimeoutException;
import com.att.cdp.exceptions.ZoneException;
import com.att.cdp.pal.util.StringHelper;
import com.att.cdp.zones.ComputeService;
import com.att.cdp.zones.Context;
import com.att.cdp.zones.ImageService;
import com.att.cdp.zones.NetworkService;
import com.att.cdp.zones.Provider;
import com.att.cdp.zones.model.Hypervisor;
import com.att.cdp.zones.model.Image;
import com.att.cdp.zones.model.Network;
import com.att.cdp.zones.model.Port;
import com.att.cdp.zones.model.Server;
import com.att.eelf.configuration.EELFLogger;
import com.att.eelf.configuration.EELFManager;
import com.att.eelf.i18n.EELFResourceManager;
import org.glassfish.grizzly.http.util.HttpStatus;
import java.util.ArrayList;
import java.util.List;
/**
* @since September 29, 2016
*/
public abstract class ProviderServerOperation extends ProviderOperation {
private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderServerOperation.class);
/**
* 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")
protected 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;
}
/**
* 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")
protected 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, Server.Status.RUNNING);
}
protected 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;
}
}
/**
* Enter a pool-wait loop checking the server state to see if it has entered one of the desired states or not.
*
* 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.
*
*
* @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")
protected 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 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 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();
}
/**
* Enter a pool-wait loop checking the server state to see if it has entered one of the desired states or not.
*
* 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.
*
*
* @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")
protected 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 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 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();
}
/**
* 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")
protected 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, Server.Status.READY, Server.Status.ERROR);
}
/**
* 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")
protected 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, Server.Status.RUNNING);
}
/**
* 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")
protected 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, Server.Status.RUNNING, Server.Status.READY);
}
/**
* 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
*/
protected void generateEvent(@SuppressWarnings("unused") RequestContext rc,
@SuppressWarnings("unused") boolean success, @SuppressWarnings("unused") String msg) {
// indication to the DG to generate the event?
}
/**
* Checks if the VM is connected to the Virtual Network and reachable
*
* @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
* @param context The interface cloud service provider to access services or the object model, or both
*
*/
protected void checkVirtualMachineNetworkStatus(RequestContext rc, Server server, Context context)
throws ZoneException, RequestFailedException {
logger.info("Performing the VM Server networking status checks...");
List ports = server.getPorts();
NetworkService netSvc = context.getNetworkService();
String msg;
for (Port port : ports) {
switch (port.getPortState().toString().toUpperCase()) {
/**
* The port is connected, configured, and usable for communication
*/
case "ONLINE":
Network network = netSvc.getNetworkById(port.getNetwork());
// Subnet subnet = netSvc.getSubnetById(port.getSubnetId());
if (!network.getStatus().equals(Network.Status.ACTIVE.toString())) {
msg = EELFResourceManager.format(Msg.SERVER_NETWORK_ERROR, server.getName(), port.getId());
logger.error(msg);
doFailure(rc, HttpStatus.PRECONDITION_FAILED_412, msg);
throw new RequestFailedException("VM Server Network is DOWN", msg.toString(),
HttpStatus.PRECONDITION_FAILED_412, server);
}
break;
/**
* The port is disconnected or powered-off and cannot be used for communication
*/
case "OFFLINE":
msg = EELFResourceManager.format(Msg.SERVER_NETWORK_ERROR, server.getName(), port.getId());
logger.error(msg);
doFailure(rc, HttpStatus.PRECONDITION_FAILED_412, msg);
throw new RequestFailedException("VM Server Port status is OFFLINE", msg.toString(),
HttpStatus.PRECONDITION_FAILED_412, server);
/**
* The port's status is changing because of some event or operation. The final state is yet to be
* determined.
*/
case "PENDING":
msg = EELFResourceManager.format(Msg.SERVER_NETWORK_ERROR, server.getName(), port.getId());
logger.error(msg);
doFailure(rc, HttpStatus.PRECONDITION_FAILED_412, msg);
throw new RequestFailedException("VM Server Port status is PENDING", msg.toString(),
HttpStatus.PRECONDITION_FAILED_412, server);
/**
* The port is in an unknown state and cannot be used.
*/
case "UNKNOWN":
msg = EELFResourceManager.format(Msg.SERVER_NETWORK_ERROR, server.getName(), port.getId());
logger.error(msg);
doFailure(rc, HttpStatus.PRECONDITION_FAILED_412, msg);
throw new RequestFailedException("VM Server Port status is UNKNOWN", msg.toString(),
HttpStatus.PRECONDITION_FAILED_412, server);
}
}
logger.info("Passed the VM Server the Hypervisor status checks..");
}
/**
* Checks if the VM is connected to the Virtual Network and reachable
*
* @param server The server object representing the server we want to operate on
*/
protected void checkHypervisor(Server server) throws ZoneException, RequestFailedException {
logger.info("Performing the Hypervisor status checks..");
String msg = null;
if (server.getHypervisor() != null && server.getHypervisor().getStatus() != null
&& server.getHypervisor().getState() != null) {
String status = null;
String state = null;
status = server.getHypervisor().getStatus().toString();
state = server.getHypervisor().getState().toString();
if (!status.equals(Hypervisor.Status.ENABLED.toString()) || !state.equals(Hypervisor.State.UP.toString())) {
msg = EELFResourceManager.format(Msg.HYPERVISOR_DOWN_ERROR, server.getHypervisor().getHostName(),
server.getName());
logger.error(msg.toString());
// doFailure(rc, HttpStatus.PRECONDITION_FAILED_412, msg);
throw new RequestFailedException("Hypervisor status DOWN or NOT ENABLED", msg.toString(),
HttpStatus.PRECONDITION_FAILED_412, server);
}
} else {
msg = EELFResourceManager.format(Msg.HYPERVISOR_STATUS_UKNOWN, server.getName());
logger.error(msg.toString());
throw new RequestFailedException("Unable to determine Hypervisor status", msg.toString(),
HttpStatus.PRECONDITION_FAILED_412, server);
}
logger.info("Passed the Hypervisor status checks..");
}
/**
* Checks if a Host machine is reachable
*
* @param ipAddress IP Address of the Host Machine.
* @param server The server object representing the Virtual Machine server
* @return boolean
*
*/
/*
* private boolean isHostReachable(String ipAddress) throws IOException {
*
* InetAddress address = InetAddress.getByName(ipAddress);
*
* return address.isReachable(15000);
*
*
* }
*/
}