private synchronized Answer execute()

in plugins/network-elements/netscaler/src/main/java/com/cloud/network/resource/NetscalerResource.java [547:910]


    private synchronized Answer execute(final LoadBalancerConfigCommand cmd, final int numRetries) {
        try {
            if (_isSdx) {
                return Answer.createUnsupportedCommandAnswer(cmd);
            }

            final LoadBalancerTO[] loadBalancers = cmd.getLoadBalancers();
            if (loadBalancers == null) {
                return new Answer(cmd);
            }

            for (final LoadBalancerTO loadBalancer : loadBalancers) {
                final String srcIp = loadBalancer.getSrcIp();
                final int srcPort = loadBalancer.getSrcPort();
                final String lbProtocol = getNetScalerProtocol(loadBalancer);
                final String lbAlgorithm = loadBalancer.getAlgorithm();
                final String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort);
                final String nsMonitorName = generateNSMonitorName(srcIp, srcPort);
                final LbSslCert sslCert = loadBalancer.getSslCert();

                if (loadBalancer.isAutoScaleVmGroupTO()) {
                    applyAutoScaleConfig(loadBalancer);
                    // Continue to process all the rules.
                    continue;
                }
                boolean hasMonitor = false;
                boolean deleteMonitor = false;
                boolean destinationsToAdd = false;
                boolean deleteCert = false;
                for (final DestinationTO destination : loadBalancer.getDestinations()) {
                    if (!destination.isRevoked()) {
                        destinationsToAdd = true;
                        break;
                    }
                }

                if (!loadBalancer.isRevoked() && destinationsToAdd) {

                    // create a load balancing virtual server
                    addLBVirtualServer(nsVirtualServerName, srcIp, srcPort, lbAlgorithm, lbProtocol, loadBalancer.getStickinessPolicies(), null);
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Created load balancing virtual server " + nsVirtualServerName + " on the Netscaler device");
                    }

                    // create a new monitor
                    final HealthCheckPolicyTO[] healthCheckPolicies = loadBalancer.getHealthCheckPolicies();
                    if (healthCheckPolicies != null && healthCheckPolicies.length > 0 && healthCheckPolicies[0] != null) {

                        for (final HealthCheckPolicyTO healthCheckPolicyTO : healthCheckPolicies) {
                            if (!healthCheckPolicyTO.isRevoked()) {
                                addLBMonitor(nsMonitorName, lbProtocol, healthCheckPolicyTO);
                                hasMonitor = true;
                            } else {
                                deleteMonitor = true;
                                hasMonitor = false;
                            }
                        }

                    }

                    for (final DestinationTO destination : loadBalancer.getDestinations()) {

                        final String nsServerName = generateNSServerName(destination.getDestIp());
                        final String nsServiceName = generateNSServiceName(destination.getDestIp(), destination.getDestPort());
                        if (!destination.isRevoked()) {
                            // add a new destination to deployed load balancing rule

                            // add a new server
                            if (!nsServerExists(nsServerName)) {
                                final com.citrix.netscaler.nitro.resource.config.basic.server nsServer = new com.citrix.netscaler.nitro.resource.config.basic.server();
                                nsServer.set_name(nsServerName);
                                nsServer.set_ipaddress(destination.getDestIp());
                                apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.add(_netscalerService, nsServer);
                                if (apiCallResult.errorcode != 0 && apiCallResult.errorcode != NitroError.NS_RESOURCE_EXISTS) {
                                    throw new ExecutionException("Failed to add server " + destination.getDestIp() + " due to" + apiCallResult.message);
                                }
                            }

                            // create a new service using the server added
                            if (!nsServiceExists(nsServiceName)) {
                                final com.citrix.netscaler.nitro.resource.config.basic.service newService = new com.citrix.netscaler.nitro.resource.config.basic.service();
                                newService.set_name(nsServiceName);
                                newService.set_port(destination.getDestPort());
                                newService.set_servername(nsServerName);
                                newService.set_state("ENABLED");
                                if(lbProtocol.equalsIgnoreCase(NetUtils.SSL_PROTO)) {
                                    newService.set_servicetype(NetUtils.HTTP_PROTO);
                                } else {
                                    newService.set_servicetype(lbProtocol);
                                }

                                apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.service.add(_netscalerService, newService);
                                if (apiCallResult.errorcode != 0) {
                                    throw new ExecutionException("Failed to create service " + nsServiceName + " using server " + nsServerName + " due to" +
                                            apiCallResult.message);
                                }
                            }

                            //bind service to load balancing virtual server
                            if (!nsServiceBindingExists(nsVirtualServerName, nsServiceName)) {
                                final com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding svcBinding =
                                        new com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding();
                                svcBinding.set_name(nsVirtualServerName);
                                svcBinding.set_servicename(nsServiceName);
                                apiCallResult = com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.add(_netscalerService, svcBinding);

                                if (apiCallResult.errorcode != 0) {
                                    throw new ExecutionException("Failed to bind service: " + nsServiceName + " to the lb virtual server: " + nsVirtualServerName +
                                            " on Netscaler device");
                                }
                            }

                            // After binding the service to the LB Vserver
                            // successfully, bind the created monitor to the
                            // service.
                            if (hasMonitor) {
                                if (!isServiceBoundToMonitor(nsServiceName, nsMonitorName)) {
                                    bindServiceToMonitor(nsServiceName, nsMonitorName);
                                }
                            } else {
                                // check if any monitor created by CS is already
                                // existing, if yes, unbind it from services and
                                // delete it.
                                if (nsMonitorExist(nsMonitorName)) {
                                    // unbind the service from the monitor and
                                    // delete the monitor
                                    unBindServiceToMonitor(nsServiceName, nsMonitorName);
                                    deleteMonitor = true;
                                }

                            }

                            if (sslCert != null && lbProtocol.equalsIgnoreCase(NetUtils.SSL_PROTO)) {
                                if (sslCert.isRevoked()) {
                                    deleteCert = true;
                                } else {

                                    // If there is a chain, that should go first to the NS

                                    String previousCertKeyName = null;

                                    if (sslCert.getChain() != null) {
                                        final List<Certificate> chainList = CertificateHelper.parseChain(sslCert.getChain());
                                        // go from ROOT to intermediate CAs
                                        for (final Certificate intermediateCert : Lists.reverse(chainList)) {

                                            final String fingerPrint = CertificateHelper.generateFingerPrint(intermediateCert);
                                            final String intermediateCertKeyName = generateSslCertKeyName(fingerPrint);
                                            final String intermediateCertFileName = intermediateCertKeyName + ".pem";

                                            if (!SSL.isSslCertKeyPresent(_netscalerService, intermediateCertKeyName)) {
                                                final PemObject pemObject = new PemObject(intermediateCert.getType(), intermediateCert.getEncoded());
                                                final StringWriter textWriter = new StringWriter();
                                                try (final PemWriter pemWriter = new PemWriter(textWriter);) {
                                                    pemWriter.writeObject(pemObject);
                                                    pemWriter.flush();
                                                } catch (final IOException e) {
                                                    if (LOGGER.isDebugEnabled())
                                                    {
                                                        LOGGER.debug("couldn't write PEM to a string", e);
                                                    } // else just close the certDataStream
                                                }

                                                SSL.uploadCert(_ip, _username, _password, intermediateCertFileName, textWriter.toString().getBytes());
                                                SSL.createSslCertKey(_netscalerService, intermediateCertFileName, null, intermediateCertKeyName, null);
                                            }

                                            if (previousCertKeyName != null && !SSL.certLinkExists(_netscalerService, intermediateCertKeyName, previousCertKeyName)) {
                                                SSL.linkCerts(_netscalerService, intermediateCertKeyName, previousCertKeyName);
                                            }

                                            previousCertKeyName = intermediateCertKeyName;
                                        }
                                    }

                                    final String certFilename = generateSslCertName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
                                    final String keyFilename = generateSslKeyName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
                                    final String certKeyName = generateSslCertKeyName(sslCert.getFingerprint());

                                    try (final ByteArrayOutputStream certDataStream = new ByteArrayOutputStream();) {
                                        certDataStream.write(sslCert.getCert().getBytes());

                                        if (!SSL.isSslCertKeyPresent(_netscalerService, certKeyName)) {

                                            SSL.uploadCert(_ip, _username, _password, certFilename, certDataStream.toByteArray());
                                            SSL.uploadKey(_ip, _username, _password, keyFilename, sslCert.getKey().getBytes());
                                            SSL.createSslCertKey(_netscalerService, certFilename, keyFilename, certKeyName, sslCert.getPassword());
                                        }
                                    } catch (final IOException e) {
                                        if (LOGGER.isDebugEnabled())
                                        {
                                            LOGGER.debug("couldn't open buffer for certificate", e);
                                        } // else just close the certDataStream
                                    }

                                    if (previousCertKeyName != null && !SSL.certLinkExists(_netscalerService, certKeyName, previousCertKeyName)) {
                                        SSL.linkCerts(_netscalerService, certKeyName, previousCertKeyName);
                                    }

                                    SSL.bindCertKeyToVserver(_netscalerService, certKeyName, nsVirtualServerName);
                                }

                            }

                            if (LOGGER.isDebugEnabled()) {
                                LOGGER.debug("Successfully added LB destination: " + destination.getDestIp() + ":" + destination.getDestPort() + " to load balancer " +
                                        srcIp + ":" + srcPort);
                            }

                        } else {
                            // remove a destination from the deployed load balancing rule
                            final com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding[] serviceBindings =
                                    com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.get(_netscalerService, nsVirtualServerName);
                            if (serviceBindings != null) {
                                for (final com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding binding : serviceBindings) {
                                    if (nsServiceName.equalsIgnoreCase(binding.get_servicename())) {
                                        // delete the binding
                                        apiCallResult = com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.delete(_netscalerService, binding);
                                        if (apiCallResult.errorcode != 0) {
                                            throw new ExecutionException("Failed to delete the binding between the virtual server: " + nsVirtualServerName +
                                                    " and service:" + nsServiceName + " due to" + apiCallResult.message);
                                        }

                                        // check if service is bound to any other virtual server
                                        if (!isServiceBoundToVirtualServer(nsServiceName)) {
                                            // no lb virtual servers are bound to this service so delete it
                                            apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.service.delete(_netscalerService, nsServiceName);
                                            if (apiCallResult.errorcode != 0) {
                                                throw new ExecutionException("Failed to delete service: " + nsServiceName + " due to " + apiCallResult.message);
                                            }
                                        }

                                        // delete the server if there is no associated services
                                        final server_service_binding[] services = server_service_binding.get(_netscalerService, nsServerName);
                                        if (services == null || services.length == 0) {
                                            apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.delete(_netscalerService, nsServerName);
                                            if (apiCallResult.errorcode != 0) {
                                                throw new ExecutionException("Failed to remove server:" + nsServerName + " due to " + apiCallResult.message);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                } else {
                    // delete the implemented load balancing rule and its destinations
                    final lbvserver lbserver = getVirtualServerIfExisits(nsVirtualServerName);
                    if (lbserver != null) {
                        //unbind the all services associated with this virtual server
                        final com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding[] serviceBindings =
                                com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.get(_netscalerService, nsVirtualServerName);

                        if (serviceBindings != null) {
                            for (final com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding binding : serviceBindings) {
                                final String serviceName = binding.get_servicename();
                                apiCallResult = com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.delete(_netscalerService, binding);
                                if (apiCallResult.errorcode != 0) {
                                    throw new ExecutionException("Failed to unbind service from the lb virtual server: " + nsVirtualServerName + " due to " +
                                            apiCallResult.message);
                                }

                                final com.citrix.netscaler.nitro.resource.config.basic.service svc =
                                        com.citrix.netscaler.nitro.resource.config.basic.service.get(_netscalerService, serviceName);
                                final String nsServerName = svc.get_servername();

                                // check if service is bound to any other virtual server
                                if (!isServiceBoundToVirtualServer(serviceName)) {
                                    // no lb virtual servers are bound to this service so delete it
                                    apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.service.delete(_netscalerService, serviceName);
                                    if (apiCallResult.errorcode != 0) {
                                        throw new ExecutionException("Failed to delete service: " + serviceName + " due to " + apiCallResult.message);
                                    }
                                }

                                //delete the server if no more services attached
                                final server_service_binding[] services = server_service_binding.get(_netscalerService, nsServerName);
                                if (services == null || services.length == 0) {
                                    apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.delete(_netscalerService, nsServerName);
                                    if (apiCallResult.errorcode != 0) {
                                        throw new ExecutionException("Failed to remove server:" + nsServerName + " due to " + apiCallResult.message);
                                    }
                                }
                            }
                        }
                        removeLBVirtualServer(nsVirtualServerName);
                        deleteMonitor = true;
                        deleteCert = true;
                    }
                }
                if (deleteMonitor) {
                    removeLBMonitor(nsMonitorName);
                }
                if (sslCert != null && deleteCert) {

                    final String certFilename = generateSslCertName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
                    final String keyFilename = generateSslKeyName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
                    final String certKeyName = generateSslCertKeyName(sslCert.getFingerprint());

                    // unbind before deleting
                    if (nsVirtualServerExists(nsVirtualServerName) &&
                            SSL.isSslCertKeyPresent(_netscalerService, certKeyName) &&
                            SSL.isBoundToVserver(_netscalerService, certKeyName, nsVirtualServerName)) {
                        SSL.unbindCertKeyFromVserver(_netscalerService, certKeyName, nsVirtualServerName);
                    }

                    if (SSL.isSslCertKeyPresent(_netscalerService, certKeyName)) {

                        SSL.deleteSslCertKey(_netscalerService, certKeyName);
                        SSL.deleteCertFile(_ip, _username, _password, certFilename);
                        SSL.deleteKeyFile(_ip, _username, _password, keyFilename);
                    }

                    /*
                     * Check and delete intermediate certs:
                     * we can delete an intermediate cert if no other
                     * cert references it as the athority
                     */

                    if (sslCert.getChain() != null) {
                        final List<Certificate> chainList = CertificateHelper.parseChain(sslCert.getChain());
                        //go from intermediate CAs to ROOT
                        for (final Certificate intermediateCert : chainList) {

                            final String fingerPrint = CertificateHelper.generateFingerPrint(intermediateCert);
                            final String intermediateCertKeyName = generateSslCertKeyName(fingerPrint);
                            final String intermediateCertFileName = intermediateCertKeyName + ".pem";

                            if (SSL.isSslCertKeyPresent(_netscalerService, intermediateCertKeyName) &&
                                    !SSL.isCaforCerts(_netscalerService, intermediateCertKeyName)) {
                                SSL.deleteSslCertKey(_netscalerService, intermediateCertKeyName);
                                SSL.deleteCertFile(_ip, _username, _password, intermediateCertFileName);
                            } else {
                                break;// if this cert has another certificate as a child then stop at this point because we need the whole chain
                            }

                        }
                    }
                }

            }

            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("Successfully executed resource LoadBalancerConfigCommand: " + _gson.toJson(cmd));
            }

            saveConfiguration();
            return new Answer(cmd);
        } catch (final ExecutionException e) {
            LOGGER.error("Failed to execute LoadBalancerConfigCommand due to ", e);
            if (shouldRetry(numRetries)) {
                return retry(cmd, numRetries);
            } else {
                return new Answer(cmd, e);
            }
        } catch (final Exception e) {
            LOGGER.error("Failed to execute LoadBalancerConfigCommand due to ", e);
            if (shouldRetry(numRetries)) {
                return retry(cmd, numRetries);
            } else {
                return new Answer(cmd, e);
            }
        }
    }