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