From 58242e9e403d0702113804c2911016abe3dbcd3c Mon Sep 17 00:00:00 2001 From: Mike Hansen Date: Tue, 5 May 2020 17:28:48 -0400 Subject: [PATCH] Initial Drop of Opensync Gateway for Cloud. Still non-functional in several areas --- opensync-ext-cloud/.gitignore | 1 + opensync-ext-cloud/pom.xml | 262 ++++++ .../OpensyncExternalIntegrationCloud.java | 750 ++++++++++++++++++ .../external/integration/OpensyncNode.java | 283 +++++++ ...yncCloudRestTemplatePostConfiguration.java | 55 ++ .../client/OpensyncCloudWebConfig.java | 50 ++ .../OpensyncCloudWebGenericConverter.java | 207 +++++ .../OpensyncCloudGatewayController.java | 130 +++ ...pensyncGatewayControllerStartListener.java | 29 + ...OpensyncGatewayControllerStopListener.java | 29 + .../OpensyncGatewayListenerConfiguration.java | 29 + .../src/main/resources/config_2_ssids.json | 27 + opensync-gateway-build/pom.xml | 2 + opensync-gateway-cloud-docker/pom.xml | 115 +++ .../Dockerfile | 33 + .../app/mqtt/mosquitto.conf | 18 + .../app/opensync/logback.xml | 80 ++ .../app/run.sh | 126 +++ .../src/main/docker/Dockerfile | 16 + .../src/main/docker/app/opensync/logback.xml | 76 ++ .../src/main/docker/app/run.sh | 37 + .../src/main/docker/app/stdout.out | 1 + opensync-gateway-cloud-process/.gitignore | 1 + opensync-gateway-cloud-process/pom.xml | 43 + .../OpenSyncGatewayCloudProcess.java | 22 + .../resources/app/certs/httpClientConfig.json | 18 + .../main/resources/app/certs/ssl.properties | 13 + .../src/main/resources/application.properties | 119 +++ ...wlan cloud certs) - prod wlan_cloud.launch | 27 + .../src/main/resources/logback.xml | 80 ++ .../resources/app/certs/httpClientConfig.json | 3 +- .../opensync/ovsdb/ConnectusOvsdbClient.java | 2 +- 32 files changed, 2681 insertions(+), 3 deletions(-) create mode 100644 opensync-ext-cloud/.gitignore create mode 100644 opensync-ext-cloud/pom.xml create mode 100644 opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/OpensyncExternalIntegrationCloud.java create mode 100644 opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/OpensyncNode.java create mode 100644 opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudRestTemplatePostConfiguration.java create mode 100644 opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudWebConfig.java create mode 100644 opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudWebGenericConverter.java create mode 100644 opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncCloudGatewayController.java create mode 100644 opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayControllerStartListener.java create mode 100644 opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayControllerStopListener.java create mode 100644 opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayListenerConfiguration.java create mode 100644 opensync-ext-cloud/src/main/resources/config_2_ssids.json create mode 100644 opensync-gateway-cloud-docker/pom.xml create mode 100644 opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/Dockerfile create mode 100644 opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/mqtt/mosquitto.conf create mode 100644 opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/opensync/logback.xml create mode 100755 opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/run.sh create mode 100644 opensync-gateway-cloud-docker/src/main/docker/Dockerfile create mode 100644 opensync-gateway-cloud-docker/src/main/docker/app/opensync/logback.xml create mode 100755 opensync-gateway-cloud-docker/src/main/docker/app/run.sh create mode 100644 opensync-gateway-cloud-docker/src/main/docker/app/stdout.out create mode 100644 opensync-gateway-cloud-process/.gitignore create mode 100644 opensync-gateway-cloud-process/pom.xml create mode 100644 opensync-gateway-cloud-process/src/main/java/com/telecominfraproject/wlan/opensync/integration/OpenSyncGatewayCloudProcess.java create mode 100644 opensync-gateway-cloud-process/src/main/resources/app/certs/httpClientConfig.json create mode 100644 opensync-gateway-cloud-process/src/main/resources/app/certs/ssl.properties create mode 100644 opensync-gateway-cloud-process/src/main/resources/application.properties create mode 100644 opensync-gateway-cloud-process/src/main/resources/launchers/OpenSyncProcess (local, wlan cloud certs) - prod wlan_cloud.launch create mode 100644 opensync-gateway-cloud-process/src/main/resources/logback.xml diff --git a/opensync-ext-cloud/.gitignore b/opensync-ext-cloud/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/opensync-ext-cloud/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/opensync-ext-cloud/pom.xml b/opensync-ext-cloud/pom.xml new file mode 100644 index 0000000..ac367b9 --- /dev/null +++ b/opensync-ext-cloud/pom.xml @@ -0,0 +1,262 @@ + + + 4.0.0 + + com.telecominfraproject.wlan + tip-wlan-cloud-root-pom + 0.0.1-SNAPSHOT + ../../wlan-cloud-root + + opensync-ext-cloud + opensync-ext-cloud + Configuration interface that provides cloud config from the file + + + com.telecominfraproject.wlan + opensync-ext-interface + ${tip-wlan-cloud.release.version} + + + com.telecominfraproject.wlan + opensync-ext-interface + ${tip-wlan-cloud.release.version} + + + base-container + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + base-client + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + webtoken-auth-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + portal-services + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + customer-service-local + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + location-service-local + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + equipment-service-local + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + profile-service-local + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + customer-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + customer-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + location-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + location-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + equipment-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + equipment-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + profile-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + profile-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + portal-user-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + portal-user-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + firmware-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + firmware-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + manufacturer-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + manufacturer-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + cloud-event-dispatcher-interface + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + cloud-metrics + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + single-process-streams + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + service-metric-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + service-metric-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + system-event-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + system-event-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + alarm-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + alarm-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + status-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + status-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + client-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + client-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + routing-service + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + + routing-datastore-inmemory + com.telecominfraproject.wlan + ${tip-wlan-cloud.release.version} + + + + diff --git a/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/OpensyncExternalIntegrationCloud.java b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/OpensyncExternalIntegrationCloud.java new file mode 100644 index 0000000..07410e4 --- /dev/null +++ b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/OpensyncExternalIntegrationCloud.java @@ -0,0 +1,750 @@ +package com.telecominfraproject.wlan.opensync.external.integration; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import com.telecominfraproject.wlan.cloudeventdispatcher.CloudEventDispatcherInterface; +import com.telecominfraproject.wlan.core.model.equipment.EquipmentType; +import com.telecominfraproject.wlan.core.model.equipment.MacAddress; +import com.telecominfraproject.wlan.core.model.equipment.RadioType; +import com.telecominfraproject.wlan.customer.models.Customer; +import com.telecominfraproject.wlan.customer.service.CustomerServiceInterface; +import com.telecominfraproject.wlan.equipment.EquipmentServiceInterface; +import com.telecominfraproject.wlan.equipment.models.Equipment; +import com.telecominfraproject.wlan.equipment.models.EquipmentDetails; +import com.telecominfraproject.wlan.location.service.LocationServiceInterface; +import com.telecominfraproject.wlan.opensync.external.integration.controller.OpensyncCloudGatewayController; +import com.telecominfraproject.wlan.opensync.external.integration.models.ConnectNodeInfo; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPConfig; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPInetState; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPRadioConfig; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPRadioState; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPSsidConfig; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPVIFState; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAWLANNode; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncWifiAssociatedClients; +import com.telecominfraproject.wlan.profile.ProfileServiceInterface; +import com.telecominfraproject.wlan.profile.models.ProfileDetails; +import com.telecominfraproject.wlan.servicemetrics.models.ApClientMetrics; +import com.telecominfraproject.wlan.servicemetrics.models.ClientMetrics; +import com.telecominfraproject.wlan.servicemetrics.models.SingleMetricRecord; + +import sts.PlumeStats.Client; +import sts.PlumeStats.ClientReport; +import sts.PlumeStats.RadioBandType; +import sts.PlumeStats.Report; +import traffic.NetworkMetadata.FlowReport; +import wc.stats.IpDnsTelemetry.WCStatsReport; + +@Profile("opensync_cloud_config") +@Component +public class OpensyncExternalIntegrationCloud implements OpensyncExternalIntegrationInterface { + + private static final Logger LOG = LoggerFactory.getLogger(OpensyncExternalIntegrationCloud.class); + + @Autowired + private CustomerServiceInterface customerServiceInterface; + @Autowired + private LocationServiceInterface locationServiceInterface; + @Autowired + private OvsdbSessionMapInterface ovsdbSessionMapInterface; + @Autowired + private CloudEventDispatcherInterface equipmentMetricsCollectorInterface; + @Autowired + private EquipmentServiceInterface equipmentServiceInterface; + + @Autowired + private ProfileServiceInterface profileServiceInterface; + + @Autowired + private CacheManager cacheManagerShortLived; + + @Value("${connectus.ovsdb.autoProvisionedCustomerId:2}") + private int autoProvisionedCustomerId; + @Value("${connectus.ovsdb.autoProvisionedEquipmentId:0}") + private int autoProvisionedEquipmentId; + @Value("${connectus.ovsdb.autoProvisionedLocationId:5}") + private int autoProvisionedLocationId; + @Value("${connectus.ovsdb.autoProvisioned24G:1}") + private int autoProvisioned24G; + @Value("${connectus.ovsdb.autoProvisioned5LG:44}") + private int autoProvisioned5LG; + @Value("${connectus.ovsdb.autoProvisioned5UG:108}") + private int autoProvisioned5UG; + @Value("${connectus.ovsdb.autoProvisionedSsid:Connectus-cloud") + private String autoProvisionedSsid; + + private Map opensyncNodeMap; + @Autowired + private OpensyncCloudGatewayController opensyncCloudGatewayController; + + private Cache equipmentRecordCache; + + @PostConstruct + private void postCreate() { + LOG.info("Using cloud integration"); + equipmentRecordCache = cacheManagerShortLived.getCache("opensync_equipment_record_cache"); + opensyncNodeMap = Collections.synchronizedMap(new HashMap()); + } + + public Equipment getEquipment(Long equipmentId) { + Equipment ce = null; + try { + ce = equipmentServiceInterface.getOrNull(equipmentId); + } catch (Exception e) { + // do nothing + } + + return ce; + } + + public void apConnected(String apId, ConnectNodeInfo connectNodeInfo) { + LOG.info("AP {} got connected to the gateway", apId); + + Customer customer = customerServiceInterface.get(autoProvisionedCustomerId); + + Equipment customerEquipment = equipmentServiceInterface.get(autoProvisionedEquipmentId); + + LOG.debug("Customer {} Equipment {}", customer.toPrettyString(), customerEquipment.toPrettyString()); + + OvsdbSession ovsdbSession = ovsdbSessionMapInterface.getSession(apId); + ovsdbSession.setEquipmentId(customerEquipment.getId()); + ovsdbSession.setCustomerId(customerEquipment.getCustomerId()); + + } + + public void apDisconnected(String apId) { + LOG.info("AP {} got disconnected from the gateway", apId); + try { + // removed the 'in-memory' cached node + synchronized (opensyncNodeMap) { + opensyncNodeMap.remove(apId); + LOG.info("AP {} and table state data removed from memory cache", apId); + } + + OvsdbSession ovsdbSession = ovsdbSessionMapInterface.getSession(apId); + + if (ovsdbSession != null) { +// routingServiceInterface.delete(ovsdbSession.getRoutingId()); + } else { + LOG.warn("Cannot find ap {} in inventory", apId); + } + } catch (Exception e) { + LOG.error("Exception when registering ap routing {}", apId, e); + } + + } + + public OpensyncAPConfig getApConfig(String apId) { + LOG.info("Retrieving config for AP {} ", apId); + OpensyncAPConfig ret = null; + + try { + OvsdbSession ovsdbSession = ovsdbSessionMapInterface.getSession(apId); + if (ovsdbSession == null) { + throw new IllegalStateException("AP is not connected " + apId); + } + long equipmentId = ovsdbSession.getEquipmentId(); + + RadioType rt; + + ret = new OpensyncAPConfig(); + + // extract country, radio channels from resolvedEqCfg + String country = "CA"; + + int radioChannel24G = autoProvisioned24G; + int radioChannel5LG = autoProvisioned5LG; + int radioChannel5UG = autoProvisioned5UG; + + OpensyncAPRadioConfig radioConfig = new OpensyncAPRadioConfig(); + radioConfig.setCountry(country); + radioConfig.setRadioChannel24G(radioChannel24G); + radioConfig.setRadioChannel5LG(radioChannel5LG); + radioConfig.setRadioChannel5HG(108); + + ret.setRadioConfig(radioConfig); + + List ssidConfigs = new ArrayList<>(); + ret.setSsidConfigs(ssidConfigs); + + OpensyncAPSsidConfig osSsidCfg = new OpensyncAPSsidConfig(); + osSsidCfg.setSsid(autoProvisionedSsid); + osSsidCfg.setRadioType(com.telecominfraproject.wlan.core.model.equipment.RadioType.is5GHz); + osSsidCfg.setBroadcast(true); + + osSsidCfg.setEncryption("WPA-PSK"); + osSsidCfg.setMode("2"); + + ssidConfigs.add(osSsidCfg); + + // configure the same ssid on the second radio + osSsidCfg = osSsidCfg.clone(); + osSsidCfg.setRadioType(com.telecominfraproject.wlan.core.model.equipment.RadioType.is2dot4GHz); + ssidConfigs.add(osSsidCfg); + + } catch (Exception e) { + LOG.error("Cannot read config for AP {}", apId, e); + } + + LOG.debug("Config content : {}", ret); + + return ret; + } + + /** + * @param topic + * @return apId extracted from the topic name, or null if it cannot be extracted + */ + public static String extractApIdFromTopic(String topic) { + // Topic is formatted as + // "/ap/"+clientCn+"_"+ret.serialNumber+"/opensync" + if (topic == null) { + return null; + } + + String[] parts = topic.split("/"); + if (parts.length < 3) { + return null; + } + + // apId is the third element in the topic + return parts[2]; + } + + /** + * @param topic + * @return customerId looked up from the topic name, or -1 if it cannot be + * extracted + */ + public int extractCustomerIdFromTopic(String topic) { + + String apId = extractApIdFromTopic(topic); + if (apId == null) { + return -1; + } + + OvsdbSession ovsdbSession = ovsdbSessionMapInterface.getSession(apId); + + if (ovsdbSession != null) { + return ovsdbSession.getCustomerId(); + } + + return -1; + + } + + public long extractEquipmentIdFromTopic(String topic) { + + String apId = extractApIdFromTopic(topic); + if (apId == null) { + return -1; + } + + OvsdbSession ovsdbSession = ovsdbSessionMapInterface.getSession(apId); + + if (ovsdbSession != null) { + return ovsdbSession.getEquipmentId(); + } + + return -1; + + } + + public void processMqttMessage(String topic, Report report) { + LOG.info("Received report on topic {} for ap {}", topic, report.getNodeID()); + int customerId = extractCustomerIdFromTopic(topic); + if (customerId > 0) { + opensyncCloudGatewayController.updateActiveCustomer(customerId); + } + + long equipmentId = extractEquipmentIdFromTopic(topic); + if (equipmentId <= 0 || customerId <= 0) { + LOG.warn("Cannot determine equipment ids from topic {} - customerId {} equipmentId {}", topic, customerId, + equipmentId); + return; + } + + List metricRecordList = new ArrayList<>(); + + populateApClientMetrics(metricRecordList, report, customerId, equipmentId); + // TODO: populateApNodeMetrics(metricRecordList, report, customerId, + // equipmentId, extractApIdFromTopic(topic)); + + if (!metricRecordList.isEmpty()) { + equipmentMetricsCollectorInterface.publishMetrics(metricRecordList); + } + + } + + private void populateApClientMetrics(List metricRecordList, Report report, int customerId, + long equipmentId) { + LOG.debug("populateApClientMetrics for Customer {} Equipment {}", customerId, equipmentId); + + for (ClientReport clReport : report.getClientsList()) { + SingleMetricRecord smr = new SingleMetricRecord(customerId, equipmentId); + metricRecordList.add(smr); + + ApClientMetrics apClientMetrics = new ApClientMetrics(); + smr.setData(apClientMetrics); + smr.setCreatedTimestamp(clReport.getTimestampMs()); + + smr.setCustomerId(customerId); + smr.setEquipmentId(equipmentId); + + Integer periodLengthSec = 60; // matches what's configured by + // OvsdbDao.configureStats(OvsdbClient) + apClientMetrics.setPeriodLengthSec(periodLengthSec); + + List clientMetrics = new ArrayList<>(); + + for (Client cl : clReport.getClientListList()) { + + // clReport.getChannel(); + ClientMetrics cMetrics = new ClientMetrics(); + clientMetrics.add(cMetrics); + + cMetrics.setRadioType( + (clReport.getBand() == RadioBandType.BAND2G) ? RadioType.is2dot4GHz : RadioType.is5GHz); + cMetrics.setDeviceMacAddress(new MacAddress(cl.getMacAddress())); + + if (cl.hasStats()) { + if (cl.getStats().hasRssi()) { + cMetrics.setRssi(cl.getStats().getRssi()); + } + + // we'll report each device as having a single (very long) + // session + cMetrics.setSessionId(cMetrics.getDeviceMacAddress().getAddressAsLong()); + + // populate Rx stats + if (cl.getStats().hasRxBytes()) { + cMetrics.setRxBytes(cl.getStats().getRxBytes()); + } + + if (cl.getStats().hasRxRate()) { + // cMetrics.setAverageRxRate(cl.getStats().getRxRate()); + } + + if (cl.getStats().hasRxErrors()) { + cMetrics.setNumRxNoFcsErr((int) cl.getStats().getRxErrors()); + } + + if (cl.getStats().hasRxFrames()) { + // cMetrics.setNumRxFramesReceived(cl.getStats().getRxFrames()); + cMetrics.setNumRxPackets(cl.getStats().getRxFrames()); + } + + if (cl.getStats().hasRxRetries()) { + cMetrics.setNumRxRetry((int) cl.getStats().getRxRetries()); + } + + // populate Tx stats + if (cl.getStats().hasTxBytes()) { + cMetrics.setNumTxBytes(cl.getStats().getTxBytes()); + } + + if (cl.getStats().hasTxRate()) { + // cMetrics.setAverageTxRate(cl.getStats().getTxRate()); + } + + if (cl.getStats().hasTxRate() && cl.getStats().hasRxRate()) { + cMetrics.setRates( + new byte[] { (byte) (cl.getStats().getTxRate()), (byte) (cl.getStats().getRxRate()) }); + } + + if (cl.getStats().hasTxErrors()) { + cMetrics.setNumTxDropped((int) cl.getStats().getTxErrors()); + } + + if (cl.getStats().hasRxFrames()) { + // cMetrics.setNumTxFramesTransmitted(cl.getStats().getTxFrames()); + cMetrics.setNumTxPackets(cl.getStats().getRxFrames()); + } + + if (cl.getStats().hasTxRetries()) { + cMetrics.setNumTxDataRetries((int) cl.getStats().getTxRetries()); + } + + } + } + + if (clReport.getBand() == RadioBandType.BAND2G) { + apClientMetrics.setClientMetrics2g(clientMetrics.toArray(new ClientMetrics[0])); + } else { + apClientMetrics.setClientMetrics5g(clientMetrics.toArray(new ClientMetrics[0])); + } + + } + } + + public void processMqttMessage(String topic, FlowReport flowReport) { + + LOG.info("Received report on topic {}", topic); + int customerId = extractCustomerIdFromTopic(topic); + if (customerId > 0) { + opensyncCloudGatewayController.updateActiveCustomer(customerId); + } + + long equipmentId = extractEquipmentIdFromTopic(topic); + if (equipmentId <= 0 || customerId <= 0) { + LOG.warn("Cannot determine equipment ids from topic {} - customerId {} equipmentId {}", topic, customerId, + equipmentId); + return; + } + + String apId = extractApIdFromTopic(topic); + + if (apId == null) { + LOG.warn("Cannot determine AP id from topic {} - customerId {} equipmentId {} apId {}", topic, customerId, + equipmentId, apId); + return; + } + + } + + public void processMqttMessage(String topic, WCStatsReport wcStatsReport) { + LOG.debug("Received WCStatsReport {}", wcStatsReport.toString()); + + LOG.info("Received report on topic {}", topic); + int customerId = extractCustomerIdFromTopic(topic); + if (customerId > 0) { + opensyncCloudGatewayController.updateActiveCustomer(customerId); + } + + long equipmentId = extractEquipmentIdFromTopic(topic); + if (equipmentId <= 0 || customerId <= 0) { + LOG.warn("Cannot determine equipment ids from topic {} - customerId {} equipmentId {}", topic, customerId, + equipmentId); + return; + } + + String apId = extractApIdFromTopic(topic); + + if (apId == null) { + LOG.warn("Cannot determine AP id from topic {} - customerId {} equipmentId {} apId {}", topic, customerId, + equipmentId, apId); + return; + } + + } + + @Override + public void wifiVIFStateDbTableUpdate(List vifStateTables, String apId) { + if (vifStateTables == null || vifStateTables.isEmpty() || apId == null) + return; + OpensyncNode osNode = null; + + synchronized (opensyncNodeMap) { + + if (opensyncNodeMap.containsKey(apId)) { + osNode = opensyncNodeMap.get(apId); + for (OpensyncAPVIFState vifState : vifStateTables) { + if (vifState.isEnabled()) + osNode.updateVifState(vifState); + } + opensyncNodeMap.put(apId, osNode); + // LOG.debug("Updated VIF States for AP to NodeMap {}", + // opensyncNodeMap.get(apId).toPrettyString()); + } else { + OvsdbSession session = ovsdbSessionMapInterface.getSession(apId); + + if (session != null) { + int customerId = session.getCustomerId(); + long equipmentId = session.getEquipmentId(); + osNode = new OpensyncNode(apId, null, customerId, equipmentId); + for (OpensyncAPVIFState vifState : vifStateTables) { + if (vifState.isEnabled()) + osNode.updateVifState(vifState); + } + opensyncNodeMap.put(apId, osNode); + } + } + + osNode = opensyncNodeMap.get(apId); + List vifStates = osNode.getVifStates(); + LOG.debug( + "BSSID SSID AUTH MODE RADIO DEVICES"); + + for (OpensyncAPVIFState vif : vifStates) { + String ssid = vif.getSsid(); + int channel = vif.getChannel(); + int devices = vif.getAssociatedClients().size(); + String bssid = osNode.getRadioForChannel(channel).getMac(); + String freqBand = osNode.getRadioForChannel(channel).getFreqBand(); + String encryption = vif.getSecurity().get("encryption"); + + LOG.debug("{} {} {} {} {}", bssid, ssid, encryption, freqBand, devices); + } + + } + + } + + @Override + public void wifiRadioStatusDbTableUpdate(List radioStateTables, String apId) { + + OvsdbSession session = ovsdbSessionMapInterface.getSession(apId); + int customerId = session.getCustomerId(); + long equipmentId = session.getEquipmentId(); + + if (customerId > 0) { + opensyncCloudGatewayController.updateActiveCustomer(customerId); + } else { + LOG.debug("Cannot get customerId {} for session {}", customerId); + return; + } + + if (equipmentId < 1) { + LOG.debug("Cannot get equipmentId {} for session {}", equipmentId); + return; + } + + if (radioStateTables == null || radioStateTables.isEmpty() || apId == null) + return; + + // add to RadioStates States Map + OpensyncNode osNode = null; + synchronized (opensyncNodeMap) { + + if (opensyncNodeMap.containsKey(apId)) { + osNode = opensyncNodeMap.get(apId); + for (OpensyncAPRadioState radioState : radioStateTables) { + if (radioState.isEnabled()) + osNode.updateRadioState(radioState); + } + opensyncNodeMap.put(apId, osNode); + } else { + osNode = new OpensyncNode(apId, null, customerId, equipmentId); + for (OpensyncAPRadioState radioState : radioStateTables) { + if (radioState.isEnabled()) + osNode.updateRadioState(radioState); + } + opensyncNodeMap.put(apId, osNode); + + } + } + } + + @Override + public void wifiInetStateDbTableUpdate(List inetStateTables, String apId) { + OvsdbSession session = ovsdbSessionMapInterface.getSession(apId); + int customerId = session.getCustomerId(); + long equipmentId = session.getEquipmentId(); + + if (customerId > 0) { + opensyncCloudGatewayController.updateActiveCustomer(customerId); + } else { + LOG.debug("Cannot get customerId {} for session {}", customerId); + return; + } + + if (equipmentId < 1) { + LOG.debug("Cannot get equipmentId {} for session {}", equipmentId); + return; + } + + if (inetStateTables == null || inetStateTables.isEmpty() || apId == null) + return; + + // add to Inet States Map + OpensyncNode osNode = null; + synchronized (opensyncNodeMap) { + if (opensyncNodeMap.containsKey(apId)) { + osNode = opensyncNodeMap.get(apId); + for (OpensyncAPInetState inetState : inetStateTables) { + if (inetState.isEnabled()) + osNode.updateInetState(inetState); + } + opensyncNodeMap.put(apId, osNode); + } else { + osNode = new OpensyncNode(apId, null, customerId, equipmentId); + for (OpensyncAPInetState inetState : inetStateTables) { + if (inetState.isEnabled()) + osNode.updateInetState(inetState); + } + opensyncNodeMap.put(apId, osNode); + + } + } + + } + + @Override + public void wifiAssociatedClientsDbTableUpdate(List wifiAssociatedClients, + String apId) { + OvsdbSession session = ovsdbSessionMapInterface.getSession(apId); + int customerId = session.getCustomerId(); + long equipmentId = session.getEquipmentId(); + + if (customerId > 0) { + opensyncCloudGatewayController.updateActiveCustomer(customerId); + } else { + LOG.debug("Cannot get customerId {} for session {}", customerId); + return; + } + + if (equipmentId < 1) { + LOG.debug("Cannot get equipmentId {} for session {}", equipmentId); + return; + } + + if (wifiAssociatedClients == null || wifiAssociatedClients.isEmpty() || apId == null) + return; + + OpensyncNode osNode = null; + synchronized (opensyncNodeMap) { + if (opensyncNodeMap.containsKey(apId)) { + osNode = opensyncNodeMap.get(apId); + for (OpensyncWifiAssociatedClients wifiClient : wifiAssociatedClients) { + osNode.updateWifiClients(wifiClient); + } + opensyncNodeMap.put(apId, osNode); + } else { + + osNode = new OpensyncNode(apId, null, customerId, equipmentId); + for (OpensyncWifiAssociatedClients wifiClient : wifiAssociatedClients) { + osNode.updateWifiClients(wifiClient); + } + opensyncNodeMap.put(apId, osNode); + } + + } + } + + @Override + public void awlanNodeDbTableUpdate(OpensyncAWLANNode opensyncAPState, String apId) { + + OvsdbSession session = ovsdbSessionMapInterface.getSession(apId); + int customerId = session.getCustomerId(); + long equipmentId = session.getEquipmentId(); + + if (customerId > 0) { + opensyncCloudGatewayController.updateActiveCustomer(customerId); + } else { + LOG.debug("Cannot get customerId {} for session {}", customerId); + return; + } + + if (equipmentId < 1) { + LOG.debug("Cannot get equipmentId {} for session {}", equipmentId); + return; + } + if (opensyncAPState == null || apId == null) + return; + + OpensyncNode osNode = null; + synchronized (opensyncNodeMap) { + if (opensyncNodeMap.containsKey(apId)) { + osNode = opensyncNodeMap.get(apId); + osNode.updateAWLANNode(opensyncAPState); + opensyncNodeMap.put(apId, osNode); + LOG.debug("Updated AWLAN_Node to map {}", osNode.toPrettyString()); + + } else { + + osNode = new OpensyncNode(apId, opensyncAPState, customerId, equipmentId); + opensyncNodeMap.put(apId, osNode); + } + + } + + } + + @Override + public void wifiVIFStateDbTableDelete(List vifStateTables, String apId) { + OvsdbSession session = ovsdbSessionMapInterface.getSession(apId); + int customerId = session.getCustomerId(); + long equipmentId = session.getEquipmentId(); + + if (customerId > 0) { + opensyncCloudGatewayController.updateActiveCustomer(customerId); + } else { + LOG.debug("Cannot get customerId {} for session {}", customerId); + return; + } + + if (equipmentId < 1) { + LOG.debug("Cannot get equipmentId {} for session {}", equipmentId); + return; + } + + synchronized (opensyncNodeMap) { + + if (opensyncNodeMap.containsKey(apId)) { + OpensyncNode osNode = opensyncNodeMap.get(apId); + + for (OpensyncAPVIFState vifToDelete : vifStateTables) { + if (osNode.deleteVif(vifToDelete)) { + opensyncNodeMap.put(apId, osNode); + LOG.debug("Deleted VIF for interface {} ssid {} from AP {}", vifToDelete.getIfName(), + vifToDelete.getSsid(), apId); + } else { + LOG.debug("Cannot find VIF for interface {} ssid {} marked for deletion under AP {}", + vifToDelete.getIfName(), vifToDelete.getSsid(), apId); + } + } + + } else { + LOG.debug("AP {} is not present in cache, cannot delete VIFs", apId); + } + } + } + + @Override + public void wifiAssociatedClientsDbTableDelete(String deletedClientMac, String apId) { + + OvsdbSession session = ovsdbSessionMapInterface.getSession(apId); + int customerId = session.getCustomerId(); + long equipmentId = session.getEquipmentId(); + + if (customerId > 0) { + opensyncCloudGatewayController.updateActiveCustomer(customerId); + } else { + LOG.debug("Cannot get customerId {} for session {}", customerId); + return; + } + + if (equipmentId < 1) { + LOG.debug("Cannot get equipmentId {} for session {}", equipmentId); + return; + } + + synchronized (opensyncNodeMap) { + if (opensyncNodeMap.containsKey(apId)) { + OpensyncNode osNode = opensyncNodeMap.get(apId); + if (osNode.deleteWifiClient(deletedClientMac)) { + opensyncNodeMap.put(apId, osNode); + LOG.debug("Deleted WifiClient {} from AP {}", deletedClientMac, apId); + } else { + LOG.debug("Cannot find WifiClient {} marked for deletion under AP {}", deletedClientMac, apId); + } + } else { + LOG.debug("AP {} is not present in cache, cannot delete WifiClient {}", apId, deletedClientMac); + } + } + + try { +// LOG.debug("Deleted AssociatedClient {}", +// clientServiceInterface.delete(new MacAddress(deletedClientMac).getAddressAsLong())); + } catch (Exception e) { + LOG.error("Error deleting AssociatedClient {}", deletedClientMac, e); + } + + } + +} diff --git a/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/OpensyncNode.java b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/OpensyncNode.java new file mode 100644 index 0000000..212db0a --- /dev/null +++ b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/OpensyncNode.java @@ -0,0 +1,283 @@ +package com.telecominfraproject.wlan.opensync.external.integration; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.telecominfraproject.wlan.core.model.equipment.MacAddress; +import com.telecominfraproject.wlan.core.model.equipment.RadioType; +import com.telecominfraproject.wlan.core.model.json.BaseJsonModel; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPInetState; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPRadioState; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPVIFState; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAWLANNode; +import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncWifiAssociatedClients; + + +public class OpensyncNode extends BaseJsonModel { + private static final Logger LOG = LoggerFactory.getLogger(OpensyncNode.class); + + private static final long serialVersionUID = 8388356663505464850L; + + private String apId; + private OpensyncAWLANNode awlanNode = null; + private List radioStates = null; + private List inetStates = null; + private List vifStates = null; + private List wifiClients = null; + private int customerId; + private long equipmentId; + + public OpensyncNode(String apId, OpensyncAWLANNode awlanNode, int customerId, long equipmentId) { + this.apId = apId; + this.awlanNode = awlanNode; + this.equipmentId = equipmentId; + this.customerId = customerId; + radioStates = new ArrayList(); + inetStates = new ArrayList(); + vifStates = new ArrayList(); + wifiClients = new ArrayList(); + } + + public static long getSerialversionuid() { + return serialVersionUID; + } + + public String getApId() { + return apId; + } + + public int getCustomerId() { + return customerId; + } + + public long getEquipmentId() { + return equipmentId; + } + + public void updateAWLANNode(OpensyncAWLANNode awlanNode) { + this.awlanNode = awlanNode; + } + + public OpensyncAWLANNode getAWLANNode() { + return awlanNode; + } + + public void updateRadioState(OpensyncAPRadioState radioState) { + + LOG.trace("Received Radio {}", radioState.toPrettyString()); + + if (radioState.getMac() == null || radioState.getIfName() == null || radioState.getFreqBand() == null) + return; // not ready + if (radioStates.isEmpty()) { + radioStates.add(radioState); + } else { + for (OpensyncAPRadioState radio : radioStates) { + if (radioState.getMac().equals(radio.getMac()) && radio.getFreqBand().equals(radioState.getFreqBand()) + && radioState.getIfName().equals(radio.getIfName())) { + int index = radioStates.indexOf(radio); + radioStates.remove(index); + radioStates.add(radioState); + return; + } + } + // no matching radio present in table + radioStates.add(radioState); + } + + } + + public void updateVifState(OpensyncAPVIFState vifState) { + + LOG.trace("Received {}", vifState.toPrettyString()); + if (vifState.getChannel() == -1 || vifState.getSsid() == null || vifState.getIfName() == null) + return; // not ready + + if (vifStates.isEmpty()) { + vifStates.add(vifState); + } else { + for (OpensyncAPVIFState vif : vifStates) { + if (vifState.getSsid().equals(vif.getSsid()) && vifState.getIfName().equals(vif.getIfName())) { + int index = vifStates.indexOf(vif); + vifStates.remove(index); + vifStates.add(vifState); + return; + } + } + // no matching radio present in table + vifStates.add(vifState); + } + + } + + public void updateInetState(OpensyncAPInetState inetState) { + + if (inetState.getHwAddr() == null || inetState.getIfName() == null) + return; + + if (inetStates.isEmpty()) { + inetStates.add(inetState); + } else { + for (OpensyncAPInetState inet : inetStates) { + if ((inetState.getHwAddr() != null && inet.getHwAddr().equals(inetState.getHwAddr())) + || inet.getIfName().equals(inetState.getIfName())) { + int index = inetStates.indexOf(inet); + inetStates.set(index, inetState); + return; + } + } + // no matching radio present in table + inetStates.add(inetState); + + } + } + + public void updateWifiClients(OpensyncWifiAssociatedClients wifiClient) { + + if (wifiClient.getMac() == null || wifiClient.getState() == null) + return; + + if (wifiClients.isEmpty()) { + wifiClients.add(wifiClient); + } else { + for (OpensyncWifiAssociatedClients client : wifiClients) { + + if (wifiClient.getMac().equals(client.getMac())) { + + int index = wifiClients.indexOf(client); + wifiClients.remove(index); + wifiClients.add(wifiClient); + return; + + } + + } + + wifiClients.add(wifiClient); + + } + } + + public OpensyncAWLANNode getAwlanNode() { + return awlanNode; + } + + public List getRadioStates() { + return radioStates; + } + + public List getInetStates() { + return inetStates; + } + + public List getVifStates() { + return vifStates; + } + + public List getWifiClients() { + return wifiClients; + } + + public OpensyncAPRadioState getRadioForMac(MacAddress mac) { + OpensyncAPRadioState ret = null; + + for (OpensyncAPRadioState radio : radioStates) { + if (radio.getMac().equals(mac.toString())) { + ret = radio; + break; + } + } + + return ret; + } + + public OpensyncAPRadioState getRadioForChannel(int channel) { + OpensyncAPRadioState ret = null; + + for (OpensyncAPRadioState radio : radioStates) { + if (radio.getChannel() == channel) { + ret = radio; + break; + } + } + + return ret; + } + + public OpensyncAPRadioState getRadioForBand(String freq_band) { + OpensyncAPRadioState ret = null; + + for (OpensyncAPRadioState radio : radioStates) { + if (radio.getFreqBand().equals("5GL") && freq_band.equals(RadioType.is5GHz.toString())) { + ret = radio; + break; + } else if (radio.getFreqBand().equals("2.4G") && freq_band.equals(RadioType.is2dot4GHz.toString())) { + ret = radio; + break; + } + } + return ret; + } + + public OpensyncAPVIFState getVIFForChannel(int channel) { + OpensyncAPVIFState ret = null; + + for (OpensyncAPVIFState vif : vifStates) { + if (vif.getChannel() == channel) { + ret = vif; + break; + } + } + + return ret; + } + + public List getVIFsForSSID(String ssid) { + List ret = new ArrayList(); + + for (OpensyncAPVIFState vif : vifStates) { + if (vif.getSsid().equals(ssid)) { + ret.add(vif); + } + } + + return ret; + } + + public OpensyncAPInetState getInetForMac(MacAddress mac) { + OpensyncAPInetState ret = null; + for (OpensyncAPInetState inet : inetStates) { + if (inet.getHwAddr().equals(mac.toString())) { + ret = inet; + break; + } + } + + return ret; + } + + public boolean deleteWifiClient(String deletedClientMacAddress) { + for (OpensyncWifiAssociatedClients client : wifiClients) { + if (client.getMac().equals(deletedClientMacAddress)) { + wifiClients.remove(client); + return true; + } + } + // could not find this client + return false; + } + + public boolean deleteVif(OpensyncAPVIFState toBeDeleted) { + for (OpensyncAPVIFState vif : vifStates) { + if (vif.getSsid().equals(toBeDeleted.getSsid()) && vif.getIfName().equals(toBeDeleted.getIfName())) { + vifStates.remove(vif); + return true; + } + } + // could not find this vif + return false; + } + +} diff --git a/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudRestTemplatePostConfiguration.java b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudRestTemplatePostConfiguration.java new file mode 100644 index 0000000..2e47e17 --- /dev/null +++ b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudRestTemplatePostConfiguration.java @@ -0,0 +1,55 @@ +package com.telecominfraproject.wlan.opensync.external.integration.client; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.client.AsyncRestTemplate; +import org.springframework.web.client.RestTemplate; + +import com.telecominfraproject.wlan.core.model.json.BaseJsonModel; + +/** + * @author dtop + * Configure rest client to understand KDC classes that are children of KDC BaseJsonModel + */ +@Configuration +@ConditionalOnClass(RestTemplate.class) +public class OpensyncCloudRestTemplatePostConfiguration { + + private static final Logger LOG = LoggerFactory + .getLogger(OpensyncCloudRestTemplatePostConfiguration.class); + + + public OpensyncCloudRestTemplatePostConfiguration(@Autowired(required=false) AsyncRestTemplate asyncRestTemplate, @Autowired RestTemplate restTemplate) { + registerModulesWithObjectMappers(restTemplate); + if(asyncRestTemplate!=null) { + registerModulesWithObjectMappers(asyncRestTemplate); + } + } + + public static void registerModulesWithObjectMappers(AsyncRestTemplate restT) { + //this is needed so that rest client can produce and consume JSON objects with (and without) _type property + for(@SuppressWarnings("rawtypes") HttpMessageConverter c: restT.getMessageConverters()){ + if(c instanceof MappingJackson2HttpMessageConverter){ + LOG.info("Configuring ObjectMapper on AsyncRestTemplate"); + BaseJsonModel.registerAllSubtypes(((MappingJackson2HttpMessageConverter)c).getObjectMapper()); + } + } + } + + public static void registerModulesWithObjectMappers(RestTemplate restT) { + //this is needed so that rest client can produce and consume JSON objects with (and without) _type property + for(@SuppressWarnings("rawtypes") HttpMessageConverter c: restT.getMessageConverters()){ + if(c instanceof MappingJackson2HttpMessageConverter){ + LOG.info("Configuring ObjectMapper on RestTemplate"); + BaseJsonModel.registerAllSubtypes(((MappingJackson2HttpMessageConverter)c).getObjectMapper()); + } + } + } + + +} diff --git a/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudWebConfig.java b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudWebConfig.java new file mode 100644 index 0000000..97bcaff --- /dev/null +++ b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudWebConfig.java @@ -0,0 +1,50 @@ +package com.telecominfraproject.wlan.opensync.external.integration.client; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +import com.telecominfraproject.wlan.core.model.json.BaseJsonModel; + + +/** + * @author dtoptygin + * + */ +@Configuration +//@EnableWebMvc - DTOP: do not use this, it will break mapping for index.html file +// see http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-auto-configuration +public class OpensyncCloudWebConfig extends WebMvcConfigurerAdapter { + + private static final Logger LOG = LoggerFactory.getLogger(OpensyncCloudWebConfig.class); + + @Override + public void extendMessageConverters(List> converters) { + //this is needed so that servlets can consume and produce JSON objects with (and without) _type parameters + LOG.info("extending MessageConverters to understand KDC BaseJsonModel and its descendants"); + for(HttpMessageConverter c: converters){ + if(c instanceof MappingJackson2HttpMessageConverter){ + BaseJsonModel.registerAllSubtypes(((MappingJackson2HttpMessageConverter)c).getObjectMapper()); + } + } + } + + @Override + public void addFormatters(FormatterRegistry registry) { + // This is needed so that @RequestParam annotations in the servlet + // methods can be used with BaseJsonModel and its descendants and its + // collections. + + //Use GenericlConverter here, simple one does not work + LOG.info("Adding custom converters to process KDC BaseJsonModel and its descendants"); + + registry.addConverter(new OpensyncCloudWebGenericConverter()); + } + +} diff --git a/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudWebGenericConverter.java b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudWebGenericConverter.java new file mode 100644 index 0000000..b54ab0a --- /dev/null +++ b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/client/OpensyncCloudWebGenericConverter.java @@ -0,0 +1,207 @@ +package com.telecominfraproject.wlan.opensync.external.integration.client; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.converter.GenericConverter; + +import com.telecominfraproject.wlan.core.model.json.BaseJsonModel; + +/** + * @author dtoptygin + * + */ +public class OpensyncCloudWebGenericConverter implements GenericConverter { + private static final Logger LOG = LoggerFactory.getLogger(OpensyncCloudWebGenericConverter.class); + private Set convertiblePairs; + + /** + * Format the typeDescriptor for logging + * @param typeDescriptor + * @return + */ + public static String getDataType(TypeDescriptor typeDescriptor) { + if (typeDescriptor == null) { + return ""; + } + if (typeDescriptor.isCollection()) { + return typeDescriptor.getName() + "<" + getDataType(typeDescriptor.getElementTypeDescriptor()) + ">"; + } + if (typeDescriptor.isArray()) { + return getDataType(typeDescriptor.getElementTypeDescriptor()) + "[]"; + } + return typeDescriptor.getName(); + } + + /** + * Constructor + */ + public OpensyncCloudWebGenericConverter() { + LOG.info("Registering Object Converter for the KDC models"); + convertiblePairs = new HashSet<>(); + convertiblePairs.add(new ConvertiblePair(String.class, com.telecominfraproject.wlan.core.model.json.BaseJsonModel.class)); + convertiblePairs.add(new ConvertiblePair(String.class, List.class)); + convertiblePairs.add(new ConvertiblePair(String.class, Set.class)); + } + + @Override + public Set getConvertibleTypes() { + return convertiblePairs; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + // dtop: this is ugly and needs to be generalized, but it works for + // List/Set of Integer/Long/BaseJsonModel/String + if (LOG.isTraceEnabled()) { + LOG.trace("Attempting to convert '{}' from {} to {}", source, getDataType(sourceType), + getDataType(targetType)); + } + + if (targetType.isAssignableTo(TypeDescriptor.valueOf(String.class)) || targetType + .isAssignableTo(TypeDescriptor.collection(Collection.class, TypeDescriptor.valueOf(String.class)))) { + LOG.trace("Proceeding with conversion of String ... "); + Object ret = null; + if (targetType.isCollection()) { + if (targetType.getName().equals(List.class.getName())) { + ret = new ArrayList(); + } else if (targetType.getName().equals(Set.class.getName())) { + ret = new HashSet(); + } else { + throw new IllegalStateException("Unsupported collection type " + targetType.getName()); + } + + if (sourceType.isArray() || sourceType.isCollection()) { + for (Object obj : (Iterable) source) { + ((Collection) ret).add((String) obj); + } + } else { + for (String str : ((String) source).split(",")) { + str = str.trim(); + if (str.isEmpty()) { + continue; + } + ((Collection) ret).add(str); + } + } + } + + return ret; + } + + if (targetType.isAssignableTo(TypeDescriptor.valueOf(Integer.class)) || targetType + .isAssignableTo(TypeDescriptor.collection(Collection.class, TypeDescriptor.valueOf(Integer.class)))) { + LOG.trace("Proceeding with conversion of Integer ... "); + Object ret = null; + if (targetType.isCollection()) { + if (targetType.getName().equals(List.class.getName())) { + ret = new ArrayList(); + } else if (targetType.getName().equals(Set.class.getName())) { + ret = new HashSet(); + } else { + throw new IllegalStateException("Unsupported collection type " + targetType.getName()); + } + + if (sourceType.isArray() || sourceType.isCollection()) { + for (Object obj : (Iterable) source) { + ((Collection) ret).add(Integer.parseInt((String) obj)); + } + } else { + for (String str : ((String) source).split(",")) { + str = str.trim(); + if (str.isEmpty()) { + continue; + } + ((Collection) ret).add(Integer.parseInt(str)); + } + } + } + + return ret; + } + + if (targetType.isAssignableTo(TypeDescriptor.valueOf(Long.class)) || targetType + .isAssignableTo(TypeDescriptor.collection(Collection.class, TypeDescriptor.valueOf(Long.class)))) { + LOG.trace("Proceeding with conversion of Long ... "); + Object ret = null; + if (targetType.isCollection()) { + if (targetType.getName().equals(List.class.getName())) { + ret = new ArrayList(); + } else if (targetType.getName().equals(Set.class.getName())) { + ret = new HashSet(); + } else { + throw new IllegalStateException("Unsupported collection type " + targetType.getName()); + } + + if (sourceType.isArray() || sourceType.isCollection()) { + for (Object obj : (Iterable) source) { + ((Collection) ret).add(Long.parseLong((String) obj)); + } + } else { + for (String str : ((String) source).split(",")) { + str = str.trim(); + if (str.isEmpty()) { + continue; + } + ((Collection) ret).add(Long.parseLong(str)); + } + } + } + + return ret; + } + + if (!targetType.isAssignableTo(TypeDescriptor.valueOf(BaseJsonModel.class)) && !targetType.isAssignableTo( + TypeDescriptor.collection(Collection.class, TypeDescriptor.valueOf(BaseJsonModel.class)))) { + throw new IllegalStateException( + "WC GenericConverter only handles BaseJsonModel and its collections and its descendants, not " + + targetType.getName()); + } + + LOG.trace("Proceeding with conversion of BaseJsonModel ... "); + + LOG.debug("Attempting to convert {} from {} to {}", source, sourceType.getName(), targetType.getName()); + + Object ret; + if (targetType.isCollection()) { + if (targetType.getName().equals(List.class.getName())) { + ret = new ArrayList(); + } else if (targetType.getName().equals(Set.class.getName())) { + ret = new HashSet(); + } else { + throw new IllegalStateException("Unsupported collection type " + targetType.getName()); + } + + if (sourceType.isArray() || sourceType.isCollection()) { + if (source != null) { + for (Object obj : (Iterable) source) { + ((Collection) ret).add(BaseJsonModel.fromString((String) obj, BaseJsonModel.class)); + } + } + } else { + if (source != null && !((String) source).isEmpty()) { + ((Collection) ret).addAll(BaseJsonModel.listFromString((String) source, BaseJsonModel.class)); + } + } + } else { + if (source != null && ((String) source).startsWith("[{")) { + // DT: should not ever get here + ret = BaseJsonModel.listFromString((String) source, BaseJsonModel.class); + } else { + if (source == null || "".equals(source)) { + return null; + } + ret = BaseJsonModel.fromString((String) source, BaseJsonModel.class); + } + } + + return ret; + } +} diff --git a/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncCloudGatewayController.java b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncCloudGatewayController.java new file mode 100644 index 0000000..ddffeed --- /dev/null +++ b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncCloudGatewayController.java @@ -0,0 +1,130 @@ +package com.telecominfraproject.wlan.opensync.external.integration.controller; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.BiFunction; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.bind.annotation.RestController; + +import com.telecominfraproject.wlan.core.model.service.ServiceInstanceInformation; +import com.telecominfraproject.wlan.core.server.container.ConnectorProperties; +import com.telecominfraproject.wlan.opensync.external.integration.ConnectusOvsdbClientInterface; +import com.telecominfraproject.wlan.opensync.external.integration.OvsdbSessionMapInterface; + +/** + * Opensync Gateway Controller - integration code for cloud deployment + * + * @author yongli + * @author dtop + * + */ +@RestController +@EnableScheduling +public class OpensyncCloudGatewayController { + + @Autowired + ConnectorProperties connectorProperties; + + @Autowired + private ServiceInstanceInformation serviceInstanceInfo; + + @Autowired + private ConnectusOvsdbClientInterface connectusOvsdbClient; + + /** + * Flag indicates if this gateway has registered with routing service + */ + private boolean registeredWithRoutingService = false; + + private long registeredGwId = -1; + + /** + * Lock used to protected {@link #activeCustomerLock} + */ + private final ReadWriteLock activeCustomerLock = new ReentrantReadWriteLock(); + private final Lock activeCustomerReadLock = activeCustomerLock.readLock(); + private final Lock activeCustomerWriteLock = activeCustomerLock.writeLock(); + + @Autowired + private OvsdbSessionMapInterface ovsdbSessionMapInterface; + + /** + * Map + */ + private ConcurrentMap activeCustomerMap = new ConcurrentHashMap<>(); + + /** + * latestTimetamp used when updating {@link #activeCustomerMap} + */ + private final BiFunction latestTimestamp = new BiFunction() { + @Override + public Long apply(Long oldValue, Long newValue) { + if (newValue.compareTo(oldValue) > 0) { + return newValue; + } + return oldValue; + } + }; + + /** + * Use connection internal hostname as the gateway name + * + * @return + */ + private String getGatewayName() { + return connectorProperties.getInternalHostName(); + } + + private static final Logger LOG = LoggerFactory.getLogger(OpensyncCloudGatewayController.class); + + public void registerWithRoutingService() { + synchronized (this) { + if (registeredWithRoutingService) { + return; + } + +// CustomerEquipmentGwRecord gwRecord = new CustomerEquipmentGwRecord(); +// gwRecord.setDeploymentId(getDeploymentId()); +// +// // Internal facing service +// gwRecord.setGatewayId(getGatewayName()); +// +// gwRecord.setIpAddr(connectorProperties.getInternalIpAddress().getHostAddress()); +// gwRecord.setPort(connectorProperties.getInternalPort()); + try { +// CustomerEquipmentGwRecord result = this.eqRoutingSvc.registerGateway(gwRecord); +// this.registeredGwId = result.getId(); +// LOG.info("Successfully registered (name={}, id={}) with Routing Service", result.getGatewayId(), +// registeredGwId); + registeredWithRoutingService = true; + } catch (RuntimeException e) { + // failed + LOG.error("Failed to register Customer Equipment Gateway (name={}) with Routing Service : {}", + getGatewayName(), e.getLocalizedMessage()); + } + } + } + + public void deregisterFromRoutingService() { + // TODO Auto-generated method stub + + } + + public void updateActiveCustomer(int customerId) { + this.activeCustomerReadLock.lock(); + try { + this.activeCustomerMap.merge(customerId, System.currentTimeMillis(), latestTimestamp); + } finally { + this.activeCustomerReadLock.unlock(); + } + + } + +} diff --git a/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayControllerStartListener.java b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayControllerStartListener.java new file mode 100644 index 0000000..bc76085 --- /dev/null +++ b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayControllerStartListener.java @@ -0,0 +1,29 @@ +package com.telecominfraproject.wlan.opensync.external.integration.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextStartedEvent; + +/** + * Listen for context started event so that we are register with routing service + * + * @author yongli + * + */ +public class OpensyncGatewayControllerStartListener implements ApplicationListener { + + private static final Logger LOG = LoggerFactory.getLogger(OpensyncGatewayControllerStartListener.class); + + OpensyncCloudGatewayController controller; + + public OpensyncGatewayControllerStartListener(OpensyncCloudGatewayController controller) { + this.controller = controller; + } + + @Override + public void onApplicationEvent(ContextStartedEvent event) { + LOG.debug("Processing ContextStartedEvent event"); + controller.registerWithRoutingService(); + } +} diff --git a/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayControllerStopListener.java b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayControllerStopListener.java new file mode 100644 index 0000000..cd100e1 --- /dev/null +++ b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayControllerStopListener.java @@ -0,0 +1,29 @@ +package com.telecominfraproject.wlan.opensync.external.integration.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextClosedEvent; + +/** + * Register for stop event so that we can de-register from routing service + * + * @author yongli + * + */ +public class OpensyncGatewayControllerStopListener implements ApplicationListener { + OpensyncCloudGatewayController controller; + + private static final Logger LOG = LoggerFactory.getLogger(OpensyncGatewayControllerStopListener.class); + + public OpensyncGatewayControllerStopListener(OpensyncCloudGatewayController controller) { + this.controller = controller; + } + + @Override + public void onApplicationEvent(ContextClosedEvent event) { + LOG.debug("Processing ContextClosedEvent event"); + controller.deregisterFromRoutingService(); + } + +} diff --git a/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayListenerConfiguration.java b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayListenerConfiguration.java new file mode 100644 index 0000000..e4767a0 --- /dev/null +++ b/opensync-ext-cloud/src/main/java/com/telecominfraproject/wlan/opensync/external/integration/controller/OpensyncGatewayListenerConfiguration.java @@ -0,0 +1,29 @@ +package com.telecominfraproject.wlan.opensync.external.integration.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Bean; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.ContextStartedEvent; +import org.springframework.stereotype.Component; + +@Component +public class OpensyncGatewayListenerConfiguration { + @Autowired + OpensyncCloudGatewayController controller; + private static final Logger LOG = LoggerFactory.getLogger(OpensyncGatewayControllerStartListener.class); + + @Bean + public ApplicationListener myStopEventListner() { + LOG.debug("Creating stop event listener"); + return new OpensyncGatewayControllerStopListener(controller); + } + + @Bean + public ApplicationListener myStartedEventListener() { + LOG.debug("Creating start event listener"); + return new OpensyncGatewayControllerStartListener(controller); + } +} diff --git a/opensync-ext-cloud/src/main/resources/config_2_ssids.json b/opensync-ext-cloud/src/main/resources/config_2_ssids.json new file mode 100644 index 0000000..91b4ffb --- /dev/null +++ b/opensync-ext-cloud/src/main/resources/config_2_ssids.json @@ -0,0 +1,27 @@ +{ + "model_type" : "OpensyncAPConfig", + "radioConfig" : { + "model_type" : "OpensyncAPRadioConfig", + "country" : "CA", + "radioChannel24G" : 1, + "radioChannel5LG" : 44, + "radioChannel5HG" : 108 + }, + "ssidConfigs" : [ { + "model_type" : "OpensyncAPSsidConfig", + "radioType" : "is2dot4GHz", + "ssid" : "Connectus-local", + "encryption" : "WPA-PSK", + "key" : "12345678", + "mode" : "2", + "broadcast" : true + }, { + "model_type" : "OpensyncAPSsidConfig", + "radioType" : "is5GHz", + "ssid" : "Connectus-local-5", + "encryption" : "WPA-PSK", + "key" : "12345678", + "mode" : "2", + "broadcast" : true + } ] +} diff --git a/opensync-gateway-build/pom.xml b/opensync-gateway-build/pom.xml index 35de47d..8a34258 100644 --- a/opensync-gateway-build/pom.xml +++ b/opensync-gateway-build/pom.xml @@ -21,8 +21,10 @@ ../opensync-ext-interface ../opensync-ext-static + ../opensync-ext-cloud ../opensync-gateway ../opensync-gateway-static-process + ../opensync-gateway-cloud-process diff --git a/opensync-gateway-cloud-docker/pom.xml b/opensync-gateway-cloud-docker/pom.xml new file mode 100644 index 0000000..704de74 --- /dev/null +++ b/opensync-gateway-cloud-docker/pom.xml @@ -0,0 +1,115 @@ + + 4.0.0 + + com.telecominfraproject.wlan + tip-wlan-cloud-root-pom + 0.0.1-SNAPSHOT + ../../wlan-cloud-root + + opensync-gateway-cloud-docker + pom + opensync-gateway-cloud-docker + Docker definition for opensync gateway that uses cloud configuration + + + 0.28.0 + tip-tip-wlan-cloud-docker-repo.jfrog.io + + + + + com.telecominfraproject.wlan + opensync-gateway-cloud-process + ${tip-wlan-cloud.release.version} + + + + + + + + io.fabric8 + docker-maven-plugin + ${docker.fabric.version} + + true + 1.23 + + + opensync-gateway:${project.version} + + @ + try + ${project.basedir}/src/main/docker + Dockerfile + + + + + + com.telecominfraproject.wlan:opensync-gateway-cloud-process:jar + + false + app.jar + + + + + + + + opensync-gateway-and-mqtt:${project.version} + + @ + try + ${project.basedir}/src/main/docker-opensync-gateway-and-mqtt + Dockerfile + + + + + + com.telecominfraproject.wlan:opensync-gateway-cloud-process:jar + + false + app.jar + + + + + + + + + + + clean-images + pre-clean + + remove + + + true + + + + generate-images + package + + build + + + + push-images + deploy + + push + + + + + + + + + diff --git a/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/Dockerfile b/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/Dockerfile new file mode 100644 index 0000000..258678d --- /dev/null +++ b/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/Dockerfile @@ -0,0 +1,33 @@ +FROM adoptopenjdk/openjdk13:alpine-jre + +LABEL maintainer="ConnectUs.ai as part of the Telecom Infrastructure Project" +LABEL version="1.0" +LABEL description="This image runs the mqtt broker (mosquitto) and \ +an OpenSync gateway." + +# Update the package list and upgrade installed packages +RUN apk update && apk upgrade +RUN mkdir -p /opt/tip-wlan/certs +VOLUME ["/opt/tip-wlan/certs"] + +# Configure mqtt broker +RUN apk add mosquitto +RUN mkdir -p /mosquitto/data /mosquitto/log +COPY app/mqtt/mosquitto.conf /etc/mosquitto/mosquitto.conf +VOLUME ["/mosquitto/data", "/mosquitto/log"] + + +# Configure OpenSync Gateway +RUN mkdir -p /app/logs /app/opensync /app/config +COPY maven/app.jar /app +COPY app/opensync/logback.xml /app/opensync/logback.xml +COPY app/run.sh /app +VOLUME ["/app/logs", "/app/config"] + +RUN chmod +x /app/run.sh + +EXPOSE 1883 6640 6643 4043 + +WORKDIR /app +ENTRYPOINT ["/app/run.sh"] +CMD [""] diff --git a/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/mqtt/mosquitto.conf b/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/mqtt/mosquitto.conf new file mode 100644 index 0000000..8682fc8 --- /dev/null +++ b/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/mqtt/mosquitto.conf @@ -0,0 +1,18 @@ +cafile /opt/tip-wlan/certs/cacert.pem +certfile /opt/tip-wlan/certs/mqttservercert.pem +keyfile /opt/tip-wlan/certs/mqttserverkey_dec.pem +require_certificate true +use_identity_as_username true +allow_anonymous false +allow_duplicate_messages true +autosave_interval 900 +log_dest file /mosquitto/log/mosquitto.log +max_queued_bytes 0 +max_queued_messages 0 +message_size_limit 0 +persistence true +persistence_file mosquitto.db +persistence_location /mosquitto/data/ +pid_file /mosquitto/mosquitto.pid +port 1883 + diff --git a/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/opensync/logback.xml b/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/opensync/logback.xml new file mode 100644 index 0000000..67c0aee --- /dev/null +++ b/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/opensync/logback.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + %d{yyyy-MM-DD HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + /app/logs/mqttData.log + true + + %date %msg%n + + + /app/logs/mqttData.%i.log.gz + 1 + 3 + + + 20MB + + + + + + /app/logs/opensyncgw.log + true + + %date %level [%thread] %logger{36} [%file:%line] %msg%n + + + /app/logs/opensyncgw.%i.log.gz + 1 + 3 + + + 20MB + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/run.sh b/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/run.sh new file mode 100755 index 0000000..bed8f1a --- /dev/null +++ b/opensync-gateway-cloud-docker/src/main/docker-opensync-gateway-and-mqtt/app/run.sh @@ -0,0 +1,126 @@ +#!/bin/sh + +# Prepare the hosts file - do it only if does not have required entries +n1=`grep opensync-mqtt-broker /etc/hosts | wc -l` + +if [[ $n1 -eq 0 ]] +then + echo Adding opensync-mqtt-broker to /etc/hosts + echo "127.0.0.1 opensync-mqtt-broker" >> /etc/hosts +fi + +n2=`grep opensync-wifi-controller /etc/hosts | wc -l` + +if [[ $n2 -eq 0 ]] +then + echo Adding opensync-wifi-controller to /etc/hosts + echo "127.0.0.1 opensync-wifi-controller" >> /etc/hosts +fi + + +echo Starting mosquitto MQTT broker +/usr/sbin/mosquitto -d -c /etc/mosquitto/mosquitto.conf + +# Provide default values for the environment variables +MQTT_CLIENT_KEYSTORE_PASSWORD="${MQTT_CLIENT_KEYSTORE_PASSWORD:=mypassword}" +MQTT_CLIENT_KEYSTORE_FILE="${MQTT_CLIENT_KEYSTORE_FILE:=/opt/tip-wlan/certs/client_keystore.jks}" +MQTT_TRUSTSTORE_FILE="${MQTT_TRUSTSTORE_FILE:=/opt/tip-wlan/certs/truststore.jks}" +MQTT_TRUSTSTORE_PASSWORD="${MQTT_TRUSTSTORE_PASSWORD:=mypassword}" + +OVSDB_SERVER_KEYSTORE_FILE="${OVSDB_SERVER_KEYSTORE_FILE:=/opt/tip-wlan/certs/server.pkcs12}" +OVSDB_SERVER_KEYSTORE_PASSWORD="${OVSDB_SERVER_KEYSTORE_PASSWORD:=mypassword}" +OVSDB_SERVER_TRUSTSTORE_FILE="${OVSDB_SERVER_TRUSTSTORE_FILE:=/opt/tip-wlan/certs/truststore.jks}" +OVSDB_SERVER_TRUSTSTORE_PASSWORD="${OVSDB_SERVER_TRUSTSTORE_PASSWORD:=mypassword}" +OVSDB_CONFIG_FILE="${OVSDB_CONFIG_FILE:=/app/opensync/config_2_ssids.json}" + +echo Reading AP configuration from $OVSDB_CONFIG_FILE + +EXT_CLIENT_KEYSTORE_PASSWORD="${EXT_CLIENT_KEYSTORE_PASSWORD:=mypassword}" +EXT_CLIENT_KEYSTORE_FILE="${EXT_CLIENT_KEYSTORE_FILE:=/opt/tip-wlan/certs/client_keystore.jks}" +EXT_TRUSTSTORE_FILE="${EXT_TRUSTSTORE_FILE:=/opt/tip-wlan/certs/truststore.jks}" +EXT_TRUSTSTORE_PASSWORD="${EXT_TRUSTSTORE_PASSWORD:=mypassword}" + +MQTT_BROKER_HOST="${MQTT_BROKER_HOST:=opensync-mqtt-broker}" +OVSDB_MANAGER_HOST="${OVSDB_MANAGER_HOST:=opensync-wifi-controller}" + +LOGBACK_CONFIG_FILE="${LOGBACK_CONFIG_FILE:=/app/opensync/logback.xml}" + +# Create ssl.properties file +cat > /app/ssl.properties < /app/httpClientConfig.json < /app/opensync-wifi-controller-stdout.out 2>&1 + diff --git a/opensync-gateway-cloud-docker/src/main/docker/Dockerfile b/opensync-gateway-cloud-docker/src/main/docker/Dockerfile new file mode 100644 index 0000000..234ab04 --- /dev/null +++ b/opensync-gateway-cloud-docker/src/main/docker/Dockerfile @@ -0,0 +1,16 @@ +FROM adoptopenjdk/openjdk13:alpine-jre +MAINTAINER ConnectUs + +# Update the package list and upgrade installed packages +RUN apk update && apk upgrade && apk add bash +RUN mkdir /app && mkdir /app/logs && mkdir /app/opensync +RUN mkdir -p /opt/tip-wlan/certs + +COPY maven/app.jar /app +COPY app/opensync/logback.xml /app/opensync/logback.xml +COPY app/run.sh /app + +RUN chmod +x /app/run.sh + +WORKDIR /app +CMD ["/app/run.sh"] \ No newline at end of file diff --git a/opensync-gateway-cloud-docker/src/main/docker/app/opensync/logback.xml b/opensync-gateway-cloud-docker/src/main/docker/app/opensync/logback.xml new file mode 100644 index 0000000..a7ac837 --- /dev/null +++ b/opensync-gateway-cloud-docker/src/main/docker/app/opensync/logback.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + %d{yyyy-MM-DD HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + /app/logs/opensyncgw.log + true + + %date %level [%thread] %logger{36} [%file:%line] %msg%n + + + /app/logs/opensyncgw.%i.log.gz + 1 + 3 + + + 20MB + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opensync-gateway-cloud-docker/src/main/docker/app/run.sh b/opensync-gateway-cloud-docker/src/main/docker/app/run.sh new file mode 100755 index 0000000..e022fbf --- /dev/null +++ b/opensync-gateway-cloud-docker/src/main/docker/app/run.sh @@ -0,0 +1,37 @@ +#!/bin/bash +PROFILES=" -Dspring.profiles.include=mqtt_receiver,ovsdb_redirector,ovsdb_manager" + +SSL_PROPS=" " +SSL_PROPS+=" -Dssl.props=file:/opt/tip-wlan/certs/ssl.properties" +SSL_PROPS+=" -Dtip.wlan.httpClientConfig=file:/opt/tip-wlan/certs/httpClientConfig.json" + +CLIENT_MQTT_SSL_PROPS=" " +CLIENT_MQTT_SSL_PROPS+=" -Djavax.net.ssl.keyStore=/opt/tip-wlan/certs/client_keystore.jks" +CLIENT_MQTT_SSL_PROPS+=" -Djavax.net.ssl.keyStorePassword=mypassword" +CLIENT_MQTT_SSL_PROPS+=" -Djavax.net.ssl.trustStore=/opt/tip-wlan/certs/truststore.jks" +CLIENT_MQTT_SSL_PROPS+=" -Djavax.net.ssl.trustStorePassword=mypassword" +CLIENT_MQTT_SSL_PROPS+=" -Dconnectus.mqttBroker.password=admin" + +OVSDB_PROPS=" " +OVSDB_PROPS+=" -Dconnectus.ovsdb.managerAddr=opensync-controller" +OVSDB_PROPS+=" -Dconnectus.ovsdb.listenPort=6640 " +OVSDB_PROPS+=" -Dconnectus.ovsdb.redirector.listenPort=6643" +OVSDB_PROPS+=" -Dconnectus.ovsdb.timeoutSec=30" +OVSDB_PROPS+=" -Dconnectus.ovsdb.trustStore=/opt/tip-wlan/certs/truststore.jks" +OVSDB_PROPS+=" -Dconnectus.ovsdb.keyStore=/opt/tip-wlan/certs/server.pkcs12" +OVSDB_PROPS+=" -Dconnectus.ovsdb.configFileName=/app/opensync/config_2_ssids.json" + +MQTT_PROPS=" " +MQTT_PROPS+=" -Dconnectus.mqttBroker.address=opensync-wifi-controller-opensync-mqtt-broker" +MQTT_PROPS+=" -Dconnectus.mqttBroker.listenPort=1883" + +LOGGING_PROPS=" -Dlogging.config=file:/app/opensync/logback.xml" + +RESTAPI_PROPS=" " +RESTAPI_PROPS+=" -Dserver.port=443" + +SPRING_EXTRA_PROPS=" --add-opens java.base/java.lang=ALL-UNNAMED" + +export ALL_PROPS="$PROFILES $SSL_PROPS $CLIENT_MQTT_SSL_PROPS $OVSDB_PROPS $MQTT_PROPS $LOGGING_PROPS $RESTAPI_PROPS $SPRING_EXTRA_PROPS" + +java $ALL_PROPS -jar app.jar \ No newline at end of file diff --git a/opensync-gateway-cloud-docker/src/main/docker/app/stdout.out b/opensync-gateway-cloud-docker/src/main/docker/app/stdout.out new file mode 100644 index 0000000..ef3e48a --- /dev/null +++ b/opensync-gateway-cloud-docker/src/main/docker/app/stdout.out @@ -0,0 +1 @@ +sudo: unable to read password: Input/output error diff --git a/opensync-gateway-cloud-process/.gitignore b/opensync-gateway-cloud-process/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/opensync-gateway-cloud-process/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/opensync-gateway-cloud-process/pom.xml b/opensync-gateway-cloud-process/pom.xml new file mode 100644 index 0000000..b00ce9a --- /dev/null +++ b/opensync-gateway-cloud-process/pom.xml @@ -0,0 +1,43 @@ + + 4.0.0 + + com.telecominfraproject.wlan + tip-wlan-cloud-root-pom + 0.0.1-SNAPSHOT + ../../wlan-cloud-root + + opensync-gateway-cloud-process + opensync-gateway-cloud-process + Process definition for opensync gateway that uses cloud configuration + + + com.telecominfraproject.wlan.opensync.integration.OpensyncGatewayCloudProcess + + + + + com.telecominfraproject.wlan + opensync-gateway + ${tip-wlan-cloud.release.version} + + + com.telecominfraproject.wlan + opensync-ext-cloud + ${tip-wlan-cloud.release.version} + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/opensync-gateway-cloud-process/src/main/java/com/telecominfraproject/wlan/opensync/integration/OpenSyncGatewayCloudProcess.java b/opensync-gateway-cloud-process/src/main/java/com/telecominfraproject/wlan/opensync/integration/OpenSyncGatewayCloudProcess.java new file mode 100644 index 0000000..33c31e9 --- /dev/null +++ b/opensync-gateway-cloud-process/src/main/java/com/telecominfraproject/wlan/opensync/integration/OpenSyncGatewayCloudProcess.java @@ -0,0 +1,22 @@ +package com.telecominfraproject.wlan.opensync.integration; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ComponentScan; + +@ComponentScan(basePackages = { "com.telecominfraproject.wlan" }) +@EnableAutoConfiguration +public class OpenSyncGatewayCloudProcess { + + /** + *
{@code java -Dssl.props=file:./ssl.properties -Dlogback.configurationFile=file:./logback.xml -jar ./opensync-experiment-0.0.1-SNAPSHOT.jar} + * + * @param args + */ + public static void main(String[] args) { + ConfigurableApplicationContext applicationContext = SpringApplication.run(OpenSyncGatewayCloudProcess.class, args); + // signal start of the application context + applicationContext.start(); + } +} diff --git a/opensync-gateway-cloud-process/src/main/resources/app/certs/httpClientConfig.json b/opensync-gateway-cloud-process/src/main/resources/app/certs/httpClientConfig.json new file mode 100644 index 0000000..ffb985f --- /dev/null +++ b/opensync-gateway-cloud-process/src/main/resources/app/certs/httpClientConfig.json @@ -0,0 +1,18 @@ +{ +"maxConnectionsTotal":100, +"maxConnectionsPerRoute":10, +"truststoreType":"JKS", +"truststoreProvider":"SUN", +"truststoreFile":"file:/opt/tip-wlan/certs/truststore.jks", +"truststorePass":"mypassword", +"keystoreType":"JKS", +"keystoreProvider":"SUN", +"keystoreFile":"file:/opt/tip-wlan/certs/client_keystore.jks", +"keystorePass":"mypassword", +"keyAlias":"clientqrcode", +"credentialsList":[ + {"host":"localhost","port":-1,"user":"user","password":"password"} + ] + +} + diff --git a/opensync-gateway-cloud-process/src/main/resources/app/certs/ssl.properties b/opensync-gateway-cloud-process/src/main/resources/app/certs/ssl.properties new file mode 100644 index 0000000..9e7c333 --- /dev/null +++ b/opensync-gateway-cloud-process/src/main/resources/app/certs/ssl.properties @@ -0,0 +1,13 @@ +truststorePass=mypassword +truststoreFile=file:/opt/tip-wlan/certs/truststore.jks +truststoreType=JKS +truststoreProvider=SUN + +keyAlias=1 +keystorePass=mypassword +keystoreFile=file:/opt/tip-wlan/certs/server.pkcs12 +keystoreType=pkcs12 +keystoreProvider=SunJSSE + +sslProtocol=TLS + diff --git a/opensync-gateway-cloud-process/src/main/resources/application.properties b/opensync-gateway-cloud-process/src/main/resources/application.properties new file mode 100644 index 0000000..3b8cf64 --- /dev/null +++ b/opensync-gateway-cloud-process/src/main/resources/application.properties @@ -0,0 +1,119 @@ +# see http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#common-application-properties-security for details + +app.name=OpenSyncManager + +# +#Select spring profiles +# +# valid values for security profiles are: no_ssl, use_ssl +# valid values for auth profiles are: no_auth, form_based_auth, http_basic_auth, http_digest_auth, client_certificate_auth +# +# this property can be overridden by application.properties in the following locations: +# classpath root +# current directory +# classpath /config package +# /config subdir of the current directory. +# System property -Dspring.profiles.active=production +# or specified on the command line using the switch --spring.profiles.active=dev,hsqldb +# +# This does not work: spring.profiles.active=${telecominfraproject.core.server.security},${telecominfraproject.core.server.auth},Extra_${app.name} +# Substitution of ${} in application.properties works in general, but not for spring.profiles.active and not for spring.profiles.include properties +# +# *** Do not set spring.profiles.active property in this file, or be prepared for the World of Weird. +#spring.profiles.active=a_1,a_2,integration_test +# Example: with application.properties:spring.profiles.active=a_1,a_2,dev,integration_test and @ActiveProfiles(profiles = "test1") +# active profiles: [profile_it_1, profile_it_2, profile_dev_1, profile_dev_2, p_1, p_2, a_1, a_2, dev, integration_test, test1] +# What happens: +# RealActiveProfiles.addAll(application.properties:spring.profiles.active) +# RealActiveProfiles.addAll(application.properties:spring.profiles.include) +# Find all other files named application-${profileName}.properties based on content of RealActiveProfiles +# All application-${profileName}.properties:spring.profiles.include are read, and for each file: +# RealActiveProfiles.addAll(application-${profileName}.properties:spring.profiles.include) +# Recursively process other files named application-${profileName}.properties based on content of RealActiveProfiles +# +# Note that application-${profileName}.properties:spring.profiles.active values are NOT added to the RealActiveProfiles in this case. +# +# Another Example: with application.properties:spring.profiles.active NOT SET and @ActiveProfiles(profiles = "integration_test") +# active profiles: [profile_it_1, profile_it_2, active_it_1, active_it_2, p_1, p_2, integration_test] +# What happens: +# application.properties:spring.profiles.active is read and not found +# RealActiveProfiles.addAll(application.properties:spring.profiles.include) +# Find all other files named application-${profileName}.properties based on content of RealActiveProfiles +# Found application-integration_test.properties file +# RealActiveProfiles.addAll(application-integration_test.properties:spring.profiles.active) +# RealActiveProfiles.addAll(application-integration_test.properties:spring.profiles.include) +# Find all other files named application-${profileName}.properties based on content of RealActiveProfiles +# All application-${profileName}.properties:spring.profiles.include are read, and for each file: +# RealActiveProfiles.addAll(application-${profileName}.properties:spring.profiles.include) +# Recursively process other files named application-${profileName}.properties based on content of RealActiveProfiles +# +# Note that only application-integration_test.properties:spring.profiles.active is read, +# all other application-${profileName}.properties:spring.profiles.active values +# are NOT added to the RealActiveProfiles in this case. +# +# Summary: +# 1. Only the first available property application*.properties:spring.profiles.active is read and added to RealActiveProfiles +# 2. All properties application*.properties:spring.profiles.include are read, and their values are added to RealActiveProfiles +# 3. Many application*.properties can be read during initialization (i.e. one can include a profile name that is referring to another) +# +# *** +# +# Use spring.profiles.active property for unit/integration tests to select proper application-*.properties file +# - this can be done by placing annotation @ActiveProfiles(profiles = "integration_test") on the test classes +# +# Use spring.profiles.active property for specific deployments - staging/cloud to select proper application-*.properties file +# - this can be done by using SystemProperty -Dspring.profiles.active=cloud +# +# Deployment-specific properties can be configured in other property files, like persistence-${envTarget:dev}.properties +# where value for property envTarget can be set using any mechanism, including placing it in the application-*.properties +# +# +# Use spring.profiles.include property to specify static collection of profiles that are +# always present in this configuration, regardless of spring.profiles.active property +# Note: this property is additive, its value is always added to the list of active profiles +#spring.profiles.include=use_ssl,http_digest_auth,customer-credential-datastore-inmemory +#spring.profiles.include=no_ssl,no_auth +#spring.profiles.include=use_ssl,client_certificate_auth +#spring.profiles.include=use_ssl_with_client_cert_and_basic_auth,client_certificate_and_basic_auth +spring.profiles.include=use_ssl,http_basic_auth,rest-template-single-user-per-service-digest-auth,use_single_ds,opensync_cloud_config + +#used by *-remote client classes when they authenticate their requests +tip.wlan.httpClientConfig=classpath:httpClientConfig.json + +#this user/password is used together with http_digest_auth and http_basic_auth spring profiles +tip.wlan.serviceUser=user +tip.wlan.servicePassword=password + +spring.main.show-banner=false +server.port=9096 + +#this port is used by secondary server connector, it is protected by digest authentication, while primary server.port is protected by client certificate auth +#tip.wlan.secondaryPort=7071 + +#this server only supports REST requests, CSRF would get in the way +tip.wlan.csrf-enabled=false + +tip.wlan.emailVerificationTokenExpiryMs=600 +tip.wlan.passwordResetTokenExpiryMs=3600 + +#properties that configure remote interfaces to communicate with cloud +tip.wlan.cloudEventDispatcherBaseUrl=https://localhost:9031 +tip.wlan.customerServiceBaseUrl=https://localhost:9091 +tip.wlan.locationServiceBaseUrl=https://localhost:9091 +tip.wlan.equipmentServiceBaseUrl=https://localhost:9091 +tip.wlan.profileServiceBaseUrl=https://localhost:9091 + +#server.session-timeout= # session timeout in seconds +#server.tomcat.max-threads = 0 # number of threads in protocol handler + +#server.context-path= # the context path, defaults to '/' +#server.servlet-path= # the servlet path, defaults to '/' +#server.tomcat.access-log-pattern= # log pattern of the access log +#server.tomcat.access-log-enabled=false # is access logging enabled + +# pretty print JSON +spring.jackson.serialization.INDENT_OUTPUT=TRUE +# sort keys +#http.mappers.json-sort-keys=false + +#spring.jmx.enabled=true # Expose MBeans from Spring diff --git a/opensync-gateway-cloud-process/src/main/resources/launchers/OpenSyncProcess (local, wlan cloud certs) - prod wlan_cloud.launch b/opensync-gateway-cloud-process/src/main/resources/launchers/OpenSyncProcess (local, wlan cloud certs) - prod wlan_cloud.launch new file mode 100644 index 0000000..8166883 --- /dev/null +++ b/opensync-gateway-cloud-process/src/main/resources/launchers/OpenSyncProcess (local, wlan cloud certs) - prod wlan_cloud.launch @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opensync-gateway-cloud-process/src/main/resources/logback.xml b/opensync-gateway-cloud-process/src/main/resources/logback.xml new file mode 100644 index 0000000..9373b72 --- /dev/null +++ b/opensync-gateway-cloud-process/src/main/resources/logback.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + %d{yyyy-MM-DD HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opensync-gateway-static-process/src/main/resources/app/certs/httpClientConfig.json b/opensync-gateway-static-process/src/main/resources/app/certs/httpClientConfig.json index ffb985f..4e13f6a 100644 --- a/opensync-gateway-static-process/src/main/resources/app/certs/httpClientConfig.json +++ b/opensync-gateway-static-process/src/main/resources/app/certs/httpClientConfig.json @@ -14,5 +14,4 @@ {"host":"localhost","port":-1,"user":"user","password":"password"} ] -} - +} \ No newline at end of file diff --git a/opensync-gateway/src/main/java/com/telecominfraproject/wlan/opensync/ovsdb/ConnectusOvsdbClient.java b/opensync-gateway/src/main/java/com/telecominfraproject/wlan/opensync/ovsdb/ConnectusOvsdbClient.java index 0b289b7..c1bcd44 100644 --- a/opensync-gateway/src/main/java/com/telecominfraproject/wlan/opensync/ovsdb/ConnectusOvsdbClient.java +++ b/opensync-gateway/src/main/java/com/telecominfraproject/wlan/opensync/ovsdb/ConnectusOvsdbClient.java @@ -151,7 +151,7 @@ public class ConnectusOvsdbClient implements ConnectusOvsdbClientInterface { ovsdbClient.cancelMonitor(OvsdbDao.awlanNodeDbTable + "_" + key); } catch (OvsdbClientException e) { - LOG.warn("Could not cancel Monitor {}", e); + LOG.warn("Could not cancel Monitor {}", e.getMessage()); } extIntegrationInterface.apDisconnected(key);