Implement probe prototype
Change-Id: If30bd80701129d9fa892df0b1d37214a7b6c7a33
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..d621e7f
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,2 @@
+.tox
+venv-service
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7e0d89e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+.noseids
+.vscode
+build
+dist
+.coverage
+coverage.xml
+cover
+.tox
+.DS_Store
+nose2-results.xml
+venv-service
+*.pyc
\ No newline at end of file
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..df6881c
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.opencord.org
+port=29418
+project=cord-workflow-probe.git
+defaultremote=origin
diff --git a/Dockerfile.synchronizer b/Dockerfile.synchronizer
new file mode 100644
index 0000000..f5c2e87
--- /dev/null
+++ b/Dockerfile.synchronizer
@@ -0,0 +1,61 @@
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# docker build -t xosproject/cord-workflow-probe-synchronizer:candidate -f Dockerfile.synchronizer .
+
+# xosproject/cord-workflow-probe-synchronizer
+
+FROM xosproject/alpine-grpc-base:0.9.0
+
+# Install pip packages
+COPY requirements.txt /tmp/requirements.txt
+RUN pip install -r /tmp/requirements.txt \
+ && pip freeze > /var/xos/pip_freeze_cord_workflow_probe_service_`date -u +%Y%m%dT%H%M%S`
+
+# Copy files
+COPY xos/synchronizer /opt/xos/synchronizers/cord-workflow-probe
+COPY VERSION /opt/xos/synchronizers/cord-workflow-probe/
+
+WORKDIR "/opt/xos/synchronizers/cord-workflow-probe"
+
+# Label image
+ARG org_label_schema_schema_version=1.0
+ARG org_label_schema_name=cord-workflow-probe-synchronizer
+ARG org_label_schema_version=unknown
+ARG org_label_schema_vcs_url=unknown
+ARG org_label_schema_vcs_ref=unknown
+ARG org_label_schema_build_date=unknown
+ARG org_opencord_vcs_commit_date=unknown
+ARG org_opencord_component_chameleon_version=unknown
+ARG org_opencord_component_chameleon_vcs_url=unknown
+ARG org_opencord_component_chameleon_vcs_ref=unknown
+ARG org_opencord_component_xos_version=unknown
+ARG org_opencord_component_xos_vcs_url=unknown
+ARG org_opencord_component_xos_vcs_ref=unknown
+
+LABEL org.label-schema.schema-version=$org_label_schema_schema_version \
+ org.label-schema.name=$org_label_schema_name \
+ org.label-schema.version=$org_label_schema_version \
+ org.label-schema.vcs-url=$org_label_schema_vcs_url \
+ org.label-schema.vcs-ref=$org_label_schema_vcs_ref \
+ org.label-schema.build-date=$org_label_schema_build_date \
+ org.opencord.vcs-commit-date=$org_opencord_vcs_commit_date \
+ org.opencord.component.chameleon.version=$org_opencord_component_chameleon_version \
+ org.opencord.component.chameleon.vcs-url=$org_opencord_component_chameleon_vcs_url \
+ org.opencord.component.chameleon.vcs-ref=$org_opencord_component_chameleon_vcs_ref \
+ org.opencord.component.xos.version=$org_opencord_component_xos_version \
+ org.opencord.component.xos.vcs-url=$org_opencord_component_xos_vcs_url \
+ org.opencord.component.xos.vcs-ref=$org_opencord_component_xos_vcs_ref
+
+CMD ["/usr/bin/python", "/opt/xos/synchronizers/cord-workflow-probe/cord-workflow-probe-synchronizer.py"]
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..157939a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,68 @@
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Configure shell
+SHELL = bash -e -o pipefail
+
+# Variables
+VERSION ?= $(shell cp -f ../VERSION . && cat ./VERSION)
+SERVICE_NAME ?= $(notdir $(abspath .))
+SYNCHRONIZER_NAME ?= cord-workflow-probe-synchronizer
+
+## Docker related
+DOCKER_REGISTRY ?=
+DOCKER_REPOSITORY ?=
+DOCKER_BUILD_ARGS ?=
+DOCKER_TAG ?= ${VERSION}
+DOCKER_IMAGENAME := ${DOCKER_REGISTRY}${DOCKER_REPOSITORY}${SYNCHRONIZER_NAME}:${DOCKER_TAG}
+
+## Docker labels. Only set ref and commit date if committed
+DOCKER_LABEL_VCS_URL ?= $(shell git remote get-url $(shell git remote))
+DOCKER_LABEL_VCS_REF ?= $(shell git diff-index --quiet HEAD -- && git rev-parse HEAD || echo "unknown")
+DOCKER_LABEL_COMMIT_DATE ?= $(shell git diff-index --quiet HEAD -- && git show -s --format=%cd --date=iso-strict HEAD || echo "unknown" )
+DOCKER_LABEL_BUILD_DATE ?= $(shell date -u "+%Y-%m-%dT%H:%M:%SZ")
+
+all: test
+
+docker-build:
+ docker build $(DOCKER_BUILD_ARGS) \
+ -t ${DOCKER_IMAGENAME} \
+ --build-arg org_label_schema_version="${VERSION}" \
+ --build-arg org_label_schema_vcs_url="${DOCKER_LABEL_VCS_URL}" \
+ --build-arg org_label_schema_vcs_ref="${DOCKER_LABEL_VCS_REF}" \
+ --build-arg org_label_schema_build_date="${DOCKER_LABEL_BUILD_DATE}" \
+ --build-arg org_opencord_vcs_commit_date="${DOCKER_LABEL_COMMIT_DATE}" \
+ -f Dockerfile.synchronizer .
+
+docker-push:
+ docker push ${DOCKER_IMAGENAME}
+
+test: test-unit
+
+test-unit:
+ tox
+
+venv-service:
+ virtualenv $@;\
+ source ./$@/bin/activate ; set -u ;\
+ pip install -r requirements.txt
+
+clean:
+ find . -name '*.pyc' | xargs rm -f
+ rm -rf \
+ .tox \
+ venv-service \
+ xos/.coverage \
+ xos/coverage.xml \
+ xos/nose2-results.xml
\ No newline at end of file
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..40840e9
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,8 @@
+CORD Workflow Probe
+===================
+
+CORD Workflow Probe detects XOS Events (both bottom-up and top-down events) and pass them to
+CORD Workflow Controller for routing.
+
+CORD Workflow is implemented in XOS Synchronizer.
+
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..6c6aa7c
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.1.0
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..843481f
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,4 @@
+xossynchronizer~=3.2.6
+xosapi~=3.2.6
+xoskafka~=3.2.6
+cord-workflow-controller-client~=0.5.0
\ No newline at end of file
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..bb5d074
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,48 @@
+; Copyright 2019-present Open Networking Foundation
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+; http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+[tox]
+envlist = py27,py35,py36,py37
+skip_missing_interpreters = true
+skipsdist = True
+
+[testenv]
+deps =
+ -r requirements.txt
+ requests_mock
+ nose2
+ flake8
+
+changedir = xos
+commands =
+ nose2 -c ../tox.ini --verbose --junit-xml
+ flake8
+
+[flake8]
+max-line-length = 119
+exclude =
+ .tox
+
+[unittest]
+plugins = nose2.plugins.junitxml
+
+[junit-xml]
+path = nose2-results.xml
+
+[coverage]
+always-on = True
+omit = .tox
+coverage-report =
+ term
+ xml
\ No newline at end of file
diff --git a/xos/synchronizer/__init__.py b/xos/synchronizer/__init__.py
new file mode 100644
index 0000000..19d1424
--- /dev/null
+++ b/xos/synchronizer/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/xos/synchronizer/config.yaml b/xos/synchronizer/config.yaml
new file mode 100644
index 0000000..4fd1440
--- /dev/null
+++ b/xos/synchronizer/config.yaml
@@ -0,0 +1,40 @@
+
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+name: cord-workflow-probe
+core_version: ">=2.2.1"
+required_models:
+ - RCORDSubscriber
+ - ONUDevice
+model_policies_dir: "/opt/xos/synchronizers/cord-workflow-probe/model_policies"
+models_dir: "/opt/xos/synchronizers/cord-workflow-probe/models"
+event_steps_dir: "/opt/xos/synchronizers/cord-workflow-probe/event_steps"
+logging:
+ version: 1
+ handlers:
+ console:
+ class: logging.StreamHandler
+ file:
+ class: logging.handlers.RotatingFileHandler
+ filename: /var/log/xos.log
+ maxBytes: 10485760
+ backupCount: 5
+ loggers:
+ 'multistructlog':
+ handlers:
+ - console
+ - file
+ level: DEBUG
\ No newline at end of file
diff --git a/xos/synchronizer/cord-workflow-probe-synchronizer.py b/xos/synchronizer/cord-workflow-probe-synchronizer.py
new file mode 100644
index 0000000..0b90e04
--- /dev/null
+++ b/xos/synchronizer/cord-workflow-probe-synchronizer.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This imports and runs ../../xos-observer.py
+
+import os
+from xossynchronizer import Synchronizer
+from xosconfig import Config
+
+
+base_config_file = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/config.yaml')
+mounted_config_file = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/mounted_config.yaml')
+
+if os.path.isfile(mounted_config_file):
+ Config.init(base_config_file, 'synchronizer-config-schema.yaml', mounted_config_file)
+else:
+ Config.init(base_config_file, 'synchronizer-config-schema.yaml')
+
+Synchronizer().run()
diff --git a/xos/synchronizer/event_steps/__init__.py b/xos/synchronizer/event_steps/__init__.py
new file mode 100644
index 0000000..19d1424
--- /dev/null
+++ b/xos/synchronizer/event_steps/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/xos/synchronizer/event_steps/cord_workflow_event_probe.py b/xos/synchronizer/event_steps/cord_workflow_event_probe.py
new file mode 100644
index 0000000..7eecf24
--- /dev/null
+++ b/xos/synchronizer/event_steps/cord_workflow_event_probe.py
@@ -0,0 +1,72 @@
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+from xossynchronizer.event_steps.eventstep import EventStep
+from cord_workflow_controller_client.probe import Probe
+
+
+class CORDWorkflowEventProbe(EventStep):
+ # topics = ["onu.events", "dhcp.events", "authentication.events"]
+ topics = ['*.events']
+ technology = 'kafka'
+ controller_url = 'http://controller:3030'
+ retry_conn_max = 3
+
+ def __init__(self, *args, **kwargs):
+ super(CORDWorkflowEventProbe, self).__init__(*args, **kwargs)
+
+ self.connected = False
+ self.retry = 0
+ self.connect()
+
+ def connect(self):
+ if not self.connected:
+ if self.retry > self.retry_conn_max:
+ self.log.info(
+ 'Could not connect to Workflow Controller (%s)...' %
+ self.controller_url
+ )
+ self.probe = None
+ self.connected = False
+ else:
+ try:
+ self.log.info(
+ 'Connecting to Workflow Controller (%s)...' %
+ self.controller_url
+ )
+
+ self.probe = Probe(logger=self.log)
+ self.probe.connect(self.controller_url)
+ self.connected = True
+ self.retry = 0
+ except Exception:
+ self.probe = None
+ self.connected = False
+ self.retry += 1
+
+ def process_event(self, event):
+ if not self.connected:
+ self.connect()
+
+ if self.connected:
+ topic = event.topic
+ # event is in json format
+ message = json.loads(event.value)
+
+ self.log.info('Emitting an event (%s - %s)...' % (topic, message))
+ self.probe.emit_event(topic, message)
+ self.log.info('Emitted an event (%s - %s)...' % (topic, message))
+ else:
+ self.log.info('Skip emitting an event (%s - %s)...' % (topic, message))
diff --git a/xos/synchronizer/migrations/__init__.py b/xos/synchronizer/migrations/__init__.py
new file mode 100644
index 0000000..19d1424
--- /dev/null
+++ b/xos/synchronizer/migrations/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/xos/synchronizer/model_policies/__init__.py b/xos/synchronizer/model_policies/__init__.py
new file mode 100644
index 0000000..19d1424
--- /dev/null
+++ b/xos/synchronizer/model_policies/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/xos/synchronizer/model_policies/cord_workflow_model_event_probe.py b/xos/synchronizer/model_policies/cord_workflow_model_event_probe.py
new file mode 100644
index 0000000..06665de
--- /dev/null
+++ b/xos/synchronizer/model_policies/cord_workflow_model_event_probe.py
@@ -0,0 +1,96 @@
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from xossynchronizer.model_policies.policy import Policy
+from cord_workflow_controller_client.probe import Probe
+import os
+import sys
+
+sync_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), ".."))
+sys.path.append(sync_path)
+
+controller_url = 'http://controller:3030'
+probe = None
+retry_conn_max = 3
+connected = False
+retry = 0
+
+
+def connect():
+ if not connected:
+ global probe, connected, retry
+ if retry > retry_conn_max:
+ probe = None
+ connected = False
+ else:
+ try:
+ probe = Probe()
+ probe.connect(controller_url)
+ connected = True
+ retry = 0
+ except Exception:
+ probe = None
+ connected = False
+ retry += 1
+
+
+def emit_helper(instance, event_type):
+ topic = 'datamodel.%s' % instance.model_name
+ message = {
+ 'event_type': event_type
+ }
+
+ if not connected:
+ connect()
+
+ if connected:
+ if 'log' in instance:
+ instance.log.info('Emitting an event (%s - %s)...' % (topic, message))
+
+ if probe:
+ probe.emit_event(topic, message)
+
+ if 'log' in instance:
+ instance.log.info('Emitted an event (%s - %s)...' % (topic, message))
+ else:
+ if 'log' in instance:
+ instance.log.info('Skip emitting an event (%s - %s)...' % (topic, message))
+
+
+class CORDWorkflowModelEventProbe_ATTSI(Policy):
+ # TODO: NEED TO ALLOW MULTI-SUBSCRIPTION OF MODEL UPDATE EVENTS AT A LOWER LEVEL
+ # TO ELIMINATE CREATION OF A CLASS PER MODEL
+ model_name = "AttWorkflowDriverServiceInstance"
+
+ def handle_create(self, instance):
+ emit_helper(self, 'create')
+
+ def handle_update(self, instance):
+ emit_helper(self, 'update')
+
+ def handle_delete(self, instance):
+ emit_helper(self, 'delete')
+
+
+class CORDWorkflowModelEventProbe_ATTWL(Policy):
+ model_name = "AttWorkflowDriverWhiteListEntry"
+
+ def handle_create(self, instance):
+ emit_helper(self, 'create')
+
+ def handle_update(self, instance):
+ emit_helper(self, 'update')
+
+ def handle_delete(self, instance):
+ emit_helper(self, 'delete')
diff --git a/xos/synchronizer/test_config.yaml b/xos/synchronizer/test_config.yaml
new file mode 100644
index 0000000..c6263fe
--- /dev/null
+++ b/xos/synchronizer/test_config.yaml
@@ -0,0 +1,30 @@
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+name: test-cord-workflow-probe
+accessor:
+ username: xosadmin@opencord.org
+ password: "sample"
+ kind: "testframework"
+logging:
+ version: 1
+ handlers:
+ console:
+ class: logging.StreamHandler
+ loggers:
+ 'multistructlog':
+ handlers:
+ - console
+# level: DEBUG
\ No newline at end of file
diff --git a/xos/unittest.cfg b/xos/unittest.cfg
new file mode 100644
index 0000000..4c43fef
--- /dev/null
+++ b/xos/unittest.cfg
@@ -0,0 +1,12 @@
+[unittest]
+plugins=nose2.plugins.junitxml
+code-directories=synchronizer
+ model_policies
+ steps
+ pull_steps
+ event_steps
+
+[coverage]
+always-on = True
+coverage = synchronizer
+coverage-report = term, html, xml
\ No newline at end of file