Changed to unmaintained
[appc.git] / appc-adapters / appc-iaas-adapter / appc-iaas-adapter-bundle / src / main / java / org / onap / appc / adapter / iaas / provider / operation / impl / base / ProviderServerOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Copyright (C) 2017 Amdocs
8  * =============================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * 
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.appc.adapter.iaas.provider.operation.impl.base;
25
26 import com.att.cdp.exceptions.ContextConnectionException;
27 import com.att.cdp.exceptions.NotLoggedInException;
28 import com.att.cdp.exceptions.TimeoutException;
29 import com.att.cdp.exceptions.ZoneException;
30 import com.att.cdp.pal.util.StringHelper;
31 import com.att.cdp.zones.ComputeService;
32 import com.att.cdp.zones.Context;
33 import com.att.cdp.zones.ImageService;
34 import com.att.cdp.zones.NetworkService;
35 import com.att.cdp.zones.Provider;
36 import com.att.cdp.zones.model.Hypervisor;
37 import com.att.cdp.zones.model.Image;
38 import com.att.cdp.zones.model.Network;
39 import com.att.cdp.zones.model.Port;
40 import com.att.cdp.zones.model.Server;
41 import com.att.eelf.configuration.EELFLogger;
42 import com.att.eelf.configuration.EELFManager;
43 import com.att.eelf.i18n.EELFResourceManager;
44 import java.util.ArrayList;
45 import java.util.List;
46 import org.glassfish.grizzly.http.util.HttpStatus;
47 import org.onap.appc.Constants;
48 import org.onap.appc.adapter.iaas.impl.RequestContext;
49 import org.onap.appc.adapter.iaas.impl.RequestFailedException;
50 import org.onap.appc.i18n.Msg;
51
52 /**
53  * @since September 29, 2016
54  */
55 public abstract class ProviderServerOperation extends ProviderOperation {
56
57     private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderServerOperation.class);
58
59     /**
60      * Looks up the indicated server using the provided context and returns the server to the caller
61      *
62      * @param rc The request context
63      * @param context The provider context
64      * @param id The id of the server
65      * @return The server, or null if there is a problem
66      * @throws ZoneException If the server cannot be found
67      * @throws RequestFailedException If the server cannot be found because we cant connect to the provider
68      */
69     @SuppressWarnings("nls")
70     protected Server lookupServer(RequestContext rc, Context context, String id)
71         throws ZoneException, RequestFailedException {
72         ComputeService service = context.getComputeService();
73         Server server = null;
74         String msg;
75         Provider provider = context.getProvider();
76
77         while (rc.attempt()) {
78             try {
79                 server = service.getServer(id);
80                 break;
81             } catch (ContextConnectionException e) {
82                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
83                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
84                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
85                     Integer.toString(rc.getRetryLimit()));
86                 logger.error(msg, e);
87                 rc.delay();
88             }
89         }
90         if (rc.isFailed()) {
91             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
92             logger.error(msg);
93             doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
94             throw new RequestFailedException("Lookup Server", msg, HttpStatus.BAD_GATEWAY_502, server);
95         }
96         return server;
97     }
98
99
100     /**
101      * Resume a suspended server and wait for it to enter a running state
102      *
103      * @param rc The request context that manages the state and recovery of the request for the life of its processing.
104      * @param server The server to be resumed
105      */
106     @SuppressWarnings("nls")
107     protected void resumeServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
108         logger.debug(Msg.RESUME_SERVER, server.getId());
109
110         Context context = server.getContext();
111         String msg;
112         Provider provider = context.getProvider();
113         ComputeService service = context.getComputeService();
114         while (rc.attempt()) {
115             try {
116                 server.resume();
117                 break;
118             } catch (ContextConnectionException e) {
119                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
120                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
121                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
122                     Integer.toString(rc.getRetryLimit()));
123                 logger.error(msg, e);
124                 rc.delay();
125             }
126         }
127         if (rc.isFailed()) {
128             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
129             logger.error(msg);
130             throw new RequestFailedException("Resume Server", msg, HttpStatus.BAD_GATEWAY_502, server);
131         }
132         rc.reset();
133         waitForStateChange(rc, server, Server.Status.RUNNING);
134     }
135
136
137     protected boolean hasImageAccess(@SuppressWarnings("unused") RequestContext rc, Context context) {
138         logger.info("Checking permissions for image service.");
139         try {
140             ImageService service = context.getImageService();
141             service.getImageByName("CHECK_IMAGE_ACCESS");
142             logger.info("Image service is accessible.");
143             return true;
144         } catch (ZoneException e) {
145             logger.warn("Image service could not be accessed. Some operations may fail.", e);
146             return false;
147         }
148     }
149
150
151     /**
152      * Enter a pool-wait loop checking the server state to see if it has entered one of the desired states or not. <p>
153      * This method checks the state of the server periodically for one of the desired states. When the server enters one
154      * of the desired states, the method returns a successful indication (true). If the server never enters one of the
155      * desired states within the allocated timeout period, then the method returns a failed response (false). No
156      * exceptions are thrown from this method. </p>
157      *
158      * @param rc The request context that manages the state and recovery of the request for the life of its processing.
159      * @param image The server to wait on
160      * @param desiredStates A variable list of desired states, any one of which is allowed.
161      * @throws RequestFailedException If the request times out or fails for some reason
162      */
163     @SuppressWarnings("nls")
164     protected void waitForStateChange(RequestContext rc, Image image, Image.Status... desiredStates)
165         throws RequestFailedException, NotLoggedInException {
166         int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL);
167         int timeout = configuration.getIntegerProperty(Constants.PROPERTY_SERVER_STATE_CHANGE_TIMEOUT);
168         Context context = image.getContext();
169         Provider provider = context.getProvider();
170         ImageService service = context.getImageService();
171         String msg;
172
173         long endTime = System.currentTimeMillis() + (timeout * 1000); //
174
175         while (rc.attempt()) {
176             try {
177                 try {
178                     image.waitForStateChange(pollInterval, timeout, desiredStates);
179                     break;
180                 } catch (TimeoutException e) {
181                     @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
182                     List<String> list = new ArrayList<>();
183                     for (Image.Status desiredState : desiredStates) {
184                         list.add(desiredState.name());
185                     }
186                     msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
187                         context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
188                         Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
189                         Integer.toString(rc.getRetryLimit()));
190                     logger.error(msg, e);
191                     rc.delay();
192                 }
193             } catch (ZoneException e) {
194                 List<String> list = new ArrayList<>();
195                 for (Image.Status desiredState : desiredStates) {
196                     list.add(desiredState.name());
197                 }
198                 String reason = EELFResourceManager.format(Msg.STATE_CHANGE_EXCEPTION, e.getClass().getSimpleName(),
199                     "server", image.getName(), image.getId(), StringHelper.asList(list), image.getStatus().name(),
200                     e.getMessage());
201                 logger.error(reason);
202                 logger.error(EELFResourceManager.format(e));
203
204                 // Instead of failing we are going to wait and try again.
205                 // Timeout is reduced by delay time
206                 logger.info(String.format("Retrying in %ds", rc.getRetryDelay()));
207                 rc.delay();
208                 timeout = (int) (endTime - System.currentTimeMillis()) / 1000;
209                 // throw new RequestFailedException(e, operation, reason,
210             }
211         }
212
213         if (rc.isFailed()) {
214             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
215             logger.error(msg);
216             throw new RequestFailedException("Waiting for State Change", msg, HttpStatus.BAD_GATEWAY_502, new Server());
217         }
218         rc.reset();
219     }
220
221
222     /**
223      * Enter a pool-wait loop checking the server state to see if it has entered one of the desired states or not. <p>
224      * This method checks the state of the server periodically for one of the desired states. When the server enters one
225      * of the desired states, the method returns a successful indication (true). If the server never enters one of the
226      * desired states within the allocated timeout period, then the method returns a failed response (false). No
227      * exceptions are thrown from this method. </p>
228      *
229      * @param rc The request context that manages the state and recovery of the request for the life of its processing.
230      * @param server The server to wait on
231      * @param desiredStates A variable list of desired states, any one of which is allowed.
232      * @throws RequestFailedException If the request times out or fails for some reason
233      */
234     @SuppressWarnings("nls")
235     protected void waitForStateChange(RequestContext rc, Server server, Server.Status... desiredStates)
236         throws RequestFailedException {
237         int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL);
238         int timeout = configuration.getIntegerProperty(Constants.PROPERTY_SERVER_STATE_CHANGE_TIMEOUT);
239         Context context = server.getContext();
240         Provider provider = context.getProvider();
241         ComputeService service = context.getComputeService();
242         String msg;
243
244         long endTime = System.currentTimeMillis() + (timeout * 1000); //
245
246         while (rc.attempt()) {
247             try {
248                 try {
249                     server.waitForStateChange(pollInterval, timeout, desiredStates);
250                     break;
251                 } catch (TimeoutException e) {
252                     @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
253                     List<String> list = new ArrayList<>();
254                     for (Server.Status desiredState : desiredStates) {
255                         list.add(desiredState.name());
256                     }
257                     msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
258                         context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
259                         Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
260                         Integer.toString(rc.getRetryLimit()));
261                     logger.error(msg, e);
262                     rc.delay();
263                 }
264             } catch (ZoneException e) {
265                 List<String> list = new ArrayList<>();
266                 for (Server.Status desiredState : desiredStates) {
267                     list.add(desiredState.name());
268                 }
269                 String reason = EELFResourceManager.format(Msg.STATE_CHANGE_EXCEPTION, e.getClass().getSimpleName(),
270                     "server", server.getName(), server.getId(), StringHelper.asList(list),
271                     server.getStatus().name(), e.getMessage());
272                 logger.error(reason);
273                 logger.error(EELFResourceManager.format(e));
274
275                 // Instead of failing we are going to wait and try again.
276                 // Timeout is reduced by delay time
277                 logger.info(String.format("Retrying in %ds", rc.getRetryDelay()));
278                 rc.delay();
279                 timeout = (int) (endTime - System.currentTimeMillis()) / 1000;
280                 // throw new RequestFailedException(e, operation, reason,
281             }
282         }
283
284         if (rc.isFailed()) {
285             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
286             logger.error(msg);
287             throw new RequestFailedException("Waiting for State Change", msg, HttpStatus.BAD_GATEWAY_502, server);
288         }
289         rc.reset();
290     }
291
292     /**
293      * Stop the specified server and wait for it to stop
294      *
295      * @param rc The request context that manages the state and recovery of the request for the life of its processing.
296      * @param server The server to be stopped
297      */
298     @SuppressWarnings("nls")
299     protected void stopServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
300         logger.debug(Msg.STOP_SERVER, server.getId());
301
302         String msg;
303         Context context = server.getContext();
304         Provider provider = context.getProvider();
305         ComputeService service = context.getComputeService();
306         while (rc.attempt()) {
307             try {
308                 server.stop();
309                 break;
310             } catch (ContextConnectionException e) {
311                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
312                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
313                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
314                     Integer.toString(rc.getRetryLimit()));
315                 logger.error(msg, e);
316                 rc.delay();
317             }
318         }
319         if (rc.isFailed()) {
320             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
321             logger.error(msg);
322             throw new RequestFailedException("Stop Server", msg, HttpStatus.BAD_GATEWAY_502, server);
323         }
324         rc.reset();
325         waitForStateChange(rc, server, Server.Status.READY, Server.Status.ERROR);
326     }
327
328     /**
329      * Start the server and wait for it to enter a running state
330      *
331      * @param rc The request context that manages the state and recovery of the request for the life of its processing.
332      * @param server The server to be started
333      */
334     @SuppressWarnings("nls")
335     protected void startServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
336         logger.debug(Msg.START_SERVER, server.getId());
337         String msg;
338         Context context = server.getContext();
339         Provider provider = context.getProvider();
340         ComputeService service = context.getComputeService();
341         while (rc.attempt()) {
342             try {
343                 server.start();
344                 break;
345             } catch (ContextConnectionException e) {
346                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
347                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
348                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
349                     Integer.toString(rc.getRetryLimit()));
350                 logger.error(msg, e);
351                 rc.delay();
352             }
353         }
354         if (rc.isFailed()) {
355             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
356             logger.error(msg);
357             throw new RequestFailedException("Start Server", msg, HttpStatus.BAD_GATEWAY_502, server);
358         }
359         rc.reset();
360         waitForStateChange(rc, server, Server.Status.RUNNING);
361     }
362
363
364     /**
365      * Un-Pause a paused server and wait for it to enter a running state
366      *
367      * @param rc The request context that manages the state and recovery of the request for the life of its processing.
368      * @param server The server to be un-paused
369      */
370     @SuppressWarnings("nls")
371     protected void unpauseServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
372         logger.debug(Msg.UNPAUSE_SERVER, server.getId());
373
374         String msg;
375         Context context = server.getContext();
376         Provider provider = context.getProvider();
377         ComputeService service = context.getComputeService();
378         while (rc.attempt()) {
379             try {
380                 server.unpause();
381                 break;
382             } catch (ContextConnectionException e) {
383                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
384                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
385                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
386                     Integer.toString(rc.getRetryLimit()));
387                 logger.error(msg, e);
388                 rc.delay();
389             }
390         }
391         if (rc.isFailed()) {
392             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
393             logger.error(msg);
394             throw new RequestFailedException("Unpause Server", msg, HttpStatus.BAD_GATEWAY_502, server);
395         }
396         rc.reset();
397         waitForStateChange(rc, server, Server.Status.RUNNING, Server.Status.READY);
398     }
399
400
401     /**
402      * Generates the event indicating what happened
403      *
404      * @param rc The request context that manages the state and recovery of the request for the life of its processing.
405      * @param success True if the event represents a successful outcome
406      * @param msg The detailed message
407      */
408     protected void generateEvent(@SuppressWarnings("unused") RequestContext rc,
409         @SuppressWarnings("unused") boolean success, @SuppressWarnings("unused") String msg) {
410         // indication to the DG to generate the event?
411     }
412
413     /**
414      * Checks if the VM is connected to the Virtual Network and reachable
415      *
416      * @param rc The request context that manages the state and recovery of the request for the life of its processing.
417      * @param server The server object representing the server we want to operate on
418      * @param context The interface cloud service provider to access services or the object model, or both
419      */
420     protected void checkVirtualMachineNetworkStatus(RequestContext rc, Server server, Context context)
421         throws ZoneException, RequestFailedException {
422
423         logger.info("Performing the VM Server networking status checks...");
424         List<Port> ports = server.getPorts();
425
426         NetworkService netSvc = context.getNetworkService();
427
428         String msg;
429         for (Port port : ports) {
430             switch (port.getPortState().toString().toUpperCase()) {
431                 case "ONLINE":
432                     /* The port is connected, configured, and usable for communication */
433                     Network network = netSvc.getNetworkById(port.getNetwork());
434                     validateNetwork(rc, server, port, network);
435                     break;
436                 case "OFFLINE":
437                     /* The port is disconnected or powered-off and cannot be used for communication */
438                     msg = createErrorMessage(rc, server, port);
439                     throw new RequestFailedException("VM Server Port status is OFFLINE", msg,
440                         HttpStatus.PRECONDITION_FAILED_412, server);
441                 case "PENDING":
442                     /* The port's status is changing because of some event or operation. The final state is yet to be determined. */
443                     msg = createErrorMessage(rc, server, port);
444                     throw new RequestFailedException("VM Server Port status is PENDING", msg,
445                         HttpStatus.PRECONDITION_FAILED_412, server);
446                 case "UNKNOWN":
447                     /* The port is in an unknown state and cannot be used. */
448                     msg = createErrorMessage(rc, server, port);
449                     throw new RequestFailedException("VM Server Port status is UNKNOWN", msg,
450                         HttpStatus.PRECONDITION_FAILED_412, server);
451                 default:
452                     logger.error("Invalid port state");
453                     break;
454             }
455
456         }
457         logger.info("Passed the VM Server the Hypervisor status checks..");
458     }
459
460     private String createErrorMessage(RequestContext rc, Server server, Port port) {
461         String msg;
462         msg = EELFResourceManager.format(Msg.SERVER_NETWORK_ERROR, server.getName(), port.getId());
463         logger.error(msg);
464         doFailure(rc, HttpStatus.PRECONDITION_FAILED_412, msg);
465         return msg;
466     }
467
468     private void validateNetwork(RequestContext rc, Server server, Port port, Network network)
469         throws RequestFailedException {
470         String msg;
471         if (!network.getStatus().equals(Network.Status.ACTIVE.toString())) {
472             msg = createErrorMessage(rc, server, port);
473             throw new RequestFailedException("VM Server Network is DOWN", msg,
474                 HttpStatus.PRECONDITION_FAILED_412, server);
475         }
476     }
477
478     /**
479      * Checks if the VM is connected to the Virtual Network and reachable
480      *
481      * @param server The server object representing the server we want to operate on
482      */
483     protected void checkHypervisor(Server server) throws ZoneException, RequestFailedException {
484
485         logger.info("Performing the Hypervisor status checks..");
486
487         String msg;
488         if (server.getHypervisor() != null && server.getHypervisor().getStatus() != null
489             && server.getHypervisor().getState() != null) {
490             String status;
491             String state;
492
493             status = server.getHypervisor().getStatus().toString();
494             state = server.getHypervisor().getState().toString();
495
496             if (!status.equals(Hypervisor.Status.ENABLED.toString()) || !state.equals(Hypervisor.State.UP.toString())) {
497                 msg = EELFResourceManager.format(Msg.HYPERVISOR_DOWN_ERROR, server.getHypervisor().getHostName(),
498                     server.getName());
499                 logger.error(msg);
500                 throw new RequestFailedException("Hypervisor status DOWN or NOT ENABLED", msg,
501                     HttpStatus.PRECONDITION_FAILED_412, server);
502             }
503         } else {
504             msg = EELFResourceManager.format(Msg.HYPERVISOR_STATUS_UKNOWN, server.getName());
505             logger.error(msg);
506
507             throw new RequestFailedException("Unable to determine Hypervisor status", msg,
508                 HttpStatus.PRECONDITION_FAILED_412, server);
509         }
510         logger.info("Passed the Hypervisor status checks..");
511     }
512 }