summaryrefslogtreecommitdiffstats
path: root/cdap
diff options
context:
space:
mode:
Diffstat (limited to 'cdap')
-rw-r--r--cdap/.gitignore1
-rw-r--r--cdap/Changelog.md37
-rw-r--r--cdap/LICENSE.txt32
-rw-r--r--cdap/README.md178
-rwxr-xr-xcdap/cdap_types.yaml90
-rw-r--r--cdap/cdapplugin/cdapcloudify/__init__.py30
-rw-r--r--cdap/cdapplugin/cdapcloudify/cdap_plugin.py231
-rw-r--r--cdap/cdapplugin/cdapcloudify/discovery.py105
-rw-r--r--cdap/cdapplugin/requirements.txt1
-rw-r--r--cdap/cdapplugin/setup.py37
-rw-r--r--cdap/cdapplugin/tests/test_plugin.py87
-rw-r--r--cdap/cdapplugin/tox.ini8
-rw-r--r--cdap/demo_blueprints/cdap_hello_world.yaml40
-rwxr-xr-xcdap/demo_blueprints/cdap_hello_world_reconfigure.sh4
-rw-r--r--cdap/demo_blueprints/cdap_hello_world_with_dmaap.yaml148
-rw-r--r--cdap/demo_blueprints/cdap_hello_world_with_laika.yaml80
-rw-r--r--cdap/demo_blueprints/cdap_hello_world_with_mr.yaml134
-rw-r--r--cdap/pom.xml283
18 files changed, 1526 insertions, 0 deletions
diff --git a/cdap/.gitignore b/cdap/.gitignore
new file mode 100644
index 0000000..0b11d9b
--- /dev/null
+++ b/cdap/.gitignore
@@ -0,0 +1 @@
+cfyhelper.sh
diff --git a/cdap/Changelog.md b/cdap/Changelog.md
new file mode 100644
index 0000000..d919964
--- /dev/null
+++ b/cdap/Changelog.md
@@ -0,0 +1,37 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
+and this project adheres to [Semantic Versioning](http://semver.org/).
+
+## [14.0.2]
+* Start a tox/pytest unit test suite
+
+## [14.0.1]
+* Type file change to move reconfiguration defaults into the type file so each blueprint doesn't need them.
+
+## [14.0.0]
+* Better type speccing in the type file
+* Simplify the component naming
+* Remove the unused (after two years) location and service-id properties
+* Add more demo blueprints and reconfiguration tests
+
+## [13.0.0]
+* Support for data router publication. Data router subscription is a problem, see README.
+* Fixes `services_calls` to have the same format as streams. This is an API break but users are aware.
+
+## [12.1.0]
+* Support for message router integration. Data router publish to come in next release.
+
+## [12.0.1]
+* Use "localhost" instead of solutioning Consul host.
+
+## [12.0.0]
+* Add in functions for policy to call (execute_workflows) to reconfigure CDAP applications
+* Remove "Selected" Nonsense.
+
+FAILURE TO UPDATE
+
+## [10.0.0]
+* Update to support broker API 3.X. This is a breaking change, involving the renaming of Node types
+* Cut dependencies over to Nexus
diff --git a/cdap/LICENSE.txt b/cdap/LICENSE.txt
new file mode 100644
index 0000000..cb8008a
--- /dev/null
+++ b/cdap/LICENSE.txt
@@ -0,0 +1,32 @@
+============LICENSE_START=======================================================
+org.onap.dcae
+================================================================================
+Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+================================================================================
+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.
+============LICENSE_END=========================================================
+
+ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+
+Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+===================================================================
+Licensed under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+you may not use this documentation except in compliance with the License.
+You may obtain a copy of the License at
+ https://creativecommons.org/licenses/by/4.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/cdap/README.md b/cdap/README.md
new file mode 100644
index 0000000..7aa357b
--- /dev/null
+++ b/cdap/README.md
@@ -0,0 +1,178 @@
+# cdap-cloudify
+Contains a plugin and type file for deploying CDAP and related artifacts.
+
+# service component name
+When the cdap plugin deploys an application, it generates a service component name. That service component name is injected
+into the node's runtime dictionary under the key "service_component_name" and also made available as an output under this key.
+
+# Demo blueprints
+There is a subfolder in this repo called `demo_blueprints` that contains (templatized) example blueprints.
+
+# Connections
+Since you cannot type-spec complicated objects in a cloudify node type, I have to explain this here. This is a requirement on all blueprints that use this node type.
+
+There is a property at the top level of the CDAP node called `connections` that is expecting a specific structure, best serviced with examples.
+
+## DMaaP
+
+### Message Router
+Message router publication
+```
+ connections:
+ streams_publishes: // is a list
+ - name: topic00 // THIS NAME MUST MATCH THE NODE NAME IN BLUEPRINT, SEE BELOW*
+ location: mtc5
+ client_role: XXXX
+ type: message_router
+ config_key: "myconfigkey1" // from spec
+ aaf_username: { get_input: aafu1 }
+ aaf_password: { get_input: aafp1 }
+ - name: topic01 // THIS NAME MUST MATCH THE NODE NAME IN BLUEPRINT, SEE BELOW*
+ location: mtc5
+ client_role: XXXX
+ type: message_router
+ config_key: "myconfigkey2" // from spec
+ aaf_username: { get_input: aafu2 }
+ aaf_password: { get_input: aafp2 }
+```
+Message router subscription is the exact same format, except change `streams_publishes` to `streams_subscribes`:
+```
+ streams_subscribes:
+ - name: topic00 #MEANT FOR DEMO ONLY! Subscribing and publishing to same topic. Not real example.
+ location: mtc5
+ client_role: XXXX
+ type: message_router
+ config_key: "myconfigkey2"
+ aaf_username: { get_input: aafu2 }
+ aaf_password: { get_input: aafp2 }
+ - name: topic01
+ location: mtc5
+ client_role: XXXX
+ type: message_router
+ config_key: "myconfigkey3"
+ aaf_username: { get_input: aafu3 }
+ aaf_password: { get_input: aafp3 }
+```
+The terms `streams_publishes` and `streams_subscribes` comes from the component specification.
+
+### Data Router
+For publication, data router does not have the notion of AAF credentials, and there is no `client_role`. So the expected blueprint input is simpler than the MR case:
+```
+ streams_publishes:
+ ...
+ - name: feed00
+ location: mtc5
+ type: data_router
+ config_key: "mydrconfigkey"
+```
+
+Data router subscription is not supported because there is an impedance mistmatch between DR and CDAP.
+CDAP streams expect a POST but DR outputs a PUT.
+Some future platform capability needs to fill this hole; either something like the AF team's DR Sub or DMD.
+
+### Bound configuration
+The above blueprint snippets will lead to the cdap application's `app_config` getting an entry that looks like this:
+```
+{
+ "streams_subscribes":{
+ "myconfigkey3":{
+ "type":"message_router",
+ "aaf_username":"foo3",
+ "aaf_password":"bar3",
+ "dmaap_info":{
+ "client_role":"XXXX",
+ "client_id":"XXXX",
+ "location":"XXXX",
+ "topic_url":"XXXX"
+ }
+ },
+ "myconfigkey2":{
+ "type":"message_router",
+ "aaf_username":"foo2",
+ "aaf_password":"bar2",
+ "dmaap_info":{
+ "client_role":"XXXX",
+ "client_id":"XXXX",
+ "location":"XXXX",
+ "topic_url":"XXXX"
+ }
+ }
+ },
+ "streams_publishes":{
+ "myconfigkey1":{
+ "type":"message_router",
+ "aaf_username":"foo1",
+ "aaf_password":"bar1",
+ "dmaap_info":{
+ "client_role":"XXXX",
+ "client_id":"XXXX",
+ "location":"XXXX",
+ "topic_url":"XXXX"
+ }
+ },
+ "mydrconfigkey":{
+ "type":"data_router",
+ "dmaap_info":{
+ "username":"XXXX",
+ "location":"XXXX",
+ "publish_url":"XXXX",
+ "publisher_id":"XXXX",
+ "log_url":"XXXX",
+ "password":"XXXX"
+ }
+ },
+ "myconfigkey0":{
+ "type":"message_router",
+ "aaf_username":"foo0",
+ "aaf_password":"bar0",
+ "dmaap_info":{
+ "client_role":"XXXX",
+ "client_id":"XXXX",
+ "location":"XXXX",
+ "topic_url":"XXXX"
+ }
+ }
+ }
+}
+```
+## HTTP
+In addition to DMaaP, we support HTTP services.
+
+### Services Calls
+In a blueprint, to express that one component calls asynchronous HTTP service of another component, writing this as `A -> B,` you need:
+
+1. `A` to have a `connections/services_calls` entry:
+```
+ connections:
+ services_calls:
+ - service_component_type: laika
+ config_key: "laika_handle"
+```
+2. A relationship of type `dcae.relationships.component_connected_to` from A to B.
+
+3. The `B` node's `service_component_type` should match #1
+
+See the demo blueprint `cdap_hello_world_with_laika.yaml`
+
+### Bound Configuration
+
+The above (without having defined streams) will lead to:
+```
+{
+ "streams_subscribes":{
+
+ },
+ "streams_publishes":{
+
+ },
+ "services_calls":{
+ "laika_handle":[
+ "some_up:some_port"
+ ]
+ }
+}
+```
+Note that the value is always a list of IP:Ports because there could be multiple identical services that satisfy the client (A in this case). This is client side load balancing.
+
+# Tests
+To run the tests, you need `tox`. You can get it with `pip install tox`. After that, simply run `tox` from inside the `cdapplugin` directory to run the tests.
diff --git a/cdap/cdap_types.yaml b/cdap/cdap_types.yaml
new file mode 100755
index 0000000..497307c
--- /dev/null
+++ b/cdap/cdap_types.yaml
@@ -0,0 +1,90 @@
+tosca_definitions_version: cloudify_dsl_1_3
+
+imports:
+ - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
+plugins:
+ cdap_deploy:
+ executor: central_deployment_agent
+ package_name: cdapcloudify
+ package_version: 14.0.2
+
+data_types:
+ cdap_connections:
+ properties:
+ services_calls:
+ default: []
+ streams_publishes:
+ default: []
+ streams_subscribes:
+ default: []
+
+node_types:
+ dcae.nodes.MicroService.cdap:
+ derived_from: cloudify.nodes.Root
+ properties:
+ service_component_type:
+ type: string
+ #####
+ #For the following parameters in this block, see the Broker API
+ #####
+ jar_url:
+ type: string
+ artifact_name:
+ type: string
+ artifact_version:
+ type: string
+ connections:
+ type: cdap_connections
+ app_config:
+ default: {}
+ app_preferences:
+ default: {}
+ program_preferences:
+ default: []
+ programs:
+ default: []
+ streamname:
+ #currently, we only support CDAP apps written that read from a
+ #stream. This is not the only ingest mechanism for CDAP. This may have to change/get
+ type: string
+ namespace:
+ #the namespace to deploy the CDAP app into
+ #defaults to the default cdap namespace which is called "default"
+ type: string
+ default : "default"
+ service_endpoints:
+ default: []
+
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ create:
+ implementation: cdap_deploy.cdapcloudify.cdap_plugin.create
+ inputs:
+ connected_broker_dns_name:
+ type: string
+ description: This is the broker's DNS name. There could be multiple brokers/clusters at a site. Could by populated via an intrinsic_function in a blueprint, or manually via inputs file
+ default: "cdap_broker"
+ start:
+ cdap_deploy.cdapcloudify.cdap_plugin.deploy_and_start_application
+ delete:
+ cdap_deploy.cdapcloudify.cdap_plugin.stop_and_undeploy_application
+ reconfiguration:
+ app_config_reconfigure:
+ implementation: cdap_deploy.cdapcloudify.cdap_plugin.app_config_reconfigure
+ inputs:
+ new_config_template:
+ description: "new unbound config for the CDAP AppConfig as a JSON"
+ default: {}
+ app_preferences_reconfigure:
+ implementation: cdap_deploy.cdapcloudify.cdap_plugin.app_preferences_reconfigure
+ inputs:
+ new_config_template:
+ description: "new bound config for the CDAP AppPreferences as a JSON"
+ default: {}
+ app_smart_reconfigure:
+ implementation: cdap_deploy.cdapcloudify.cdap_plugin.app_smart_reconfigure
+ inputs:
+ new_config_template:
+ description: "new unbound config for the CDAP AppConfig as a JSON"
+ default: {}
+
diff --git a/cdap/cdapplugin/cdapcloudify/__init__.py b/cdap/cdapplugin/cdapcloudify/__init__.py
new file mode 100644
index 0000000..388ac55
--- /dev/null
+++ b/cdap/cdapplugin/cdapcloudify/__init__.py
@@ -0,0 +1,30 @@
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+import logging
+
+def get_module_logger(mod_name):
+ logger = logging.getLogger(mod_name)
+ handler = logging.StreamHandler()
+ formatter = logging.Formatter(
+ '%(asctime)s [%(name)-12s] %(levelname)-8s %(message)s')
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
+ logger.setLevel(logging.DEBUG)
+ return logger
diff --git a/cdap/cdapplugin/cdapcloudify/cdap_plugin.py b/cdap/cdapplugin/cdapcloudify/cdap_plugin.py
new file mode 100644
index 0000000..f5eaf0b
--- /dev/null
+++ b/cdap/cdapplugin/cdapcloudify/cdap_plugin.py
@@ -0,0 +1,231 @@
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+import requests
+from cloudify import ctx
+from cloudify.decorators import operation
+from cloudify.exceptions import NonRecoverableError
+import time
+import uuid
+import re
+from cdapcloudify import discovery
+import json
+
+"""
+TODO: Tons of crappy URL forming going on here...
+"""
+# Property keys
+SERVICE_COMPONENT_NAME = "service_component_name"
+SELECTED_BROKER = "selected_broker"
+PUB_C = "streams_publishes_for_config"
+SUB_C = "streams_subscribes_for_config"
+SER_C = "services_calls_for_config"
+STREAMS_PUBLISHES = "streams_publishes"
+STREAMS_SUBSCRIBES = "streams_subscribes"
+SERVICES_CALLS = "services_calls"
+
+# Custom Exception
+class BadConnections(NonRecoverableError):
+ pass
+
+
+def _validate_conns(connections):
+ """
+ Cloudify allows you to type spec a data type in a type file, however it does not appear to do strict checking on blueprints against that.
+ Sad!
+ The "connections" block has an important structure to this plugin, so here we validate it and fail fast if it is not correct.
+ """
+ try:
+ def _assert_ks_in_d(ks,d):
+ for k in ks:
+ assert(k in d)
+ assert STREAMS_PUBLISHES in connections
+ assert STREAMS_SUBSCRIBES in connections
+ for s in connections[STREAMS_PUBLISHES] + connections[STREAMS_SUBSCRIBES]:
+ _assert_ks_in_d(["name", "location", "type", "config_key"], s)
+ assert(s["type"] in ["message_router", "data_router"])
+ if s["type"] == "message_router":
+ _assert_ks_in_d(["aaf_username", "aaf_password", "client_role"], s) #I am not checking that these are not blank. I will leave it possible for you to put empty values for these, but force you to acknowledge that you are doing so by not allowing these to be ommited.
+ #nothing extra for DR; no AAF, no client role.
+ except:
+ raise BadConnections("Bad Connections definition in blueprint") #is a NoneRecoverable
+
+def _streams_iterator(streams):
+ """
+ helper function for iterating over streams_publishes and subscribes
+ note! this is an impure function. it also sets the properties the dmaap plugin needs into runtime properties
+ """
+ for_config = {}
+ for s in streams:
+ if s["type"] == "message_router":
+ #set the properties the DMaaP plugin needs
+ ctx.instance.runtime_properties[s["name"]] = {"client_role" : s["client_role"], "location" : s["location"]}
+ #form (or append to) the dict the component will get, including the template for the CBS
+ for_config[s["config_key"]] = {"aaf_username" : s["aaf_username"], "aaf_password" : s["aaf_password"], "type" : s["type"], "dmaap_info" : "<< " + s["name"] + ">>"} #will get bound by CBS
+ if s["type"] == "data_router":
+ #set the properties the DMaaP plugin needs$
+ ctx.instance.runtime_properties[s["name"]] = {"location" : s["location"]}
+ #form (or append to) the dict the component will get, including the template for the CBS$
+ for_config[s["config_key"]] = {"type" : s["type"], "dmaap_info" : "<<" + s["name"] + ">>"} #will get bound by CBS
+
+ return for_config
+
+def _services_calls_iterator(services_calls):
+ """
+ helper function for iterating over services_calls
+ """
+ for_config = {}
+ for s in services_calls:
+ #form (or append to) the dict the component will get, including the template for the CBS
+ for_config[s["config_key"]] = "{{ " + s["service_component_type"] + " }}" #will get bound by CBS
+ return for_config
+
+######################
+# Cloudify Operations
+######################
+
+@operation
+def create(connected_broker_dns_name, **kwargs):
+ """
+ This is apparantly needed due to the order in which Cloudify relationships are handled in Cloudify.
+ """
+
+ #fail fast
+ _validate_conns(ctx.node.properties["connections"])
+
+ #The config binding service needs to know whether cdap or docker. Currently (aug 1 2018) it looks for "cdap_app" in the name
+ service_component_name = "{0}_cdap_app_{1}".format(str(uuid.uuid4()).replace("-",""), ctx.node.properties["service_component_type"])
+
+ #set this into a runtime dictionary
+ ctx.instance.runtime_properties[SERVICE_COMPONENT_NAME] = service_component_name
+
+ #fetch the broker name from inputs and set it in runtime properties so other functions can use it
+ ctx.instance.runtime_properties[SELECTED_BROKER] = connected_broker_dns_name
+
+ #set the properties the DMaap plugin expects for message router
+ #see the README for the structures of these keys
+ #NOTE! This has to be done in create because Jack's DMaaP plugin expects to do it's thing in preconfigure.
+ # and we need to get this key into consul before start
+ #set this as a runtime property for start to use
+ ctx.instance.runtime_properties[PUB_C] = _streams_iterator(ctx.node.properties["connections"][STREAMS_PUBLISHES])
+ ctx.instance.runtime_properties[SUB_C] = _streams_iterator(ctx.node.properties["connections"][STREAMS_SUBSCRIBES])
+ ctx.instance.runtime_properties[SER_C] = _services_calls_iterator(ctx.node.properties["connections"][SERVICES_CALLS])
+
+@operation
+def deploy_and_start_application(**kwargs):
+ """
+ pushes the application into the workspace and starts it
+ """
+ try:
+ #parse TOSCA model params
+ config_template = ctx.node.properties["app_config"]
+
+ #there is a typed section in the node type called "connections", but the broker expects those two keys at the top level of app_config, so add them here
+ #In cloudify you can't have a custom data type and then specify unknown propertys, the vlidation will fail, so typespeccing just part of app_config doesnt work
+ #the rest of the CDAP app's app_config is app-dependent
+ config_template[SERVICES_CALLS] = ctx.instance.runtime_properties[SER_C]
+ config_template[STREAMS_PUBLISHES] = ctx.instance.runtime_properties[PUB_C]
+ config_template[STREAMS_SUBSCRIBES] = ctx.instance.runtime_properties[SUB_C]
+
+ #register with broker
+ ctx.logger.info("Registering with Broker, config template was: {0}".format(json.dumps(config_template)))
+ discovery.put_broker(cdap_broker_name = ctx.instance.runtime_properties[SELECTED_BROKER],
+ service_component_name = ctx.instance.runtime_properties[SERVICE_COMPONENT_NAME],
+ namespace = ctx.node.properties["namespace"],
+ streamname = ctx.node.properties["streamname"],
+ jar_url = ctx.node.properties["jar_url"],
+ artifact_name = ctx.node.properties["artifact_name"],
+ artifact_version = ctx.node.properties["artifact_version"],
+ app_config = config_template,
+ app_preferences = ctx.node.properties["app_preferences"],
+ service_endpoints = ctx.node.properties["service_endpoints"],
+ programs = ctx.node.properties["programs"],
+ program_preferences = ctx.node.properties["program_preferences"],
+ logger = ctx.logger)
+
+ except Exception as e:
+ ctx.logger.error("Error depploying CDAP app: {er}".format(er=e))
+ raise NonRecoverableError(e)
+
+@operation
+def stop_and_undeploy_application(**kwargs):
+ #per jack Lucas, do not raise Nonrecoverables on any delete operation. Keep going on them all, cleaning up as much as you can.
+ #bombing would also bomb the deletion of the rest of the blueprint
+ ctx.logger.info("Undeploying CDAP application")
+
+ try: #deregister with the broker, which will also take down the service from consul
+ discovery.delete_on_broker(ctx.instance.runtime_properties[SELECTED_BROKER],
+ ctx.instance.runtime_properties[SERVICE_COMPONENT_NAME],
+ ctx.logger)
+ except Exception as e:
+ ctx.logger.error("Error deregistering from Broker, but continuing with deletion process: {0}".format(e))
+
+############
+#RECONFIGURATION
+# These calls works as follows:
+# 1) it expects "new_config_template" to be a key in kwargs, i.e., passed in using execute_operations -p parameter
+# 2) it pushes the new unbound config down to the broker
+# 3) broker deals with the rest
+############
+@operation
+def app_config_reconfigure(new_config_template, **kwargs):
+ """
+ reconfigure the CDAP app's app config
+ """
+ try:
+ ctx.logger.info("Reconfiguring CDAP application via app_config")
+ discovery.reconfigure_in_broker(cdap_broker_name = ctx.instance.runtime_properties[SELECTED_BROKER],
+ service_component_name = ctx.instance.runtime_properties[SERVICE_COMPONENT_NAME],
+ config = new_config_template, #This keyname will likely change per policy handler
+ reconfiguration_type = "program-flowlet-app-config",
+ logger = ctx.logger)
+ except Exception as e:
+ raise NonRecoverableError("CDAP Reconfigure error: {0}".format(e))
+
+@operation
+def app_preferences_reconfigure(new_config_template, **kwargs):
+ """
+ reconfigure the CDAP app's app preferences
+ """
+ try:
+ ctx.logger.info("Reconfiguring CDAP application via app_preferences")
+ discovery.reconfigure_in_broker(cdap_broker_name = ctx.instance.runtime_properties[SELECTED_BROKER],
+ service_component_name = ctx.instance.runtime_properties[SERVICE_COMPONENT_NAME],
+ config = new_config_template, #This keyname will likely change per policy handler
+ reconfiguration_type = "program-flowlet-app-preferences",
+ logger = ctx.logger)
+ except Exception as e:
+ raise NonRecoverableError("CDAP Reconfigure error: {0}".format(e))
+
+@operation
+def app_smart_reconfigure(new_config_template, **kwargs):
+ """
+ reconfigure the CDAP app via the broker smart interface
+ """
+ try:
+ ctx.logger.info("Reconfiguring CDAP application via smart interface")
+ discovery.reconfigure_in_broker(cdap_broker_name = ctx.instance.runtime_properties[SELECTED_BROKER],
+ service_component_name = ctx.instance.runtime_properties[SERVICE_COMPONENT_NAME],
+ config = new_config_template, #This keyname will likely change per policy handler
+ reconfiguration_type = "program-flowlet-smart",
+ logger = ctx.logger)
+ except Exception as e:
+ raise NonRecoverableError("CDAP Reconfigure error: {0}".format(e))
+
+
diff --git a/cdap/cdapplugin/cdapcloudify/discovery.py b/cdap/cdapplugin/cdapcloudify/discovery.py
new file mode 100644
index 0000000..a8f0ce2
--- /dev/null
+++ b/cdap/cdapplugin/cdapcloudify/discovery.py
@@ -0,0 +1,105 @@
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+import requests
+import json
+
+CONSUL_HOST = "http://localhost:8500"
+
+def _get_broker_url(cdap_broker_name, service_component_name, logger):
+ """
+ fetch the broker connection information from Consul
+ """
+ def _get_connection_info_from_consul(service_component_name, logger):
+ """
+ Call consul's catalog
+ TODO: currently assumes there is only one service
+ """
+ url = "{0}/v1/catalog/service/{1}".format(CONSUL_HOST, service_component_name)
+ logger.info("Trying to query: {0}".format(url))
+ res = requests.get(url)
+ res.raise_for_status()
+ services = res.json()
+ return services[0]["ServiceAddress"], services[0]["ServicePort"]
+
+ broker_ip, broker_port = _get_connection_info_from_consul(cdap_broker_name, logger)
+ broker_url = "http://{ip}:{port}/application/{appname}".format(ip=broker_ip, port=broker_port, appname=service_component_name)
+ logger.info("Trying to connect to broker endpoint: {0}".format(broker_url))
+ return broker_url
+
+"""
+public
+"""
+def put_broker(cdap_broker_name,
+ service_component_name,
+ namespace,
+ streamname,
+ jar_url,
+ artifact_name,
+ artifact_version,
+ app_config,
+ app_preferences,
+ service_endpoints,
+ programs,
+ program_preferences,
+ logger):
+ """
+ Conforms to Broker API 4.X
+ """
+
+ data = dict()
+ data["cdap_application_type"] = "program-flowlet"
+ data["namespace"] = namespace
+ data["streamname"] = streamname
+ data["jar_url"] = jar_url
+ data["artifact_name"] = artifact_name
+ data["artifact_version"] = artifact_version
+ data["app_config"] = app_config
+ data["app_preferences"] = app_preferences
+ data["services"] = service_endpoints
+ data["programs"] = programs
+ data["program_preferences"] = program_preferences
+
+ #register with the broker
+ response = requests.put(_get_broker_url(cdap_broker_name, service_component_name, logger),
+ json = data,
+ headers = {'content-type':'application/json'})
+ logger.info((response, response.status_code, response.text))
+ response.raise_for_status() #bomb if not 2xx
+
+def reconfigure_in_broker(cdap_broker_name,
+ service_component_name,
+ config,
+ reconfiguration_type,
+ logger):
+ #trigger a reconfiguration with the broker
+ #man am I glad I broke the broker API from 3 to 4 to standardize this interface because now I only need one function here
+ response = requests.put("{u}/reconfigure".format(u = _get_broker_url(cdap_broker_name, service_component_name, logger)),
+ headers = {'content-type':'application/json'},
+ json = {"reconfiguration_type" : reconfiguration_type,
+ "config" : config})
+ logger.info((response, response.status_code, response.text))
+ response.raise_for_status() #bomb if not 2xx
+
+def delete_on_broker(cdap_broker_name, service_component_name, logger):
+ #deregister with the broker
+ response = requests.delete(_get_broker_url(cdap_broker_name, service_component_name, logger))
+ logger.info((response, response.status_code, response.text))
+ response.raise_for_status() #bomb if not 2xx
+
diff --git a/cdap/cdapplugin/requirements.txt b/cdap/cdapplugin/requirements.txt
new file mode 100644
index 0000000..1128300
--- /dev/null
+++ b/cdap/cdapplugin/requirements.txt
@@ -0,0 +1 @@
+uuid==1.30
diff --git a/cdap/cdapplugin/setup.py b/cdap/cdapplugin/setup.py
new file mode 100644
index 0000000..d16667d
--- /dev/null
+++ b/cdap/cdapplugin/setup.py
@@ -0,0 +1,37 @@
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+import os
+from setuptools import setup, find_packages
+
+setup(
+ name = "cdapcloudify",
+ version = "14.0.2",
+ packages=find_packages(),
+ author = "Tommy Carpenter",
+ author_email = "tommy at research dot eh tee tee dot com",
+ description = ("Cloudify plugin for CDAP"),
+ license = "",
+ keywords = "",
+ url = "https://gerrit.onap.org/r/#/admin/projects/dcaegen2/platform/plugins",
+ zip_safe=False,
+ install_requires = [
+ "uuid==1.30"
+ ]
+)
diff --git a/cdap/cdapplugin/tests/test_plugin.py b/cdap/cdapplugin/tests/test_plugin.py
new file mode 100644
index 0000000..7434fe8
--- /dev/null
+++ b/cdap/cdapplugin/tests/test_plugin.py
@@ -0,0 +1,87 @@
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+from cdapcloudify.cdap_plugin import _validate_conns, BadConnections
+import pytest
+
+#todo.. add more tests.. #shame
+
+def _get_good_connection():
+ connections = {}
+ connections["streams_publishes"] = [
+ {"name" : "test_n",
+ "location" : "test_l",
+ "client_role" : "test_cr",
+ "type" : "message_router",
+ "config_key" : "test_c",
+ "aaf_username": "test_u",
+ "aaf_password": "test_p"
+ },
+ {"name" : "test_n2",
+ "location" : "test_l",
+ "client_role" : "test_cr",
+ "type" : "message_router",
+ "config_key" : "test_c",
+ "aaf_username": "test_u",
+ "aaf_password": "test_p"
+ },
+ {"name" : "test_feed00",
+ "location" : "test_l",
+ "type" : "data_router",
+ "config_key" : "mydrconfigkey"
+ }
+ ]
+ connections["streams_subscribes"] = [
+ {"name" : "test_n",
+ "location" : "test_l",
+ "client_role" : "test_cr",
+ "type" : "message_router",
+ "config_key" : "test_c",
+ "aaf_username": "test_u",
+ "aaf_password": "test_p"
+ },
+ {"name" : "test_n2",
+ "location" : "test_l",
+ "client_role" : "test_cr",
+ "type" : "message_router",
+ "config_key" : "test_c",
+ "aaf_username": "test_u",
+ "aaf_password": "test_p"
+ }
+ ]
+ return connections
+
+def test_validate_cons():
+ #test good streams
+ good_conn = _get_good_connection()
+ _validate_conns(good_conn)
+
+ #mutate
+ nosub = _get_good_connection().pop("streams_subscribes")
+ with pytest.raises(BadConnections) as excinfo:
+ _validate_conns(nosub)
+
+ nopub = _get_good_connection().pop("streams_publishes")
+ with pytest.raises(BadConnections) as excinfo:
+ _validate_conns(nopub)
+
+ noloc = _get_good_connection()["streams_publishes"][0].pop("location")
+ with pytest.raises(BadConnections) as excinfo:
+ _validate_conns(noloc)
+
diff --git a/cdap/cdapplugin/tox.ini b/cdap/cdapplugin/tox.ini
new file mode 100644
index 0000000..afabca4
--- /dev/null
+++ b/cdap/cdapplugin/tox.ini
@@ -0,0 +1,8 @@
+[tox]
+envlist = py27
+[testenv]
+deps=
+ pytest
+ uuid==1.30
+ cloudify==3.4
+commands=pytest
diff --git a/cdap/demo_blueprints/cdap_hello_world.yaml b/cdap/demo_blueprints/cdap_hello_world.yaml
new file mode 100644
index 0000000..1b7ff90
--- /dev/null
+++ b/cdap/demo_blueprints/cdap_hello_world.yaml
@@ -0,0 +1,40 @@
+tosca_definitions_version: cloudify_dsl_1_3
+
+imports:
+ - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
+ - {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2 }}/type_files/cdap/14.0.2/cdap_types.yaml
+
+inputs:
+ hello_world_jar_url:
+ type: string
+ connected_broker_dns_name:
+ type: string
+ default : "cdap_broker"
+
+node_templates:
+
+ hw_cdap_app:
+ type: dcae.nodes.MicroService.cdap
+ properties:
+ service_component_type:
+ 'hello_world'
+ jar_url: { get_input : hello_world_jar_url }
+ artifact_name: "HelloWorld"
+ artifact_version: "3.4.3"
+ namespace: "cloudifyhwtest"
+ programs:
+ [{"program_type" : "flows", "program_id" : "WhoFlow"}, {"program_type" : "services", "program_id" : "Greeting"}]
+ streamname:
+ 'who'
+ service_endpoints:
+ [{"service_name" : "Greeting", "service_endpoint" : "greet", "endpoint_method" : "GET"}]
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ create:
+ inputs:
+ connected_broker_dns_name: { get_input: connected_broker_dns_name }
+
+outputs:
+ hw_cdap_app_name:
+ value:
+ {get_attribute:[hw_cdap_app, service_component_name]}
diff --git a/cdap/demo_blueprints/cdap_hello_world_reconfigure.sh b/cdap/demo_blueprints/cdap_hello_world_reconfigure.sh
new file mode 100755
index 0000000..c5df2f5
--- /dev/null
+++ b/cdap/demo_blueprints/cdap_hello_world_reconfigure.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+cfy executions start -d cdap-hello-world -w execute_operation -p '{"operation" : "reconfiguration.app_config_reconfigure", "node_ids" : ["hw_cdap_app"], "operation_kwargs" : {"new_config_template" : {"foo":"bar"}}, "allow_kwargs_override": true}'
+cfy executions start -d cdap-hello-world -w execute_operation -p '{"operation" : "reconfiguration.app_preferences_reconfigure", "node_ids" : ["hw_cdap_app"], "operation_kwargs" : {"new_config_template" : {"fooprefs":"barprefs"}}, "allow_kwargs_override": true}'
+cfy executions start -d cdap-hello-world -w execute_operation -p '{"operation" : "reconfiguration.app_smart_reconfigure", "node_ids" : ["hw_cdap_app"], "operation_kwargs" : {"new_config_template" : {"fooprefs":"SO SMARTTTTTT", "foo":"SO SMART AGAINNNNN"}}, "allow_kwargs_override": true}'
diff --git a/cdap/demo_blueprints/cdap_hello_world_with_dmaap.yaml b/cdap/demo_blueprints/cdap_hello_world_with_dmaap.yaml
new file mode 100644
index 0000000..ea02543
--- /dev/null
+++ b/cdap/demo_blueprints/cdap_hello_world_with_dmaap.yaml
@@ -0,0 +1,148 @@
+tosca_definitions_version: cloudify_dsl_1_3
+
+imports:
+ - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
+ - {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2 }}/type_files/cdap/14.0.2/cdap_types.yaml
+ - {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2 }}/type_files/dmaap/1.1.0/dmaap.yaml
+
+inputs:
+ hello_world_jar_url:
+ type: string
+ connected_broker_dns_name:
+ type: string
+ default : "cdap_broker"
+
+ #aaf inputs
+ client_role:
+ type: string
+ topic00fqtn:
+ type: string
+ topic01fqtn:
+ type: string
+ aafu0:
+ type: string
+ default: "foo0"
+ aafp0:
+ type: string
+ default: "bar0"
+ aafu1:
+ type: string
+ default : "foo1"
+ aafp1:
+ type: string
+ default : "bar1"
+ aafu2:
+ type: string
+ default: "foo2"
+ aafp2:
+ type: string
+ default: "bar2"
+ aafu3:
+ type: string
+ default : "foo3"
+ aafp3:
+ type: string
+ default : "bar3"
+
+node_templates:
+ topic00:
+ type: dcae.nodes.ExistingTopic
+ properties:
+ fqtn: { get_input : topic00fqtn }
+ topic01:
+ type: dcae.nodes.ExistingTopic
+ properties:
+ fqtn: { get_input : topic01fqtn }
+ feed00:
+ type: dcae.nodes.Feed
+ properties:
+ feed_name: "FEEDME-12"
+ feed_description: "Tommy Test feed for CDAP Publishes"
+ feed_version: 6.6.6
+ aspr_classification: "unclassified"
+
+ hw_cdap_app:
+ type: dcae.nodes.MicroService.cdap
+ properties:
+ service_component_type: 'hello_world'
+ jar_url: { get_input : hello_world_jar_url }
+ artifact_name: "HelloWorld"
+ artifact_version: "3.4.3"
+ namespace: "cloudifyhwtest"
+ programs:
+ [{"program_type" : "flows", "program_id" : "WhoFlow"}, {"program_type" : "services", "program_id" : "Greeting"}]
+ streamname:
+ 'who'
+ service_endpoints:
+ [{"service_name" : "Greeting", "service_endpoint" : "greet", "endpoint_method" : "GET"}]
+
+ #special key for CDAP plugin
+ connections:
+ streams_publishes:
+ - name: topic00 #MR pub 1
+ location: mtc5
+ client_role: { get_input: client_role }
+ type: message_router
+ config_key: "myconfigkey0"
+ aaf_username: { get_input: aafu0 }
+ aaf_password: { get_input: aafp0 }
+ - name: topic01 #MR pub 2
+ location: mtc5
+ client_role: { get_input: client_role }
+ type: message_router
+ config_key: "myconfigkey1"
+ aaf_username: { get_input: aafu1 }
+ aaf_password: { get_input: aafp1 }
+ - name: feed00 #Feed pub 1
+ location: mtc5
+ type: data_router
+ config_key: "mydrconfigkey"
+ streams_subscribes:
+ - name: topic00 #MEANT FOR DEMO ONLY! Subscribing and publishing to same topic. Not real example.
+ location: mtc5
+ client_role: { get_input: client_role }
+ type: message_router
+ config_key: "myconfigkey2"
+ aaf_username: { get_input: aafu2 }
+ aaf_password: { get_input: aafp2 }
+ - name: topic01
+ location: mtc5
+ client_role: { get_input: client_role }
+ type: message_router
+ config_key: "myconfigkey3"
+ aaf_username: { get_input: aafu3 }
+ aaf_password: { get_input: aafp3 }
+
+ relationships:
+ - type: dcae.relationships.publish_events
+ target: topic00 #MEANT FOR DEMO ONLY! Subscribing and publishing to same topic. Not real example.
+ - type: dcae.relationships.publish_events
+ target: topic01
+ - type: dcae.relationships.subscribe_to_events
+ target: topic00
+ - type: dcae.relationships.subscribe_to_events
+ target: topic01
+ - type: dcae.relationships.publish_files
+ target: feed00
+
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ create:
+ inputs:
+ connected_broker_dns_name: { get_input: connected_broker_dns_name }
+
+outputs:
+ hw_cdap_app_name:
+ value: {get_attribute:[hw_cdap_app, service_component_name]}
+
+ topic00_data:
+ description: "Topic 00 data"
+ value: { get_attribute: [hw_cdap_app, topic00]}
+
+ topic01_data:
+ description: "Topic 01 data"
+ value: { get_attribute: [hw_cdap_app, topic01]}
+
+
+
+
diff --git a/cdap/demo_blueprints/cdap_hello_world_with_laika.yaml b/cdap/demo_blueprints/cdap_hello_world_with_laika.yaml
new file mode 100644
index 0000000..4587a47
--- /dev/null
+++ b/cdap/demo_blueprints/cdap_hello_world_with_laika.yaml
@@ -0,0 +1,80 @@
+tosca_definitions_version: cloudify_dsl_1_3
+
+imports:
+ - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
+ - {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2 }}/type_files/cdap/14.0.2/cdap_types.yaml
+ - {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2 }}/type_files/docker/2.1.0/node-type.yaml
+ - {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2 }}/type_files/relationship/1.0.0/node-type.yaml
+
+inputs:
+ hello_world_jar_url:
+ type: string
+ laika_image:
+ type: string
+ connected_broker_dns_name:
+ type: string
+ default : "cdap_broker"
+
+node_templates:
+
+ hw_cdap_app:
+ type: dcae.nodes.MicroService.cdap
+ properties:
+ service_component_type:
+ 'hello_world'
+ jar_url: { get_input : hello_world_jar_url }
+ artifact_name: "HelloWorld"
+ artifact_version: "3.4.3"
+ namespace: "cloudifyhwtest"
+ programs:
+ [{"program_type" : "flows", "program_id" : "WhoFlow"}, {"program_type" : "services", "program_id" : "Greeting"}]
+ streamname:
+ 'who'
+ service_endpoints:
+ [{"service_name" : "Greeting", "service_endpoint" : "greet", "endpoint_method" : "GET"}]
+
+ connections:
+ services_calls:
+ - service_component_type: laika
+ config_key: "laika_handle"
+
+ relationships:
+ - type: dcae.relationships.component_connected_to
+ target: laika-one
+
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ create:
+ inputs:
+ connected_broker_dns_name: { get_input: connected_broker_dns_name }
+
+ laika-one:
+ type: dcae.nodes.DockerContainerForComponents
+ properties:
+ service_component_type: 'laika'
+ service_id: 'this_is_dumb'
+ location_id: 'this_is_dumb'
+ image: { get_input : laika_image }
+ # Trying without health check
+ relationships:
+ - type: dcae.relationships.component_contained_in
+ target: docker_host
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ stop:
+ inputs:
+ cleanup_image:
+ False
+
+ docker_host:
+ type: dcae.nodes.SelectedDockerHost
+ properties:
+ location_id: 'this is dumb'
+ docker_host_override: 'platform_dockerhost'
+
+outputs:
+ hw_cdap_app_name:
+ value: {get_attribute:[hw_cdap_app, service_component_name]}
+
+
+
diff --git a/cdap/demo_blueprints/cdap_hello_world_with_mr.yaml b/cdap/demo_blueprints/cdap_hello_world_with_mr.yaml
new file mode 100644
index 0000000..e1e0adb
--- /dev/null
+++ b/cdap/demo_blueprints/cdap_hello_world_with_mr.yaml
@@ -0,0 +1,134 @@
+tosca_definitions_version: cloudify_dsl_1_3
+
+imports:
+ - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
+ - {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2 }}/type_files/cdap/14.0.2/cdap_types.yaml
+ - {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2 }}/type_files/dmaap/1.1.0/dmaap.yaml
+
+inputs:
+ hello_world_jar_url:
+ type: string
+ connected_broker_dns_name:
+ type: string
+ default : "cdap_broker"
+
+ #aaf inputs
+ client_role:
+ type: string
+ topic00fqtn:
+ type: string
+ topic01fqtn:
+ type: string
+ aafu0:
+ type: string
+ default: "foo0"
+ aafp0:
+ type: string
+ default: "bar0"
+ aafu1:
+ type: string
+ default : "foo1"
+ aafp1:
+ type: string
+ default : "bar1"
+ aafu2:
+ type: string
+ default: "foo2"
+ aafp2:
+ type: string
+ default: "bar2"
+ aafu3:
+ type: string
+ default : "foo3"
+ aafp3:
+ type: string
+ default : "bar3"
+
+node_templates:
+ topic00:
+ type: dcae.nodes.ExistingTopic
+ properties:
+ fqtn: { get_input : topic00fqtn }
+
+ topic01:
+ type: dcae.nodes.ExistingTopic
+ properties:
+ fqtn: { get_input : topic01fqtn }
+
+ hw_cdap_app:
+ type: dcae.nodes.MicroService.cdap
+ properties:
+ service_component_type:
+ 'hello_world'
+ jar_url: { get_input : hello_world_jar_url }
+ artifact_name: "HelloWorld"
+ artifact_version: "3.4.3"
+ namespace: "cloudifyhwtest"
+ programs:
+ [{"program_type" : "flows", "program_id" : "WhoFlow"}, {"program_type" : "services", "program_id" : "Greeting"}]
+ streamname:
+ 'who'
+ service_endpoints:
+ [{"service_name" : "Greeting", "service_endpoint" : "greet", "endpoint_method" : "GET"}]
+
+ #special key for CDAP plugin
+ connections:
+ streams_publishes:
+ - name: topic00 #MR pub 1
+ location: mtc5
+ client_role: { get_input: client_role }
+ type: message_router
+ config_key: "myconfigkey0"
+ aaf_username: { get_input: aafu0 }
+ aaf_password: { get_input: aafp0 }
+ - name: topic01 #MR pub 2
+ location: mtc5
+ client_role: { get_input: client_role }
+ type: message_router
+ config_key: "myconfigkey1"
+ aaf_username: { get_input: aafu1 }
+ aaf_password: { get_input: aafp1 }
+ streams_subscribes:
+ - name: topic00 #MEANT FOR DEMO ONLY! Subscribing and publishing to same topic. Not real example.
+ location: mtc5
+ client_role: { get_input: client_role }
+ type: message_router
+ config_key: "myconfigkey2"
+ aaf_username: { get_input: aafu2 }
+ aaf_password: { get_input: aafp2 }
+ - name: topic01
+ location: mtc5
+ client_role: { get_input: client_role }
+ type: message_router
+ config_key: "myconfigkey3"
+ aaf_username: { get_input: aafu3 }
+ aaf_password: { get_input: aafp3 }
+
+ relationships:
+ - type: dcae.relationships.publish_events
+ target: topic00 #MEANT FOR DEMO ONLY! Subscribing and publishing to same topic. Not real example.
+ - type: dcae.relationships.publish_events
+ target: topic01
+ - type: dcae.relationships.subscribe_to_events
+ target: topic00
+ - type: dcae.relationships.subscribe_to_events
+ target: topic01
+
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ create:
+ inputs:
+ connected_broker_dns_name: { get_input: connected_broker_dns_name }
+
+outputs:
+ hw_cdap_app_name:
+ value: {get_attribute:[hw_cdap_app, service_component_name]}
+
+ topic00_data:
+ description: "Topic 00 data"
+ value: { get_attribute: [hw_cdap_app, topic00]}
+
+ topic01_data:
+ description: "Topic 01 data"
+ value: { get_attribute: [hw_cdap_app, topic01]}
+
diff --git a/cdap/pom.xml b/cdap/pom.xml
new file mode 100644
index 0000000..d31c06b
--- /dev/null
+++ b/cdap/pom.xml
@@ -0,0 +1,283 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <!--parent>
+ <groupId>org.onap.oparent</groupId>
+ <artifactId>oparent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent-->
+ <parent>
+ <groupId>org.onap.dcaegen2.platform</groupId>
+ <artifactId>plugins</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.onap.dcaegen2.platform.plugins</groupId>
+ <artifactId>cdap</artifactId>
+ <name>cdap-plugin</name>
+ <version>1.0.0-SNAPSHOT</version>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <sonar.sources>.</sonar.sources>
+ <!-- customize the SONARQUBE URL -->
+ <sonar.host.url>http://localhost:9000</sonar.host.url>
+ <!-- below are language dependent -->
+ <!-- for Python -->
+ <sonar.language>py</sonar.language>
+ <sonar.pluginName>Python</sonar.pluginName>
+ <sonar.inclusions>**/*.py</sonar.inclusions>
+ <!-- for JavaScaript -->
+ <!--
+ <sonar.language>js</sonar.language>
+ <sonar.pluginName>JS</sonar.pluginName>
+ <sonar.inclusions>**/*.js</sonar.inclusions>
+ -->
+ </properties>
+
+ <build>
+ <finalName>${project.artifactId}-${project.version}</finalName>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>sonar-maven-plugin</artifactId>
+ <version>2.7.1</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
+ <plugins>
+ <!-- plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4.1</version>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly/dep.xml</descriptor>
+ </descriptors>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin -->
+
+ <!-- first disable the default Java plugins at various stages -->
+ <!-- maven-resources-plugin is called during "*resource" phases by default behavior. it prepares the resources
+ dir. we do not need it -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+
+ <!-- maven-compiler-plugin is called during "compile" phases by default behavior. we do not need it -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+
+ <!-- maven-jar-plugin is called during "compile" phase by default behavior. we do not need it -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.4</version>
+ <executions>
+ <execution>
+ <id>default-jar</id>
+ <phase/>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- maven-install-plugin is called during "install" phase by default behavior. it tries to copy stuff under
+ target dir to ~/.m2. we do not need it -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+
+ <!-- maven-surefire-plugin is called during "test" phase by default behavior. it triggers junit test.
+ we do not need it -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.12.4</version>
+ <configuration>
+ <skipTests>true</skipTests>
+ </configuration>
+ </plugin>
+
+
+ <!-- now we configure custom action (calling a script) at various lifecycle phases -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2.1</version>
+ <executions>
+ <execution>
+ <id>clean phase script</id>
+ <phase>clean</phase>
+ <goals><goal>exec</goal></goals>
+ <configuration>
+ <executable>${session.executionRootDirectory}/mvn-phase-script.sh</executable>
+ <arguments>
+ <argument>${project.artifactId}</argument>
+ <argument>clean</argument>
+ </arguments>
+ <environmentVariables>
+ <!-- make mvn properties as env for our script -->
+ <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID>
+ <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID>
+ <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION>
+ <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY>
+ <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL-->
+ </environmentVariables>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>generate-sources script</id>
+ <phase>generate-sources</phase>
+ <goals><goal>exec</goal></goals>
+ <configuration>
+ <executable>mvn-phase-script.sh</executable>
+ <arguments>
+ <argument>${project.artifactId}</argument>
+ <argument>generate-sources</argument>
+ </arguments>
+ <environmentVariables>
+ <!-- make mvn properties as env for our script -->
+ <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID>
+ <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID>
+ <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION>
+ <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY>
+ <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL-->
+ </environmentVariables>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>compile script</id>
+ <phase>compile</phase>
+ <goals><goal>exec</goal></goals>
+ <configuration>
+ <executable>mvn-phase-script.sh</executable>
+ <arguments>
+ <argument>${project.artifactId}</argument>
+ <argument>compile</argument>
+ </arguments>
+ <environmentVariables>
+ <!-- make mvn properties as env for our script -->
+ <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID>
+ <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID>
+ <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION>
+ <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY>
+ <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL-->
+ </environmentVariables>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>package script</id>
+ <phase>package</phase>
+ <goals><goal>exec</goal></goals>
+ <configuration>
+ <executable>mvn-phase-script.sh</executable>
+ <arguments>
+ <argument>${project.artifactId}</argument>
+ <argument>package</argument>
+ </arguments>
+ <environmentVariables>
+ <!-- make mvn properties as env for our script -->
+ <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID>
+ <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID>
+ <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION>
+ <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY>
+ <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL-->
+ </environmentVariables>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>test script</id>
+ <phase>test</phase>
+ <goals><goal>exec</goal></goals>
+ <configuration>
+ <executable>mvn-phase-script.sh</executable>
+ <arguments>
+ <argument>${project.artifactId}</argument>
+ <argument>test</argument>
+ </arguments>
+ <environmentVariables>
+ <!-- make mvn properties as env for our script -->
+ <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID>
+ <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID>
+ <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION>
+ <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY>
+ <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL-->
+ </environmentVariables>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>install script</id>
+ <phase>install</phase>
+ <goals><goal>exec</goal></goals>
+ <configuration>
+ <executable>mvn-phase-script.sh</executable>
+ <arguments>
+ <argument>${project.artifactId}</argument>
+ <argument>install</argument>
+ </arguments>
+ <environmentVariables>
+ <!-- make mvn properties as env for our script -->
+ <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID>
+ <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID>
+ <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION>
+ <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY>
+ <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL-->
+ </environmentVariables>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>deploy script</id>
+ <phase>deploy</phase>
+ <goals><goal>exec</goal></goals>
+ <configuration>
+ <executable>mvn-phase-script.sh</executable>
+ <arguments>
+ <argument>${project.artifactId}</argument>
+ <argument>deploy</argument>
+ </arguments>
+ <environmentVariables>
+ <!-- make mvn properties as env for our script -->
+ <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID>
+ <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID>
+ <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION>
+ <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY>
+ <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL-->
+ </environmentVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>