From 647addf5d6c78b2b8c941cc9cd8c57a3eb9f30b4 Mon Sep 17 00:00:00 2001 From: Tommy Carpenter Date: Tue, 22 Aug 2017 18:07:40 -0400 Subject: [PATCH] [DCAEGEN2-42] Initial commit of broker Change-Id: I1c553c82d5b39a4c134c44e2320ac0e44785e0ef Signed-off-by: Tommy Carpenter --- .gitignore | 20 + .gitreview | 4 + Changelog.md | 107 +++ Dockerfile | 30 + LICENSE.txt | 31 + README.md | 131 +++ bin/build_and_check.sh | 5 + bin/build_and_run.sh | 8 + bin/build_and_test.sh | 12 + bin/build_and_unit_test.sh | 5 + config/sys.config | 86 ++ config/vm.args | 9 + config_template.json | 1 + doc/cdap_broker.png | Bin 0 -> 351432 bytes entry.sh | 20 + get_version.sh | 3 + rebar.config | 74 ++ src/application.hrl | 28 + src/cdap_interface.erl | 363 ++++++++ src/cdap_interface_tests.erl | 34 + src/cdapbroker.app.src | 23 + src/cdapbroker_app.erl | 94 ++ src/cdapbroker_sup.erl | 55 ++ src/consul_interface.erl | 139 +++ src/httpabs.erl | 118 +++ src/httpabs_tests.erl | 33 + src/logging.erl | 157 ++++ src/resource_handler.erl | 465 ++++++++++ src/util.erl | 192 ++++ src/util_tests.erl | 53 ++ src/workflows.erl | 324 +++++++ src/workflows_tests.erl | 27 + swagger/swagger.html | 1899 ++++++++++++++++++++++++++++++++++++++++ swagger/swagger.json | 560 ++++++++++++ swagger/swagger.yaml | 418 +++++++++ test/apitest/apitest_SUITE.erl | 826 +++++++++++++++++ 36 files changed, 6354 insertions(+) create mode 100644 .gitignore create mode 100644 .gitreview create mode 100644 Changelog.md create mode 100644 Dockerfile create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100755 bin/build_and_check.sh create mode 100755 bin/build_and_run.sh create mode 100755 bin/build_and_test.sh create mode 100755 bin/build_and_unit_test.sh create mode 100644 config/sys.config create mode 100644 config/vm.args create mode 100644 config_template.json create mode 100644 doc/cdap_broker.png create mode 100755 entry.sh create mode 100755 get_version.sh create mode 100644 rebar.config create mode 100644 src/application.hrl create mode 100644 src/cdap_interface.erl create mode 100644 src/cdap_interface_tests.erl create mode 100644 src/cdapbroker.app.src create mode 100644 src/cdapbroker_app.erl create mode 100644 src/cdapbroker_sup.erl create mode 100644 src/consul_interface.erl create mode 100644 src/httpabs.erl create mode 100644 src/httpabs_tests.erl create mode 100644 src/logging.erl create mode 100644 src/resource_handler.erl create mode 100644 src/util.erl create mode 100644 src/util_tests.erl create mode 100644 src/workflows.erl create mode 100644 src/workflows_tests.erl create mode 100644 swagger/swagger.html create mode 100644 swagger/swagger.json create mode 100644 swagger/swagger.yaml create mode 100644 test/apitest/apitest_SUITE.erl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27bdf03 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +build_and_cover.sh +Mnesia.nonode@nohost/ +rebar3.crashdump +.DS_Store +.rebar3 +rebar.lock +_* +.eunit +*.o +*.beam +*.plt +*.swp +*.swo +.erlang.cookie +ebin +log +erl_crash.dump +.rebar +logs +_build diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..0699f50 --- /dev/null +++ b/.gitreview @@ -0,0 +1,4 @@ +[gerrit] +host=gerrit.onap.org +port=29418 +project=dcaegen2/platform/cdapbroker.git diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..0794b83 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,107 @@ +# 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/). + +## [4.0.2] - July 26 2017 +* Make testing magical so that it runs on localhost or in Docker the same +* Code cleanups in workflows thanks to abstraction provided by Garry + +## [4.0.1] - July 7 2017 +* Work with config binding service 1.0.0. + +## [4.0.0] - June 28 2017 +* Policy reconfiguration work. There are two new reconfiguration endpoints: smart and app-preferences. +* The smart interface allows you to send a JSON of keys that are either in app_preferences, app_config, or both. The broker figures out the overlaps, refreshes them in Consul, and makes the appropriate CDAP reconfiguration calls. The preferences API allows you to simply reset a CDAP app's application preferences (analagous to the call that was already in here for app_config). +* I broke the original app_config API to make all three reconfiguration APIs consistent. You give it "reconfiguration_type" and "config" for all three APIs. And hopefully for any future reconfiguration APIs, e.g., for hydrator pipelines. +* Hardcodes the cute short name "config_binding_service", now that DCAE is using short names. Obliterates usage of the env variable and removes passing it around all over the place. + +## [3.4.8] - May 16 2017 +* support JARs hosted at https webservers +* trim JAR URLs to prevent problems due to whitespace +* add a primitive get_version.sh script for the build team to use.. needs to be actually implemented instead of printing a fixed version right now.. + +## [3.4.7] - May 15 2017 +* EELF part 6... pretty much done at this point, some less-important logs could still be cleaned up maybe. +* All HTTP requests made from the broker to another HTTP API now include the XER. +* All functions in `src/workflows` are now EELF compliant, and produce detailed metrics logs. Workflows is the workhorse of all the major API calls so this tracks pretty much all requests the broker makes to to it's job. +* App Config reconfiguration is now a workflow + +## [3.4.6] - May 12 2017 +* All HTTP GETs issued by this broker now pass an/the XER... even if the downstream server is not expecting it #ExpectUs.. + +## [3.4.5] - May 10 2017 +* error EELF field implemented, three important Metrics EELF fields added +* src/workflows has no more lager (non EELF) statements... though it could use *more* EELF statements because part of it is not covered by logs.. + +## [3.4.4] - Apr 28 2017 +* four more EELF fields implemented, one ignored. + +## [3.4.3] - Apr 27 2017 +* Fixes audit records not being used at the end of API calls (they now are, and elapsed time is computed) +* Implements ISO8601 timestamps in all log records +* Implements a few more of the EELF fields, still more to go + +## [3.4.2] - Apr 26 2017 +* Towards Implementing the "ONAP logging requirements" aka "EELF": +* Logs are now written to /tmp/log/cdapbroker/... and are in three files: error.log, audit.log, metrics.log (logs are still also written to stdout) +* X-ECOMP-RequestID is now parsed and logged, and generated if missing, for all main broker APIs. It does not yet generate it's own for the call to the CBS. +* EELF logging functions added to a new source file `src/logging`. +* The field list formats and delimiters in each of those follow version 1.0 of the ONAP logging requirements. However, many required fields are left blank right now, this needs to be fixed. Parsing the fields should work though as each has the correct positional arguments and correct number of positions. +* Only functions in `src/resource_handler` are using the EELF logging functions right now, this needs to be fixed + +## [3.4.1] +* Move tests, update README + +## [3.4.0] +* Only healthcheck programs that are part of an intial program-flowlet PUT. The use case for this was a CDAP application that had flows that were purposely not wanting to be started by the component developer (whether that is valid is another question...) + The broker thought their application was in an unhealthy state because it was sourcing the programs to get the health of from CDAP itself, and not the intial PUT request. + This actually goes back to the way healthcheck used to work, but this now does it in a better way, because the application table is now used for multiple types of CDAP apps +* To accomplish the above, this creates a "supplementary" table for program-flowlet apps, that right now stores the programs that are in the intial PUT, but could be extended later with more properties. +* Paves the way for a "hydrator supplemental" table if that is ever needed +* Starts the painful process of adding function and type definitions so that the Erlang Dialyzer ("bolt on" static typing tool) is of some use; sick of huge positional tuples +* Fixes a bug where undeploy would not "plow through" if CDAP was totally unreachable (or gone) + +## [3.3.0] +* Broker now includes it's own API version in information endpoint + +## [3.2.1] +* Fix an error found in HTTP error reporting (a bad request type of error is now correctly caught) +* Fix errors in test cases found while testing a new version of CDAP. Tests are now more agnostic to json key ordering. + +## [3.2.0] +* Returns more information in the "infomation endpoint" ('/'). Specifically, now returns the CDAP GUI port and the CDAP cluster version. +This is mostly to aid component developers in testing that are hitting the broker via the DCAE CLI tool. +* Introduces the first unit test (eunit; the rest of the test suite is ran via common_test). + +## [3.1.0] +* Persistence. This is an important feature. This persists the MNesia database to disk so that you can stop and start the broker without losing state. NOTE: Catching Docker SIGTERM is not yet implemented. It turns out this is non-trivial to do in Erlang. So, in rare cases, if `docker stop` is called immediately after `delete`, the deletion may not persist to the database. +* Erlang 19.3 is supposed to handle SIGTERM at the BEAM level. That is not out yet as Docker (it was just announced a week ago.). +The proper way to shut down an Erlang node is to execute a command to the BEAM. +I don't know what Erlang developers did for 20 years, but to date the BEAM does not handle SIGTERM, so a wrapper script is needed if you want to kill the BEAM gracefully on a SIGTERM. +This was needed because this broker runs in Docker. With database persistence, the broker has a graceful stop function that ensures any transactions in cache (RAM) are persisted to disk before the shutdown. +I need this function called, so I need SIGTERM to be handled in a way that gracefully terminates the VM, which in turn gracefully shuts down my application, which in turn calls this function. Supposedly, this will be no longer necessary soon: http://www.erlang.org/news/110 + +## [3.0.0] +* Waterfall CDAP_CLUSTER_TO_MANAGE +* Handle CBS moving while broker is up +* For program-flowlet apps, return configuration when info requested +* make /application only return the appnames (API change) +* make testing more stable by not using order-dependent Expected JSONs +* Reconfiguring with an invalid request returns a 4xx instead of 5xx now (bugfix) +* Dead programs/flowlets now triggers a failing healthcheck (bugfix) +* Rename "reconfigure_app_config" to make way for reconfiguring preferences (API change) + +## [2.2.0] +* Implements healthchecking for Pipelines based on Terry S's healthCheck.py script + +## [2.1.0] +* Added a text file of some example commands that can be useful for demos and understanding this repo +* Fixed a bug in a workaround for https://issues.cask.co/browse/CDAP-7191?filter=-2 +* Added the ability to deploy Pipelines that contain custom JARs + +## [2.0.0] + +* Add support for primitive CDAP Pipelines. Required an API break because the API caller has to specify whether the application is a program-flowlet style app or a hydrator pipeline. +* Changelog did not exist before this... diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ef4f76e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +FROM erlang:19.2 +MAINTAINER tommy at research dot eh tee tee dot com + +ENV TERM=xterm + +#copy files into repo +ADD src /tmp/src +ADD test /tmp/test +ADD rebar.config /tmp +ADD entry.sh /tmp +ADD config /tmp/config + +WORKDIR /tmp + +#make sure there is no leftover release +RUN rm -rf _build/ + +#build +RUN rebar3 upgrade +RUN rebar3 release + +#fail the docker build if unit tests fail +RUN rebar3 eunit + +#set the broker test type so the integration test can be run inside Docker +ENV BROKER_TEST_TYPE=DOCKER + +#run +EXPOSE 7777 +ENTRYPOINT ["/tmp/entry.sh"] diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..7c1e63a --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,31 @@ +============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/README.md b/README.md new file mode 100644 index 0000000..14aa99c --- /dev/null +++ b/README.md @@ -0,0 +1,131 @@ +# cdapbroker +This repo is the thing in red: +![Alt text](doc/cdap_broker.png?raw=true) + +The high level workflow for how this broker is to be used in the DCAE platform is as follows +
    +
  1. CLoudify wants to deploy a new CDAP app. It deploys it via the broker.
  2. +
  3. This broker registers with Consul and lights up a metrics, health, and configuration change endpoint for the app
  4. +
  5. The broker pushes the app's configuration into Consul for the Ops view layer (documentation purposes) +
  6. At periodic intervals the health endpoints (plural when mutliple CDAP apps are registered), provided by this broker, are pinged by consul
  7. +
  8. At peridic intervals, some metrics system (TBD) pulls then pushes metrics from the apps
  9. +
  10. Occasionaly some higher power decides to update configuration for a running CDAP app. They make the change via the broker.
  11. +
  12. Finally on a service undeploy Cloudify deletes the CDAP app via the broker
  13. +
+ +# Purpose & Responsibilities +The purposes of this broker are as follows: + +1. To isolate CDAP developers from the complexity of the DCAE platform. The only thing CDAP developers should need to interface with are the CDAP APIs. They should not need to know about concepts like "service discovery" or "confiuration discovery". They should specify what external systems they should talk to in their configuration template and the rest should be hidden from them. + +2. To minimize the onboarding process for CDAP developers. Their *only* deliverables should be a JAR (with built in metrics), and their configuration template. + +3. Provide Consul interfacing, metrics, healthchecks, and configuration updates bewtween CDAP applications and the rest of the platform. Specifically, this has northbound interfaces for +
    +
  1. providing initial configuration of a CDAP app
  2. +
  3. changing configuration of a CDAP app
  4. +
  5. getting the custom metrics of a CDAP app
  6. +
  7. healthchecking a CDAP app
  8. +
+ And talks to the CDAP APIs in various ways southbound to achieve these objectives. + +# CDAP service discovery +When registering an application (`appname`) with the broker, the broker registeres *itself* as the Address and Port of that CDAP application. That is because a CDAP application can have multiple services behind it, so there is no way to register a CDAP application in Consul. + +The CDAP client library for collectors (or anything upstream of a CDAP app) will be required to do the following: + +1. do a consul service discovery GET on `appname` +2. Take that serviceaddress and port, and form `serviceaddress:port/application/appname` +3. Do a GET on that, which is the broker +4. Parse out `connectionurl` and `serviceendpoints`, which is input and output connection information for the CDAP app. See the swagger spec (in the swagger folder in this repo) for the schema of those. + +# Special charcters: hackaround +CDAP application names cannot have special characters in them. +When this broker talks southbound to CDAP, it maps `APPNAME` into `APPNAME_WITHOUT_SPECIAL_CHARACTERS`. So in CDAP you will see the latter. However, + when communicating with this broker API, you should still pass in `APPNAME`. The conversion is handled internally. + +# Logs +The broker conforms to ONAP/ECOMP logging requirements (aka EELF). The logs are written to `/tmp/log/cdapbroker/..`. If running in Docker, you'll want to mount this outside into a safe store. + +# Running and testing + +## Runtime Assumptions +In a real deployment setting, these assumptions are handled by the ONAP Docker plugin when this is launched. +When doing local testing, you must set up these assumptions yourself. + +1. `HOSTNAME` is set as an env variable in this runtime environment and is a Consul key that holds this broker's configuration. + +2. `CONSUL_HOST` is set as an env variable and is either an IP address or a resolvable name (Via real DNS whereever you are running this). It should not include the port, the broker currently hardcodes 8500. + +3. `CDAP_CLUSTER_TO_MANAGE` is an env variable, and cooresponds to a CDAP cluster registered in `CONSUL_HOST`. This is the CDAP cluster the broker will manage when it runs. The CDAP API port must be registered as well, that is, the broker does *not* hardcode "well known ports" and retrieves it from Consul. (Currently for CDAP 3 that port is 10000 and CDAP 4 it is 11011.) + +4. `CONFIG_BINDING_SERVICE` is set as an env variable, and cooresponds to the name that the CBS is registered in `CONSUL_HOST`. + +5. The user that runs this application needs write access to the directory '/var/mnesia'. This works in Docker, but on your local machine, this may not be owned by your local user.In this case, create the dictory and CHOWN it to your user. The broker writes it's database backup to that location. + +## The integration test suite +Bestides the unit tests, the broker comes with an integration suite that touches both Consul and CDAP (the ones pointed to via `CONSUL_HOST` and `CDAP_CLUSTER_TO_MANAGE`. It will actually deploy test apps, test configurations into Consul, and then delete them after the test suite is over. Please note that this is not a unit test, it touches the real systems the broker is connected to. It can be used to verify a signifigant portion of the DCAE, including CDAP, Consul, the broker, and the config binding service. + +The integration test suite requires several test artifacts to be loaded into a Nexus Raw Webserver. In the test suite, the root of this server is read from the env `NEXUS_RAW_ROOT`. Thus, in order to run the integration suite, in addition to the above runtime assumptions, this env must be set. +(TODO: Talk about the specific artifacts to be loaded in) + +## Docker + +### Build +Note: doing a Docker build *automatically* runs the unit tests. In fact, the docker container will fail to build if any unit tests fail. + + docker build --rm -t cdapbroker:VERSION . + +### Run + + docker run -v /tmp/log/cdapbroker/:/tmp/log/cdapbroker/ -d -e CDAP_CLUSTER_TO_MANAGE="cdap_cluster" -e HOSTNAME="cdap_broker" -e CONSUL_HOST="XXXX" -e CONFIG_BINDING_SERVICE="config_binding_service" -p 7777:7777 DOCKER_REGISTRY/cdapbroker:VERSION + +(Fill in `CONSUL_HOST` and `DOCKER_REGISTRY`) + +### Running the Integration Suite in Docker + + docker exec -it CONTAINER_ID_HERE /bin/bash + export NEXUS_RAW_ROOT=XXXX + rebar3 ct + +## Local Development +The below is for building, running, and testing on your local machine. This requires Erlang 19+ and rebar3 on your machine. These scripts require the runtime assumptions mentioned above. + +### Running locally +To use this script, you will have to modify `CONSUL_HOST` for your enviornment. + +./bin/build_and_run.sh + +### Running the integration test suite +To use this script, you will have to modify `CONSUL_HOST` and `NEXUS_RAW_ROOT` for your enviornment. + + ./bin/build_and_test.sh + +### Running the unit tests + + ./bin/build_and_unit_test.sh + +### Running the Dialyzer +This is a type checking tool that attempts to find errors based on types. +Warning, right now very few things are typed/specs, so the usefulness of this is limited: + + ./bin/build_and_check.sh + +# On "Leave No Trace" +The CDAP broker does not currently implement "leave no trace", because it is not really clear in DCAE when this should be done, or whether the orchestrator should be allowed to invoke such deadly operations, i.e., maybe this should be done by an operations team. +Leave No Trace here means deleting streams and datasets after an application is deleted from the broker. +The problem is that streams and datasets can be shared between applications, like a shared Kafka queue used by two CDAP applications. +Streams and datasets are created by the CDAP deployment API when an application that uses a streamname or a dataset name for the first time, however subsequent apps can be deployed using those, without re-creating them. +Moreover, subsequently deployed apps may be *expecting* that data already exists in some dataset. +Consider the case of deplyoying A1 that creates S1, then deploying A2 that uses S1, then wanting to undeploy A1. Deleting the stream or it's data on the deletion of A1 would clobber A2. + +This leaves the question of who/what/when/where/why/how streams and datasets should be cleaned up from CDAP clusters in DCAE. +For now, this is an open question. It can always be done on the CDAP management interface by an operations team in the meantime. + +# On Version Bumping (Development) +Currently the CDAP Broker Version is in four places in this repo.. +1. rebar.config +2. src/cdapbroker.app.src +3. get_version.sh (could be made smarter, parse rebar.config) +4. swagger spec +If you make a developmemt change, please bump in all places until this is resolved.. diff --git a/bin/build_and_check.sh b/bin/build_and_check.sh new file mode 100755 index 0000000..7d8b4e1 --- /dev/null +++ b/bin/build_and_check.sh @@ -0,0 +1,5 @@ +#!/usr/local/bin/fish +rm -rf _build/; +rebar3 upgrade; +rebar3 release; +dialyzer -r _build/default/lib/cdapbroker/ebin/ diff --git a/bin/build_and_run.sh b/bin/build_and_run.sh new file mode 100755 index 0000000..8d48716 --- /dev/null +++ b/bin/build_and_run.sh @@ -0,0 +1,8 @@ +#!/usr/local/bin/fish +rm -rf /tmp/log/cdapbroker/*; +rebar3 release; +set -x CDAP_CLUSTER_TO_MANAGE "cdap"; +set -x CONSUL_HOST "XXXX"; +set -x CONFIG_BINDING_SERVICE "config_binding_service"; +set -x HOSTNAME "cdap_broker"; +./_build/default/rel/cdapbroker/bin/cdapbroker diff --git a/bin/build_and_test.sh b/bin/build_and_test.sh new file mode 100755 index 0000000..b0456f4 --- /dev/null +++ b/bin/build_and_test.sh @@ -0,0 +1,12 @@ +#!/usr/local/bin/fish +rm -rf /tmp/log/cdapbroker/*; +rebar3 release; +set -x NEXUS_RAW_ROOT "XXXX"; +set -x CDAP_CLUSTER_TO_MANAGE "cdap"; +set -x CONSUL_HOST "XXXX"; +set -x CONFIG_BINDING_SERVICE "config_binding_service"; +set -x HOSTNAME "cdap_broker"; +set -x REBAR3_ERL_ARGS "-sname cdapbroker@localhost"; +rebar3 local install; +env DEBUG=1 ~/.cache/rebar3/bin/rebar3 ct; +rebar3 eunit diff --git a/bin/build_and_unit_test.sh b/bin/build_and_unit_test.sh new file mode 100755 index 0000000..7a2c757 --- /dev/null +++ b/bin/build_and_unit_test.sh @@ -0,0 +1,5 @@ +#!/usr/local/bin/fish +rm -rf _build/; +rebar3 upgrade; +rebar3 release; +rebar3 eunit diff --git a/config/sys.config b/config/sys.config new file mode 100644 index 0000000..3b8edc0 --- /dev/null +++ b/config/sys.config @@ -0,0 +1,86 @@ +[ + {sasl, [{utc_log, true}]}, + + %% {size, 10485760}, {date, "$D0"}, {count, 5} -> This tells lager to log error and above messages to error.log and to rotate the file at midnight or when it reaches 10mb, whichever comes first, and to keep 5 rotated logs in addition to the current one + + {lager, [ + {colored, true}, + {log_root, "/tmp/log/cdapbroker"}, + + %%Any logs just starting with lager: will go into stdout and cdapbroker.log. These are the default for non-EELF caught logs + {handlers, + [ + {lager_console_backend, info}, + {lager_file_backend, [{file, "cdapbroker.log"}, + {level, debug}, + {formatter, lager_default_formatter}, + {size, 10485760}, + {date, "$D0"}, + {count, 5}, + %% Message will hold the delimited fields that the logging standard actually wants + {formatter_config, [message, "--", module ,":", function, ":", line, "\n"]} + ]} + ] + }, + %%EELF logs have special sink names: error:, audit:, metrics:, and optionally debug: + %%these sinks will log to their respective files, and for sanity reasons, stdout as well + {extra_sinks, + [ + {audit_lager_event, + [{handlers, + [ + {lager_console_backend, debug}, + {lager_file_backend, + [{file, "audit.log"}, + %regarding level, we want the lowest becaue audit:anything will show up in audit.log + {level, debug}, + {formatter, lager_default_formatter}, + {size, 10485760}, + {date, "$D0"}, + {count, 5}, + %% Message will hold the delimited fields that the logging standard actually wants + {formatter_config, [message, "--", module ,":", function, ":", line, "\n"]}] + } + ] + }] + }, + {metrics_lager_event, + [{handlers, + [ + {lager_console_backend, debug}, + {lager_file_backend, + [{file, "metrics.log"}, + %regarding level, we want the lowest becaue metrics:anything will show up in metrics.log + {level, debug}, + {formatter, lager_default_formatter}, + {size, 10485760}, + {date, "$D0"}, + {count, 5}, + %% Message will hold the delimited fields that the logging standard actually wants + {formatter_config, [message, "--", module ,":", function, ":", line, "\n"]}] + } + ] + }] + }, + {error_lager_event, + [{handlers, + [ + {lager_console_backend, debug}, + {lager_file_backend, + [{file, "error.log"}, + %regarding level, we want the lowest becaue error:anything will show up in error.log + {level, debug}, + {formatter, lager_default_formatter}, + {size, 10485760}, + {date, "$D0"}, + {count, 5}, + %% Message will hold the delimited fields that the logging standard actually wants + {formatter_config, [message, "--", " [",severity,"] ", module ,":", function, ":", line, "\n"]}] + } + ] + }] + } + ] + } + ]} +]. diff --git a/config/vm.args b/config/vm.args new file mode 100644 index 0000000..cbe012c --- /dev/null +++ b/config/vm.args @@ -0,0 +1,9 @@ +# only show the programmed prompt +-noshell + +## Name of the node +-sname cdapbroker@localhost + +## Cookie for distributed erlang +-setcookie cdapbroker + diff --git a/config_template.json b/config_template.json new file mode 100644 index 0000000..1775b8f --- /dev/null +++ b/config_template.json @@ -0,0 +1 @@ +{"autoderegisterafter": "10m", "cdap_cluster_to_manage": "{{cdap_cluster}}", "bindingttw": 5, "hcinterval": "5s"} diff --git a/doc/cdap_broker.png b/doc/cdap_broker.png new file mode 100644 index 0000000000000000000000000000000000000000..712cdc22da4845b7df4b6c6e918cbb94b3c802cb GIT binary patch literal 351432 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 z z@L+%P_VlEeFFfesb5DxnHj>EoBlsPMZNIsZF4vENP(Q{->~p46qFgm{u2`1Jlqp5U z9c;+NKu=5g;x|ezds0F?G0gFwkG#nSy9@V;`o?6;JURvP;XI@!B@hQ?iqr{bM^}$+ zVoW)^2iu$b+XPWR6Y5s5t-jW5nBTTZW8b)Q=MJ@M)r$DVpLXrqMU5LbP9MMK=H5a- z|KpE8(uNHisAbERv}eyAGBwrifFM59la8zyL4%i_rMSeDtl88tqB0+~p{>VuQ}Z$w zq^F%mmh~R0ej$lMJnzz$pLUW*a!PuLM#kx2uQ0Q7q7DN`Q;Q1Lq%Y!Z31QxJV)Z2I zzvwTD&0aRLpo-P{)84bosFs6*3aI70&OTBo*!3bU@B2Beco0KLZ@ZNA<2t4#sb<&3 zbo|#|RNTbi9r}L?g}B|ImHqqClG|RCn3k>oRX9hRK3MG`tA3r zRMpx@r9TMi9OiU}h^0eTRISb++WGe)s%c*kew9rA56{r@fxT(f{YWKWGP0{kpN;s5 zcFb;1R@|40eNy8B>B6B^^!d9!LhX2jyH;Vz5HxN2rSfYv$0T)yF9;Iw9M+4pgtjVETFM6spB(<#nu~!*gf4Jhvun z@A}WtV)|E%mumTLCMG611uUX?pOWB`I^+bHbm zAJnjVKXT7*C4B{1c3MrZ{v5)u>e3%=0}#aRE-u)WHjEoe6Zc&ezcG&}jLdDxrFD1u zYS?J%_gM`x)56mlRr#ugoL~fAd zuJ;#!5GEw!$?y3Sx^w*sU3>JB0t5WX_mvmDeDZ?Ac>;vjyQWWiW}k}|CdCCXS4RMc z4eY2w)v{F5u>=(>QH+XJuS;#})uCz?OOi=WqvRZ|ujvWGWNi%jzIaA=u3e{_Pud+C{wRr$|o%)kc3LVQ^cY4n4ADlsaEp4`7lSI%6c7r_DK=jTU0-hTAl$DdMC z+2{BrLI44>PQeLv!*#^Ir_bQNZHWq0hQXoYj>V}&2}i2mtUcAMRfURM80YaN2$T>R zM3=U$p>zHTl$>qCQs2aq%D3)E0~(bfLp8?<8rdh?$tm$s9 zD)k%FlggN>o;*!WjN$(FZ`yY3F8f)w$pIZ>vbL*7gU7U|VkSicgeZytL~=|JUEaHZ z{x@zT#l~kx+jYpHOjVk_?HG+{R=PlZE3>O1Ihvkb`GflQ{f0c_60)^DB8Re-X~u?w z)W41+PmE^1^7Z#Z3qWv5qWzxG-g*6L{PqVFpS=y~no-4C-D$_+mDIq|Tn!*kx$N55 z!;u>F?CPI1yvu015*DL0(PivVk=joFm9~#>!4qa;{jX{OLdT{Y)gAUT9s9Ne*-K20 zYoi<)X{ZDs^zEryv(fb1{+U$Grsx0=NRFaMXMdyNy(iF(hy=>^Xdvq{)o9TCt+cRj z9pWgb3{zzJF9Q%+%#p*7*8s%Yab4(#b0PqQB?A!s8Gu+;Q~(H~#4ry!w(UFm@|#^0 zmyn#T{JK=OW)qsdb`O2oz^UM$0g0h>?f6a_G3E#IiBD8|29&GWh^GI%jk>uwFbJJ3 z>-@7Y0T5u|;Ks3SG9!P>lam`eXGRn!Nll zg)4z75|`!2Ze3$4U#Bfi|8XhxYf^zsb65bQ8i25;`V2s<+Bu7Am$b|g%*c=8J?@^zuis3=$N}BaytXs!Y;9m^Va|eWMxs2V zQhlhP6=JL~fw_ehtnG`zsdh7T8!!rUzT1gQPkfM|B4j&nHIw=3G^8X&!|mp2teHCl zBfsp1W;Lt8-j2&;ZUzN&YV#T=Nk7Y8Hla*LTqZLvlZ}0Gl&sSVJqM4$obNZ_!hH|K zYq3m8v0=EdZU{;{6@#sqkOg*GJSUj^ua`Qb+u;IC1P^NSV<$RQ= z2$wfSsqRzNK(r3Xt z6EibdT3MsGQz^9Q& zI8~{IRp&ia`jJe*q=_G;An?g)%xf*>(-qKY^gaZ~=XOk@NnW&bZYqy~F7Evf<+-2b zMeIs_t$E2B82rn5@MO1kZm2;j$&o%d`s-v^i1tAysNSd_PI*MIps;wNg^7YGF3=5o zzUv1oQLPq2xmr!}>m@IhZ564klX&${46k1X9D%Gb01LYhDqO&vWq_F8q6C3Z}weM{*7e-U7mkzC!zX?*It4bV|G**0!sx-a|u2 z4~BIo;ZcNU5B-7zAar41R2%DWx#NYqJKPImb8~~ct1CPLwI@ORK?4x1ED{@V9z8?` zokRvaxaf|Hp{fyx`~V<$S_DZkLAbEzTeNmo9uU77RPm&rfx-&KOEkxqqo?7!9mnv< zBM541W-`bb7a53qmyTi9l+pOSi8CzCl!f3k?x$y9j2d0X;nK749A8rNvtxa)00;pD z3w(kbg-;Yb>Udp*RyZ)ajix6e?em;-}aTqXm3_4<<`)fZ-~mZ7p*XXw4-1b<Ps+o@dd}ugWdP#I=_L#Zh_p*% z8YLm8VF1GaA%5y;4r39aNE2Hp3|fDk0SL{;3YqPp$@j#F032W3Q^G$?QL6k9 zTn~uLQMW2F!XJPC&`mm>3d7V&N0Yqg=eb1@fIw;jeC{1a@6x6)5aD~)F|Tl=POhipeoD&L~3FL9-LT(k4+UKLe#{ID@vpD z=>6#e;00{<|EePeVJ~iCNn01@h8N=*SD<{gZaD514yM+Y_@pAt>lT*xswmERZcz#~ zN9=$f0}usK#+U$i?40o#3&83rKZnhn@bRGacoma#UJ4HYk<63f7cjeJ6$W_3>c|9@ zYW2pcmt03G3@if>67DOy`~3qTkP-vebKB9`$wYMgqif=bhP@WzVF>rND*Q;)TzT9X z8~6-6=J$lcNMtN(=!klq7vW*J^fRE)01#|8@1OQ0J3TIQb-iMb}kVwhTbnqjv4u=?kk96N`#QjOsd- zkIELvtp#KXChnyrKU$_>67Iud)Z~6(4pr{?qvUNf4(RF|P@5ml&|edqk+D=XUdG9p z{udkt6ER1#Db?@RgQ}V^FJY!U|=$%zyj8%e?bKJ?P<0bRf6POq5q z=by`WDLyueViS}pXVUMeZ%AhKd(eu7v#5X5kB9}^vS*~ge!njiOli#R@B8#$TJ`Hr zx_;s~-49Hlxae5Q9t5r}!|Lc5l8Kci)ArP&POY0#p8-RuNtNQHmjkb{CihQc|MI$f zhSqP}OBeq-Nl&9=C?+a>JzY#Wfym9B2W3_6p??GvM}v zKUtKaT74GM@fAI(m_jvmTw&3GNKFW*yQj9%n89=DR(K3kIcBpN>qgb;I)e_Z9>#Sf zZC{y!DVyC?{#1j4sUK4?EiXD0OvLYjL9Ul+{j}k<=x;aTK!>arU^>LIwLhcTt5?y0 zdZoyq0B9axXCRG&-LKHb*~4kU!Dmdk@y@>8b#4691Sd^oty=T&{r30z7g;al)h1hsdJr<8nu3Y- zI9d#$RXb);ol-IdQ|>EFzEZY85wSpSk&A-3?tP4a5LR}_`dviF$~mp36zCipVYh39 z#w&vgE&@U*1FwWNw}ho-!EM%d4(Pi6uGU=egN}gU)#tJP|Dub;ifcm?D-7NHSf#D= zCj#R2Ez{DH5f%6phgXhO9SM=1|JSR+Etvkq-k~@eG;N3OeFk9Is4*BnaWW=Por)=w zCSk(3u^2gQFnV_BfF?}yV{2p0tE&~lh+BHoGlZgHUwr%LRRqVWjtEg{EG->;A0i-F z#1?Ls_F_c8wy?Ff5M9}=vQAXhm&#*;pP0aoSEhFvIvEGAdufeEC^<0-_fKrc$X=hJ zn5`9zI8q>g%8=bxb)d_XX?Dd+qSK&B*m>R+anj3DbM(U35fJ?(R;Fj%o9}64iSqv& zj?>SAwPwTYnaeQ(qPu1h5UI)W@VtElBYJ%bd-gkn0;!|d^D8G}m>J!ZeIG51{QwmeAA9=yTrwH+Cq8&Oe<; zgbG@a!W;o1ybHvIyu|Mdd-95Wk=4DV3yTufF=EqYL={kE)7!dAL^g5))zSOQuV4|Rq3mJEG+@v_l{y{6-%Zr zdFw|R&u0Uh@@PH%AVSp$pDi2_5Gjawbq8yQwE*iMiH>mq91Vl1Io?piD0Zm|GAl_DOoaY-BGpW&NROq)pl3l@M-9>`~uA;13XG4)8d zH8KDpQuVpmmC8KH_c6MRcs=Uso1ki!tq4=`j+vhTgixT@AjC5q-#883n>(v)H*b87 zCl!s11-^U>SXo=c#^yiXbQ>G~ZVfAeS44rGEO{ZQMHs)(gnK2V{=6;KBzkR*Un==P9 zrcK7!;e*h%bz_v(*Au0+c#|Gapa>K>7Iuzk-ESg}Kgz3?0c(gPgyZ&+pD?gPJ=j{B za{A(J>P;TFOhy$x#wVZm!dG0TsnaCNG-?pKw{MB+W%LKz~q;Cl0 zinX|YdSLMIF_<)UI%dwEi@Ac&&7Y5X^XB238B;NS%vboLV{=q0#y*!rowGF&U)zJvoJ~Y0dUSM6P^Nkx?7NrOep3C)N{H~n z(VxG7oteHUFS&i$%J}ir3vk4SWTJ%|fB;f?g6+}S4QN$L0bW$BG`7)ISfYC8vACpy z<6N@vc{m{G?mWA+108DGKwpe!T;CiOn+?U87hx(VoP;bSM*8B!x>1tgmIL>(i%z+z ztj9bQ<;|sOiQ%|+{1?=ape`|Ys*IuQE+Iw@u%|Ep5Xo_&xcS#|d{V)ZX>-IDI+&tj z&3-uaBq+zl0Wtvb#!b}t@_qskX-o-s=fqmHEGN+yG1X4>rXz6ZabS-Aq=pgII7I+K zA7R&m4zMv51851QT^eKczg{Z)j=}&yB*g^c;%^Jlyqtw-KTl-AS{6fbJbfXLv}t04 z+_8J%m#{V!p(G?r)Mz{sC)`4jl*)Qz%rC38jmOP?kIvxRUUgZEL!>TveBj)$C$?RB zfmjuQvtx$?_z`a~%U-&z!JkK>-wnj85IKnP_LK!|7-+q-mV6UO#w z2YVH5=gkCfp3l*Rp>bvO9y=5J&ptpPgAciz&egnDa=M}@0}w*w!?TNfFrY(ySelB7 zi@xZ2&?5a&!%0U#=ad9(stlT-@ue6~(`44}f5>HNq47=k|f4 ztvT0`*rW~Hkab?nYPP|^@w2dKi%>sTasQDkUV6TQkDovM1)mEFLO@^ud|!Fux$Avg zI(rmbei3}GHyTzd&ORrRHrq>A*9avlcEpk+Pc^6;8GsP?j>5IKr~(kes@_Py2Us(* zp#&(e3lqz7=ssZ&JfiXkXv|WRDe>@na0ES?+e2SZtSyK}80g&lwZ zN1!q-5LOIq!Ws!8D`UAYw=DJ%M$S22fGdxa5y5#{^JP2On23WvruOB~=er{aR71NV zH6e_F`K74H8a_sbdb-zlbG1KF)TPjMNBwYVO18L$L_?dsKgu>&By?RCeHMJ0uaKyM6mls zEFMq?Mh0SfBHR}_)WDFr2k|Oelf@I7*!JzYOudOmmv-WR4Q&|&Rqi*0N&A|ON8o~2 zlu8ivT>}sTxc~C{VT|e60Op2bb|sE3;rGm`d*L0eqOGPS;?>RL7~fP}LqcI&8QmxU z4&Uhfcs{2gA@n5<{X7;GtV~7vaUEDVe2l>}kHRNHdXb(CK*#{Z+ZHZ=`_L^Q0}!e_ zKn(yQQq}d6$5>!D;t8fVa8MeIzn=8fg?`BnxZoQvnS!bVX(>s#wW^zF+PVgY=)PM0 z$$KHKn=AW>rj;?FR?z>22ng*15M9N~sAmMz_L~r+%HX*?CQv_JUC~SYzN8OR^WM0Z zA2-gH-{kmE9Gp~3A|FfzW^9KqzB`SmY}aM{EC>K1{a)N2Y-7GftdCEc3gSliD)%mv@`5c5dVuR0FlPRzutF_U=T+>Sf~OY*#0K< zJ7eOUMc9A(3S2#X5fTxN*!Tn_C8sb@Agu1mWNG0yulh+&PC|Ta48j8a;r`$%{@OYp z;|6v`6$1m2LGx>$5GL%cij~EXseiE;rsgkJDT#4-dS*KYw*8pF2Sd@xfb>3+C$>%N zcEs43^Re&Pc|3XPjo^r=w`F2Zp6q23CNzaICB(%dGAs~Y?hkP0@Gi`rJPd7I9K~0s z3X?oS1dyczYIhxlJy%{LNyRGROjdmJRTBV0pyAUsW<6;wTg1rokZPB3nc--(&SCm=?ATpV~(0(nt00bbcsJ^{_ zA?leJiTbUMt^&m>cEZe^*AdRE#51=8?N$g=6Y*rnp9{Oe-co!5+{nBH+K$-H6E>0h5(bQg8 ztt$rpn4)y$-q?4`msi@V;RUI2@VM~@dXzE|7dh88LxtLX@y8v%{99SgfR^{|L-?wJ zEttPv$;LzqRCMWy8S!wV$Y7N_U#3WM>c0ol>%vtf%qzN6VsT~F zm!fI2$TAv!{W~I5Jd9MOE<`}w|8;<9+UWp<2Kotw5rEJ)QegPbC#p=K(XrIz1l-=x zU({YC01#c?1pr~d0K|X-0U%g}8_!QHMkSG#Ut!`@N7n#$HM-%DTZE`x)d3(j-U}DK zR`Z={NJ)%Eh|ddLKDi&?elrcj`gTG+XM6GblPHrYXvS^Ypki&b?==Y1<}Sp+Gq>?7 zFcJy*{?f0x6^bMP!K*!E{O)2-@75|K9}Ji}t4Yss_~F0>xcdY#_>+)}i3#=-js9=YN^5*r@>wm~KkcpBY$DSQkU9{u6M) zU7*TP|8-F_073vf_+GYU(03BAz{&-PlVMM>|Jnf{QV|>MhK;>iz(!)ls1bt?pADXl zzi+rQ@DR(Oji!+!g3l!)Dl`yJub;**&bn3_ytaMq%4m zlmQ6l144+~Wz28?F^ohbtaPBqz*)slzry-+PxGWPqpIGL6Qc0o)Ovhgn}I^nNFrkt zFWV98&puZq5`87*k=6!S2g1`1z!1zog3AS&t<~ z2jTL*@6n~c9ZW?h>Up)UHS5?+`5mt!Rjk&{l57gXUf#r#FRF6+#8v?7!pyoN`b^mg z&wPrmi4S{)qdyHp1q%c5XSBi*EW2n)R+9Qf1{NjI zV(2e;5)`LaRHqC;WO3LWe!RZ`L>f<+d*3>asjaHPP*1$AviLk)I*-GS%kJF&=1*Ug z6cdcg2bQ934S@nqd9s^`LCcT(VEbhcmGnzOMZPltf^8Y{{0cTq?uELxmZIRRFm5*- z5Z{#m06+jqL_t)vE{k?wufwxoZmW`>mx?ft>sUFmk$4n^!VY!2PsMeP;?Biuh2&kc z9N_o2bRCP~P5Avyi~>pz_Eno<+WuPzlhDzT0SFm@$l_D-j}O`cIzs8W6D*V;A#3N( zouf}b{gm|d^e7@Cg3Qd!3NWvr#E=KHWZhxqdoss{UES_9yj>OIRZE(GkVa7+m+6oSr)t7@&4`}5Li3VL{gHXOdAoSu#z8B}Rcle*U;L*=7++Jn>- z^1F4Iww!t_l8!DJ7`o8liJhpJwr`yMZtO4dAl|l%btU&QE5}< zGmuKrzBlRTt*4cb@gAm}p>~75rjLsmiyqI_PQGVid^|-)gi(;M2R(cIfbO|^QD{&A zz4G>?S6jOM)lgwd&3lifaYF}DBbTydZE8%+jh%-Nh$){a zGT4jmoZCceep*dO?@4ZpGzq$I^s@XH6Zf5lRozWpf0 zCn?*IqejTN-7Gq|c^p+1{7vO;(kMFc32h$Mm}VZ2ri9e2C!5$hQSXI+(&`~~NMVqx z5lPkrbNH1M8AxZ=O`sn0_lx+4DU~YUn+{xAMYW45RF01lIi0g>$5W352gK8<(1#9O zUYTP$Ib^rM4m0O6-MMpzTD59LHa0f2Yu7Gn+_-W2_%%0~5c>HafBca)Y}i08TehS< zd-jm2smL=pH;F4<14@nwp&JKQ)7Viz(u4R!Qtl>o$=3uYPN3(uU2=k^B zt0z(aMSoFjV)iy@K^3d@r@d#FQ7s2W4(%^%y4wB4{Y6|D-TQkpO&dRtF8C!V_fOo9 zD{M);`e@C4@ zF2Q+FVf>7Q`F~QRFJ0KRmoI%?~anix&4 zR}a$M+4JexH4kE0J*A`>45mJFx6+b<^~u68=l(N3*n?pwsG4yPIo;bh-2iH%EBwE$IUE%_t(_bs6(6HslL~LV2F7*e~_M_jE zi@otXY;#IQ)L;j{FFrj-YsYn=AI`nAh_+QzD(ljorvCIj4Q}B~3WC&V_6NQ417i_(c%VIdkTWFv0=@5QvVBF7WIM ztGk8O#$sDoOk$q$la?GOnyzrK=!BF!rJWKVEtz(t1UfBs!{oRq$+X1mQV{!M5~SA( zNR>l+Kd)R(khWKFWPCn_nzC@MD%*xcs}&9|T`u*Hr19#<2nj!bU7sO{krYHvIdi_j%$YMWbJlFE*t!|t z%w!?inX@r>?mT?|{aS3{TUYyM3U$JR7g$)e9AlKvQQio|BR743h`EoLj-+qA@4f`mm z`)2G<*ANMD!-@5y&_rPu!k9GL2W7KuH!Ih6n%d$LQ{jVJOBS&bDS?0FLGVhhKTMm|Bz>TsDm(Akynp zplh>1z24(-)jLvaZAcpt5GnByxcU1`*fG6~FrLW1nc6yH_|^*u$|0OT!=G~g&wV0O zKE1eh1YfpsX4(&t)r2~%ol&6;_B{+%Bf>|HfXLbA@BWM;9Rb1S6Z+|3_bXV~qp8Gd ze4#(lWzK3RH0?DGn@-+GIFAd|kFAofqhublK0Ln{BYL%ktt7RKDV)mp!fvLOQzbr~ zahD0T`PU=7?_$IF&!I39rySwML(H>X8m;*mx$WE|MDgllZP=ZkWQdFO!P(u* z(5KCRG=dTuM%IoMFn;A}_{FNGzRIwF#(&{m$K(1z45;rUL4m~4HKz8c@W0_$a_BZf z`Ta*5WfR8rPp=%n(4MVeWhz0BXkd;C&4%E(EBC`{MhO;V1cVS}8S4EIM|Um7h~6Dg zl_MV%`eHOvub*q?c4g3S#tyjhifT2B133aB!&BAy|Ncfm2&GRG=*sS%#Eee$B_iR3 zX8>yhI+jP9LDRA8{9{Bg=Z-eoYhp|&uK&Fi1G=<=wYd~!krk@c9*P4uU#ayBi1vMg zEmJ#6^s9EL*L()<2gj?3K2XOeUZ0bi9FJhnyZCF{Vtm#8GgRTo2V;pyGGPpA_Qbvbw~ zlX6~|POnOne)#RC7wf?(dxRVTAxA*G^(Oh-hi(Cxg6Tu|0J;3K1>O@2q-y{$1xg%i z07ONEBP=M8g^GRQ3(5NUAs`@tLA5YMM6#|xTs#t!UUR$`6;l)~ z0D?7dVgqqvQ3seAi40nKAg;^8%+4K$9y%ipet!i7{cg|IaQA zY*Ufxm_#PJ1flH0Ks+3)I#R=K7Kkkjw9${Jrd|9|JIuK`f%s_2XPGudK*_XxG-FFc$MVkA@MPvZtjVTK8 zm!b|p@bnWeiU`O3zc=8E22K(J(EouDwk1&evq6}*GUn*!m{Ih2% z26kx%TPrh3fp~M9QW!e>FL=hg16%r5j&N={5c8KGhnv5kkE7{*GOW*iFVnbO zKeioT^=!>PWh(7c#VTO%k4NFJ0jQ!HfUrTex>Ip4H1~d$vADqF(G48jz6O&<^}{C( zoMB^ODoMK}jAs;94ro1OHvYNqqt@hXhP7k>BEu5u{C~dz2;mu!7!`=ie=J9bTE!)3 z@c0>^rw?=1PHWh4Bo?nc2{+$}+_zT-zN7q~;^@}z(Yr$g>(RgSMiI!X9#Uo0P#DH z`VQwG`KfNJOws3i_cUgnM zhAle@f06o;0SFm@$ka6DuOGMtWB}p=cL2HgvIX8}3kXqE!j>)|%LNr)>@xNh<#HD( z076(*`|K1tRX3Fwj2kisbVn>dbr(?y$@y9>sk{=?>&9X9YRE70V%)O4D&3)MC!Az4 zN>yB{LiEG4lPgf4g*us$K)GD39b@6r4Xcjd=Ew(ixw3OvboTFrDCX`yuoxYjjYT8j;=ABDt5=Z^8#OaZYPl5+Cm!uM0D^| z{L zsBiUmcV^KCAlP>NjEoKS#EH!_(7K8dm|;n&%?J|@Oz#Fm6FZbH*9u>bnTaKP{>DR( zK*S}f*XGlB;wC!G7dOrx!Z(vgpnaoCJZYnloB%g8vqs~7({SNQkXn71;03Ay2xF9} z*d7}%J-{gb}*L$2Dq+GtnAQX#B7|p=fNvma|hR? zCdaZE^`98tvb+SpJo_2@ls@yBmvwH95mOgn@5!5Z6%wI7;K9C|6dQ&Y_s(J4l8NZ~ zSp(RlN7E?xz3G!@##X4%eiV*B3RK&t1iw-ZKqyeI+UKm-aSv{4`jy+WXL$VJE^b}B zgww|lV#~S}m^pPKhW7gc&FWNzosDJs3T|d45p9b?SxgvwXftpI{=ED&J%V1nRw$H) zfvDI3oZa&c%p@WNnSu#B?)s}`qu2mkdh_Z< zoILs`Hm>;zGp04Kxo$+<{h?Im#y1r`)wH>pGVw04uY^1QF zP9wI_iiPc|q)C2rVzRDJls}#Nbp&%hpAg}l*CA8uk~C$-3mfV^Zx_w~suh*AWS(-RGqk&d*UwUH$O}5LZVnAxbdb51le67G zhqWk*(IvkfKXW3Q@7dcsh`6gnm2M8-D1w@tdz7mWT3F6hF=Vz zUzRMOnvTo`n+F5rT>~PGVuGL1#$gR;)-l#k$VLTkWL2Enf3uHvj%z|@YVdz&Gi(k& znNvB!myRqQNrRT3;CjjCD{QCoU4Ed8n+B32YgkB|N!EbKnVCI@swjZN3~m=;4T!e} zVoD&240NM2dw-$TtG3fcuOubj>DOoLu$GcBnOR$rP5Eln*riIkeo}RpdQ_oeNwT-K zCNmRbGSJr}9oD=`PD-Shm`DotdqvOP9?_i#ZshLzgf88BKrvBK=^Wj{jE2(3*n%9J z_Mq=)ji;VXs;b>iRck=#kcp)O)o$H}Dw^?Bige>s%8tf6nEzYH(2B~`>rImf)|1Y^ zpvM&zLiaBorPXUz)9?S>r(|WpBEG#2>xvkYsf{&jTM2frOchF(r0TWU?qy1ngRK>r z{AYJvem0~eCsAxn3~OZhk;n6AbnD(@@_Xe*kMCb6H=kIFjfx{Cloc%&gAdfA`!E_a zd@!|eDNm+GT$iF}=CqUh!bm^5bYLYdnDYx=@lRCNx=2q#m&;~E)(-Ymu||DzsZyRw zm2jpSA6KTbC5w@@jTM;GJiUr<5d$kBv&#|9bh{jc(t2M7|!b^x*ala`TI3 zEsI1^Z6+ckvMt?^hAmn|lfS4>whHz1k%TO&)_~9@bDLt+;1hoKoAP)@4P)_)FQq0Y zlAy;G9Th==0e<8c6h=u&NtBq7KnWrmLg}XZ?~fVZ?~@+GXy})HsYUIIWUf&4EXjQ3 z>+iA#gtASf_q@*<5N}JJ#=2Rd-Vf-+?q6vAhTrMBcd~SQ)#qn`tt~lJs7ej1SE7n# z%1||zI#j;A6WOJ=SJpja6hkL9m3=y%Vxl7{(ASgPpFO6#58cT1$s@YXeNs$xG(Q8f zjgd04WM)s!t^3gYDWj-!{Yq+Sn+TW2_&udRex53!0ijD)4o+0Rc{3`ZL0e5>UAcsW zc#4V)rvQI{@(&58Ter;Z?9QB^OffkNyLAE@xpIa+v3xL=>v;oZ!0Elewa7NaS)Skt*caLpMCRzs| zSXehcobLR!m_8Z$3k!T^L*Q7{wPgKKbo|(Ss%E811W^Vc-oD0ap|Rvs67LHD@qhNN z13ZeVYrmUhTQgwe2n!2bMZH^AhBUytFK^c)*)ZoL74I{QUOOAf7l0)oYMa)!oL=WsFQl5JObT^EeDcfXCL z(}%;)j?szzkD<>@#=&jN@cj=z;*S-3nS>~H(JJnoud~i7HFS)-&W#I1w`hy7-~jk~ zdO)jHvmu|2e%zkfXk?u8k(H5xxR@B6x)8_4GCd0NnRqajzJV1t4kniTG4TGUFz(TZ z(5F)~xN(8g%3jB%RwZI9Bklq#JvsR4| z?C%Q?PdDf^Dme4+?EMFeS<)>RS?Q^Wi;cl)NjEkQ>htyB%yz}imHG7YkHE;M-^H`z z??anF9UQEuZEeRs0RblEisn^$1)Hx3#d=tE;j!XWqA>D!*&OpL2T3bx_yn}Yy^r3H z`$yb|?rj_KIao3BL25-15E2TGF8>VzLPCSxkiF zN8-MF??$)Q;ns7txLw&#b3V@OSd1zEdlr8mWs;-RGriWQCGHsWHfFqcA41$5$3(U- zhc^=P5>Mlw??1rvpDscglh>sejdu&&_RyP{{`Lqo^>w}SUMC0$K|qwAE8_cq7=ij6 zz9FSbSzpIRsOvL6LNQpQCbfRryhyf z_dBPUxq)toypbX!Ba8lS7^*MNWoMBUbCry(qazN z;%{E0yL+|dnhM8)7DgQ&pF>Icg(VP{UzJit z=4B+(?zMC2+0lck5!WnY=hiE@$jK=c2UlxlaQ9{0eHeEyPx5frkw&ew+fGs2D)RE{ zM324v0j=G4u3BptN$CsYk8PpvUK~Sx+bC_O_`0g2f}EU`#6%Ifdw5=+Q<6@_e-+hD zL%xAG(Q|KqO1n=dRw_-P{S-|0$LXqGRohR^=SJs&57U(Cf6%_uah%Gf@^z*}3MTpU zP=0Gs3Z^Lob+XTo@N7ms#?Pk|efj6PeEaojE2ppJXZXZ(yXlWlpQYQoHMLn6sN}qM zvR;cyp0B0v0UqS0(~`=8dw`oy5cPZTW%_!>KDv}$@zh;X+8^6RsH=7kmekqay2jI= zB5!|`-uvP&I&e0g>)bh(YSxe$L(67Pq{bd9*|byzi}k3Je|gMKPo9?337PwUC{Z#zRpQjFcLcQd%- zttSQcet@QY_7@$wkXUKMU0o6oTAe4|c*`()_RSBuM#dhxn3zQc<=#K!N1}MEARvm7 zaOCs9L_kP*NF;=wQe#ih%DFRW?9e{sUn}DYG1wr$%sJ2vj>z0bMd-H-Pr59=j=RgD^RjyYyk$tyU>4UR%czP6DN zIN|XvRDNx;*pCh0FSmK4WF^Xihfb>!lj5yPDBE6&XrZT_ca5bGg?34_8`obhl_xNi zJO;xUljE!lD2t24hgQ@lAiJ}liXnHcN`$wnhjR!D0N}EAoNr#!OGE$}2F~pyWcLpR zMhNs15KJUyxP|GR7se6dubkv9#C_#HoeJ4pdi;@a6r-vuHrsc%a$*tH?~p*Reu@0O zvSLCNTk9qXXcOV(S1hbnTOwACIB7X-b!SzYS*dNE%C0XpJ8c&ymMl+nw@{=QWzWa| zaHbiwF_aI5gpAIQji4zOzs$3M|85X-REJ0i9Sq}sCw=g2+pGkB{8}=hk%?ra_pO@Jc{~M=ORK5RoszjH8wg*d6zOSIyTM^0t&PXIpy3r{U9MA zktzjNaK{vXvhs*}|ALKdq0vou0j2E&DvSwILxbpD38Zs=B-#1LD{<@7jqZ{MPj(fD zQ32|zmkad_&`rH$58PMw4LM)T`#WhSx6t^pm+UmZ3%;{8UXLOO(?K)H${IF2dK5Nm zw><*y&78`s>8eXxY^yXn zkFLc+(CGak(h@CYxl$bbVA%p2P~Kvz@^J>l97s%5ar37w7p+E9xSYtKvWuQzQCO=H zZv;O8|G$EWbI7E4YLmAbkb!2ihza63fb;8?X~hdmF1;tnhz|?(@!J@JU*d)4|qWgAI^b2|T{MLJ41^szcl#n#Nx|m~w z_rP@7mFiMt&_X}}3Z%HNtn4&nfPerh5{OAfSRx<*ASMc-TtNhcA0VFBG=RM7unmP&IR8vzXSq=Hi0YaCnj0 z@ue~in(4IXeYv!@Tx&>KQ_!Ys_kL)5c=b(Lu0Q_~mz1EeQx=TV$)O(yYfE$-ug!FL zP4ZMM%7b6V7dMR9Sahq0u3XC*IG}`qJ$T8NH(6PEv>0EJqjZG70iE{)@Si;ilk`!n zjU6>Bv_1hNpasz@y{b|N?t=!;K@PTpm5<<)%}AlobtUf>iiyGz(k<&Js9K2CKCfai zStz(4YR{ROi-Mpa3y0gu9O$N!?j$1E-~^jbKqVoF@G~>^COj-8pI;4Jx7dYeJ~=$j z&du{CqRf=cy;WjH-L^gCSIwjh8i zSn0xj878ohq?9vcFq@^guFaWfV916rJl`t`@6%rS{Z_;2{c-$a!|^p#gseoK6<*HR zhO{-MHXhJyp)koLZ|aT$)nLa!JQQ&CO-H&Ec-%A^I<+0Vv z`_Jnig~@j^PnLqbdT$xZ45K15OI5jxTNzGWShw{QpM6kT?QV3PAFnVhM_byZ!pPla z3HdU9uXa*-hVan^&HS(NYBszw_LQrtWP+9+?~Yp7YkO8`AK+k0`QU zr>w8t@_fZ$UsZXX;&K2Bn(FXC^-5>4IJ@9w9*@*^)l7{xVen~|zJ0Guq)^Q?Km)q| zBI?W8eC?d$?(O0D z=(aur!h?lQ5RG%BABE7Qe1j1pBqS&(FdUSBh(b{MIseYY+4QXYi3!G--#IM&Hum-E zP@`K%pn97A`7w9^Avd0MF>L>eEj(d&jfyA-Io$gik6$pgS+07jcyNT4T5*>NrN~$s ztDDQU#5;0U%p9v&(v{E2%e(FKF&tgpq^Rg2TDxdTCvYp|1JVQzI+QwT3iwf98klBE zjs28%>hl;+COw6!Mk35Y*=C^qdC4;4M?d*&pEej99cPD1CnRg6`Iz`ZHvi3z^|Vop z%&vV^E+jcQ9Uk5Wj&~^BP!IQ?-pkFF*sAL2^K&%;jnKxjljwZNMhc-#^t+?UK)K@b zlY`Qw4^A9l@X}oSA6W55^gH+A`y4K8SdvgsVd0Tt8-wN~B7?+Hkxo)Hm62L-F*^n( zb~nb~c@vrhO23N~92r8!K#FNdPyh!8BCOQG*;p;&O!f)woL@rGqGMH!I19;1Ch%b& zKUMYaT^1{vQ#p4gbLWyZm+~Ua1mH>&zd-u6kFW~jfziz8qX$}lhQvpnt%Oowbo4j| z{lPi7Tn(mCYS8#Z>F_SU;mTw}`2LhPwc83EI_mcve?K<^=*JaSFdI;t!&`DTuG}BZ zP}BCQF@ybxo*8WW<&rH(J7<@cSUXJrGba%HxMvZZwGP;fXwtxWHa+U74EjD|2qTl} zqnV{Mcc)4W)+bpm{UT2RJSJwPI1ER;V!6zoa7RXf#Os@@oehhMIJyiU*-234VpY{S zSX~^3&`hC|l&hXYqkG30c=A&S3JoP-Ap!L#?1i*gMPqOH8A6uVdwuBWcfOd&y*)Nx z&p?h!?o!=f)_H7tWb7`!{;E5gf_=q%RE%j6;31weVg1mTr**P^jF0|{Ys+^=l8**f*GAAX8A5WS8O}-HkQZWF-;%~ z8o8^@phnMWA$^TkuKkc1FSI1R9N0JnW#^4iixrjeSSI)M`s^6b30aa#z_J>BP z%Q=gQ0g}73AN_lZRju-;qIW(1AScTJ%SnRH=j+4u{$dq*YAPu~uWd>`gAH!m_lx)S zu@WCtgwZ2273#MT2=u+j!4ES+;;bk|Nhpa3d6Basl0r_AW^CC`A&@v!@f}fDrPt8c*ZSZXD7E4wIXfQR(L+=wH;f)399ByGMLu!mx&kvM$ zLCqS!XLGStsYrGb1$rC$_x@~{9y1a4{>c=Nq>M1#LjI$$S3_eYD3EzUiyqYN2P2SS zNWgKf*d$50FXVgLJrp#gKyEiZ_Vh-Y(@c%MHk90@3i%9*vzEyU3l?-P{fM}Y4IR_` zd@R{%a%K?V%@`9C3_}(y!z0h?h~v2G_TYy@&Y?C=i-wsOumY%a)E)e9+XDJsKiY+d zhvea=sf(l^Fgr+*s$$`4T3^pH)uGASvvwyAP>R{>&kiO`0#(`ZQm}9_`BI{SJ?u;d zQ3C)KOFIV_|EW!oiyM81`inMiE0l^Hw5x2u6TPZ%F1vjk6eH83dV&_jROJT)%N%ey z$5pq}YH(^6n7u`{Y+8SSUPj`sfGk9x{0^j{BzDggxpKW8uLU?*0})b3PyhizJr{u*7znUKat#R-zMvqDs-HRD8N1-|GF)qE zN~UZePnb}}UAn@0##WEUnl$INX~YV%*8PS(HzE&DaWoam_>&v7&nU*NgXm8)R7(iitu&Qhv0o#s(^De+`@`WDk!a zdpyF@gntvqDA|}Td4ilsy#WeocyN6tEzp95L>r{q{>{&L_z*qO^8Y2oxCkgMwkEKZyBU~6weo6KE#mMw?m|DS&zU+p9yYOT9bF$N-A4Yv# z#cno|ZK}vAs*JmXTfqKbD8N>JM=;T&9@%JdLBEB%(CkeT!f_1>9hFCCVadFKwn0+E zlBQHo@p=l)Zg_jr3Pj5y-9F_7=@ToTApe#N;NuW#=nzWQVHF-dj}wxYs`cq_3J2I} zEN{f##KZK#fB~!C^AIEOQ4M66_kQolvaj}%`9`NjfA+A)L}e}@Y|3~>=`kF$upvvW ztPNCn2bIg7lDU`J=&aA*Q#f7deMc6TQLa-7jeZMtCg+PIca%AG3!)H*g`lpr^WO7v zs*`H77KoCkmOLntN6@H_vB~@?&Xu$4=09{+0%Vw^7*D@XRGI#Q^014AXEoErr!6s! ze(MXZWM|`%)lTmI_N;6tq21=*gV6TXJ8aQ6fNp-9=z5ak9%(*bCG14U6%G@C^^E%t zjkVZ8^ix2EIhS>A!&w(3KOjtU`j7f&3(k4cLprx46~*pD+gqcCbc-~rb;UEgThjQM zi>V%~+h!0ju>U!XKlSl%rw>Yd_?E5)lr>1u3u1zw0xQGf@2}e;0=Fck&5=%bNT4E} zxOjxA0G*>C4!Ph9+$X{b^>%tlb~~io*iO%TJ*nqIYQYg%#1J!Oohi6wgM}H`$n5?i zK4%MIh5cZutQ^T0Lud6FfpyMe8vc!9gt`WCat%{F6J1xWLJARKBYsdtV3eGF#<_w{i4-tGRn_Y_h#FNTjM)CF)Ka0io!(Xy-c> zWS9phjSvN3=l>ON2>+zKjnRGt1V3>dW(`3E0Nem)5E~TsFFB9^KVfrQHmhaOaW$qCii{k(f>umtk z!+Na!{(PJIbm!E3Y{Hdiub}WseHjeM9yRi{oeVPUm77h7>A!;x|2t@8>sfW-zk~>9 zS{Ri1&!BghfFE-FC<=eUSf0>f?l+qZEPA}m!bDE9m)tbS3z(14p9rqu<%s`&%}pwb zotvu4Q@r9@2OX$7i}9-|n<|ZVP@bL(coK`FE;gdFXlSmY&XhPu79=MBltXtMW1moG z2P~>NBQ^y!Y5Jp$j?ka38=g((8fs+3DO1x%M&I!hlg$`qw$>7f^RpkMB)|beCDPUY zEDjSK9`3j8_iquGPK>P0@fPU-L5?q1ero~{v+j`L+y89s|6SI1_P=S6uW@E@GO93O zc&Po-7qtH@_Zg0Vh=72Jo{sR-8pBSTePqh7SD?pS$chIN zP%o&+>kI3>fi409Y#EBF-RTM!7JCB>_G8u<#v`iSPiQL-ZtsSB(9?0rK^0`sAeJkg zgGAUD&O{8ykfus4i9fRL!Pywz?9R5!VJ&VJm}!TSp>?yQgKv_ENK{cv>2;(06p2J{ z+oJN_Ji$j*tKyQaN6^2`0Q*jKYO!ri9Ra~PxZ_0q{{j`TJ^~*?fZ;q?@&vIwfB*qV zKE@tF>91}B1`0(qrvM$W!v+m1PvP%uz0dD|T?)mGgbc%EgM=hSMhG-F*0Jdf_bZVG z4w!sXNzIYtM)ws1A>u$y$ZyEg6Qskkjp#VmT=U@Tw^=JoCnAVAP8_r%^44P`)s4t6 z@NAmfYu%pbR@N(kis6@V-9VD01W64Ypw z&HR-aTVGi7LiIIdQf{Nzh=G5m`%z>EDT#>W3Cg!>VkTnX3zNhDDS{hEpPSb27EjRk zjLUYvC&Y5`)c?6m6p%@UNtkDlrCODZg0d7Y7Udh5j1y*G@*O-5Q0N>k<@1FG&gYAX zj+On-qFfRJDvoRYTK5Zff2%|NnAC)&{}4`}IaIq5@#lNla99cjPR zS<1esllyeI+CPmQmMu)qKsXXoe8pcM42V$2)@LnM1u3=mH-6KP$`>cap{i(u1|>#} z#%74EAAjLLIIAW&Vls&cN=4B>U~$Gh4*iJJ5zB7_d?9@DpcPqo?9B18qRS6(Qc|7# zJ2UyYt}Jcym;6>1z;&|bx8q+0wNKlUakL<Um1er%J+3` z`bolo?60<@8;}o{bQ=?sApe85f0z#t<}&^!5p1()-mEA9V9qLtNsUncLmPC&3V)y= zR%IhAkp$`QU)^s^b5r!wIg&z#%^54;cf$a1932rW z`Cl9p|HbjJ&b`JLA^^u9_{4;H|Dd4-{O@9GNaUbOZ}TG&8hBZOKJLRjP9yy!R%FRjE&<* zYPF;(OdaxR4tr>9xy~h6i;}=eLIW{jj0Mq45f>C>DMUSE4&9ZWkTG~eLs|r7#h~~7 ze$$=GNK1;&88MKeQdhonHnq-#77>X9)7**D0_9rm5q|p3P(2Hv`_*9=MV7PxU#g0` zbfa`Ici7x9vGZQ{5COp_?|$W?Gto9>fP&iDv>Ag5*VZ> zmVAMNDjM2Q(dMjehwLr}dkNX(O@=!s28DOtIwpLdCr2KdSC;1yluvxkxPC8hco&f> z-FW{oCd(o7$JLpN@9d%=#+bMH}M^17saIpi&oP{{~|iU^st222_)IfA_C?K>>=9N%BO#^>h{XSckZy zAmO{yp&5eP$6KOmB;V`~yrl+G?|R`KMbqCc^w+3pJgY^@-H4NkF zgiaGr)&?6kg}$4jh3#eG-$%eBgPSoP-Hq{c56cv;Q4EXn0uq33!$eHiur7BiNDHe% zqgz-TF?p}HY^9Z0JsgNx1gJ1022vs-cHX$hiuYhV?72}gsNKGUaas6x8GE)->Nn7! zK3YF5o_0T^JDAA!s#$r!FA%}o*GRarXIhEG!2|>sAS95GZ_oduIQ};+Sy2BQ?)1gQ zMpRS&G7a4Hg|PK-zUv6P@} za^h(3BnA-J+Xfz&wr`D8KLh+?onr0yo2?0>+Bh>4nPxHN=(HkE*wTHrk;ex+A}PYk z5D?H3{FSCIe{cWrmgfI_-e2rq-JYG^_7y6J*QY`~R6;DoU0*h0RQ6FLvev(b+T1IP zBMr{AD-K(tpY2uA7V{({;CTJ^>U3l4__qJF|r-t8S3JE-eTkv1r%}KG%ssbn zACB>(sN6NnC_uf22song0_Q)vC3FGMQEG>ny^N7BD2RvP4b(sd?gOM%o=060o7{~B z(YRa+!_l~rpIi+EBUP8?d-B|p`Y_JOg+d!?wc;n^i0qE{p^mGZ!_J%m*t~Mu`*)Jr z?R9oqmGdl?GSqYjw9Hjn`akb?o=}ECMXV>dy~TKFeU9Z`u!ynrfAYLLwxt?#531iJ zq9Y;Y|%R?$jjLuu=CDxA@mYpV7LH31LYDv;)t%! z>fm3!szjujqqH^5-d((1&=M*~Gx@-)-F)647KcidrMwh&12SzCDc?ikMpthjPAfm7 zBx(11t9Mvr{Ga)lUEU&i@-A`m3aITYzDV`B^A}&8%{e{Y3SZJ=1NdBSXR(A z1_h-yVMJFFTfj@dx&DS-n#uu8T0tF^)0o8sdqjndzBBYl+1`#p3kB#>eAj6S*2sCl5^jM>2Kb^^pW_6O$~!TVA3 ziFw=BRg0Pv-{_xd6Nx#>R~s2iY?Cm4R`+X&wnTM4Od?1~_n^pTKrV*?b@Ok4|C>Pr z*genUswcFz_E#4*2G*a5{xhX2*uZdsegsUYCbL^P){Fi-VL*-Wn@lczMQb-h z)oe2n*hV03XK4>C4T0#bBPa=KZ7&MlU)s``U=F3qG%BenLg!r`K~7j{Cr}g;mxyA- z-6fp?J%c|rVR(-R=I5UN5a2gP{))pcy!&2g=DQ)gYPHhbyg&j(_+ZI&Fq1avXg(k- z13U7|KVdEl>&ZRnlM6*2yo%Jp=yLdgE`?5dUwHTFLjcO^B3XMPgodl`otLkvVpe~5 zPc+I?w%{)9(DQ7(QFqq*hcFwiHlwT_d^USm-lWCjmbAK(e3H#}Y?cT$e^<_N*2Id` zfcm_D!@X5V6lBC)rRr{b@N~{yhJ_F}pl{<>R=qZXv-hLC)a-bSl0(h=SMSr=!BZ5pP1HG%syg?%pn6epQkd9I?ftIvai zh6={=F^8!6-eEMF5e=8#b5Nv?+`txb=X{39krmID!X=Rs)SW(KVGnB+s9xo&nlV|4 z;iBv-;^wFU8#U4b_ocn}wasJ_OUek0JdqV8tTCD)i7SjOv>1=Zjwx7TPZaa+igRd*b#spd#0KL3@7SOK2{}rwpMxpN9~DDmiO`Idg<7}( zIu~1fJWDD}>Q{0?_=C7e+&V859CQRt5PVtU8VW;(dL>~4{Hur8L2U zEQcR^n$?O2pZCT#Vw`zNND2oElDT*>rx!7H9x8elpau-#X)ejUI7j3BF5japd(sxmPE|fNh)cATb*3)WB~WLvA@&kbTX^nbKu z_1}=%75yu=obGS-s+&*$iuO--pCpjGi-4enxU0j}`HFm|vo`*5>l!R1xkU(aI=KC) zs7G33_l`j6t;AGWayKmbzjpy-Fs1`{9z@;K>3ro4pZuZVTKCbyE0?qEF50q!bxEF; z-Yq2h3gbRK1oNa^*K0Hz4sNa|KTpb$S@-b@d4=$BxP(YMfhZZ_wuAhrV@`%uGCg)k zULznNaTpsoO^UAm2*0waPLd2QA|P)hXT^H{ChL7nIcILd^EFOL5N7FOGH{W{?%6W> z8%C+bdEtJl*g{%mQoJ0+L^t1;A7_LW$3%jfP6)S8w4|BT0r97{vGJ~XzH<3#-Vm44 znCKRV1x3pXLwY^=)DJ9jZCUP)tof9p%r$|1+ehLg88{RHS-~jq`FQ117s!tCPAK3# zDl`XxDvA{rwfe6p`oCJh@bX`Muu+S*s?5&M9;uX&aH=E&tJ~prGo~+dK`JF9S#Yu8 z#guM+U};x@UaO7?I-wGqBaK-q+9EERReX0`ZG=C*Qq1t!>H+eG6Ddldzz)em0xZM? zd^~{v8{XE^j2T*JcTdoeonK_zicgwV6=}t4Vg3cTdp^wO^MJ^bM>W1(9{<(r!6M@{ zrRo=3F~XQEk07)7(~(ez1Gp($c6kSd(GD?-XW#*xo})SpG4>5S?OW#6A4~z8IuC!9 zsx6l1Qcjd4i|%KqTAxN?0Xy4Y#y%b>v~LH7KM6A;M#ELE^cH>_OFOu@P;vW?5fh{y zP#DB~kSde*ck5h&k~=(D${6eENz}HoVpR4yBhO9Q<`=KpRVQK-7oi6~dFIHi(SEo2 zojH(jKM8`{>edX4rXwy?0F!4ZKmGeolNA}va76NVRDE_)ayHfKy{UqyazQWtOzAyv z=v54WMfvs*0R1q8F_9}&{~^<^zf=FpCnVI>CLloQJl5KBen=GFWWO&4i^1@1YHDg^ zVj?IbL%TDvaZD%;ZbU{>;69i_M7PE7gM7NzfT2f00aDnIPzG&0i4M?as8FUlQ?jUF zsRC*30;1IzCa^z*2>JasG@80x&8Ai$r+9cVn`&9g8t1TZL1-M6p}gZ7hxwq0kc|rK zcsi>m?W5SPbjB|r0QfV(j=k5&K4AW^isWJu=}}Al6GnV}M9qA*f-*fMv~O5f)ztoi zRp1BmEe!0VOKJADh9)`Rb|M{}9i>`_hgMUQ&=2BsMU5z0wOYzxV5unTGGi`PMWj%8 zd0AOeb90IYE!v}rw7@*!P%ba4Q``p+-XBw$;p%$sVAktRgR=$V(tnf=|NIdC9{uq~ ziig99Ic%z}+#`A%_!ua*Gnk^+TaqoiL)5N+$fhL|9LC=Th3~}z=S#EstHP_kkwSEI zDG>|)9`6D1ha7%nGN0CULruHJFL#dSLsuCuFQlcx6GJL*@}#4rcKkM29RKiX`GHQ} z4B<;1xaA5Yr8Kx!j@DConVcKcWGl`g56!U?FmkvK?alCNpHJ8)(U4l$LyDnG?7O*I z=OsrBHg~>TXcZYsP?l8+VJNB=bF&huij|ZrUt=*IuIeuaw*CTJr z*K1)CZuY7dw}|nVV?$zH!v_OKoAA~9FRo}iUdg2s7^R&7c5ma|d&TJBJ>tgL%E~@m zk6#ajV$oknj4#2aYr7-Z&unK=wex&E2cAT`nx|&|b!8gAJal+kU~M~Y$0~m6o3LZhWXv=wESG8`i0Alw!6Fgd;n0ycIZce|HPCuv#ZX z>YcLv-VU9WRu}3q6QCCWKjyhbngbOVUM`VPw8Zau&-t>v3mBRlEOUine*oNQJ2p8i z3{u3-4gvVxd$x1i?!KdxHh|g$fjsrDfWdN1MnttbVsR_IZxw7;m~5w2yN`O4E$tS; z^@`-tX47Ane42=p5YN6A9np~s>lBTuuM74{$rb77S9c%g6kV73MjK*ZzYyZkif8km za8HlzFg4kLyiz@GVv+*yJ^#UHr_U>?^NVYLo@x}HYMn%?5~1{bWo0rAqCNy9ELeVd zbrn%o$(ZMlubn$EPaL%3->xb@8!&F~Gfr@Sm!4LYRepqs30#AU+3eYSeZ9}S+4su1 z>-w^}jJ)j7PhX=#C?@_5@0 z9)EfHLwK+S4*?PL>ZkTT(AK=ykGdTsh>ox)vc^)Q$f;%7VA#RqVLhRU!Cyeavq7tG z_Q*1z6&ij;yre$tPd}%OhW_FS{G}&@;r48JpV7Uy2?c^!q0G79Y7Ou?z^NSt+2pJ; zBbRf05zD7h8E&*aysW%j{rqB&^jzK<->>`X-R^R-C>YYES%;RLlF)_P;Cl=9b9$MD z+nLjLFA(I4u;O2&C?@3lw~DrR3go*6)&T7b*B^&#qN7jO88go)8E4@ zB>6hQl(Ri>GUZ@&+V<9d7rrG7Arp3n7;PjVGZ>nac%{wMY#NpJTYDvqgq{>&Gknz3 zUk}IAj!Yc3s(I*}(FSmB1#5Qu`V(5e=N;U&b^wkTJR%~226=l8RR0H|XViaXYc(

;SY23w)##_^%#;=f;a@!{$eU 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

g{7T&m? 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 + %CDAP APIs do not allow app names with any special characters. Here we will map the + %name to ensure it does not contain special characters using a regex whitelist + %see http://stackoverflow.com/questions/3303420/regex-to-remove-all-special-characters-from-string + re:replace(Appname, "[^0-9a-zA-Z]+", "", [{return, binary}, global]). + +get_metrics_list_for_app(XER, Appname, Namespace, CDAPURL) -> + URL = ?SC([CDAPURL, "/v3/metrics/search?target=metric&tag=namespace:", Namespace, "&tag=app:", map_appname(Appname)]), + {ReturnCode, RetBody} = httpabs:post(XER, URL, "application/json", ""), + case ReturnCode of + 200 -> [ X || X <- jiffy:decode(RetBody),binary:match(X, <<"user.">>) /= nomatch]; + _ -> 504 %must bubble this up + end. + +-spec get_app_healthcheck_program(string(), binary(), binary(), string(), #program{}) -> integer(). +get_app_healthcheck_program(XER, Appname, Namespace, CDAPURL, P) -> + %helper function: checks for a partocular program from an app + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/", P#program.type, "/", P#program.id]), + {RC, _} = httpabs:get(XER, URL), + case RC of + 200 -> + %Next make sure it's status is running + {RC2, RB2} = httpabs:get(XER, ?SC([URL, "/status"])), + case RC2 of + 200 -> + S = jiffy:decode(RB2, [return_maps]), + case maps:is_key(<<"status">>, S) andalso maps:get(<<"status">>, S) == <<"RUNNING">> of + true -> 200; %return 200 + false -> ?BAD_HEALTH_CODE %return + end; + _ -> ?BAD_HEALTH_CODE + end; + _ -> ?BAD_HEALTH_CODE + end. + +-spec exec_program(string(), binary(), binary(), string(), #program{}, string()) -> httpstat(). +exec_program(XER, Appname, Namespace, CDAPURL, P, Exec) -> + %Exec should be 'start' or 'stop' + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/", P#program.type, "/", P#program.id, "/", Exec]), + httpabs:post(XER, URL, "application/json", ""). + +push_down_program_preference(XER, Appname, Namespace, CDAPURL, {PT, PI, PP}) -> + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/", PT, "/", PI, "/", "preferences"]), + httpabs:put(XER, URL, "application/json", jiffy:encode(PP)). + +deploy_pipeline_dependency(XER, Namespace, CDAPURL, {ArtExtendsHeader, ArtName, ArtVerHeader, ArtURL, _}) -> + %deploys a single dependency + %TODO! I should really be using Erlang records more and not relying on positional arguments so much. For example, I could add a record that represents a Dependency instead of using a positionally-based tuple. + {200, JarBody} = httpabs:get(XER, ArtURL), + Headers = [{"Artifact-Extends", ArtExtendsHeader}, {"Artifact-Version", ArtVerHeader}], + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/artifacts/", ArtName]), + httpabs:post(XER, URL, Headers, "application/octet-stream", JarBody). + +deploy_pipeline_dependency_property(XER, Namespace, CDAPURL, {_, ArtName, ArtVerHeader, _, UIPropertiesURL}) -> + %TODO! I should really be using Erlang records more and not relying on positional arguments so much. For example, I could add a record that represents a Dependency instead of using a positionally-based tuple. + case UIPropertiesURL of + none -> {200, ""}; %nothing to do + _ -> + {200, PropertiesJSON} = httpabs:get(XER, UIPropertiesURL), + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/artifacts/", ArtName, "/versions/", ArtVerHeader, "/properties"]), + httpabs:put(XER, URL, "application/json", PropertiesJSON) + end. + +%%% +%%%EXTERNAL +%%% +get_app_metrics(XER, Appname, Namespace, CDAPURL) -> + %Namespace should be a binary + MetricsList = get_metrics_list_for_app(XER, Appname, Namespace, CDAPURL), %assert 200 or bomb + case MetricsList of + 504 -> {504, []}; + %TODO! cdap seems to return a {200, []} for above call even if the app is not deployed. Is that OK? for now return empty list but maybe we should determine this and error with a 404 or something + [] -> {200, []}; + _ -> + URL = ?SC([CDAPURL, "/v3/metrics/query"]), + Body = jiffy:encode( + {[{<<"appmetrics">>, + {[{<<"tags">>, {[{<<"namespace">>, Namespace}, {<<"app">>, map_appname(Appname)}]}}, + {<<"metrics">>, MetricsList}]} + }]}), + {ReturnCode, RetBody} = httpabs:post(XER, URL, "application/json", Body), %even when app does not exist this seems to return a 200 so assert it! + case ReturnCode of + 200 -> {200, jiffy:decode(RetBody)}; + 504 -> {504, []} + end + end. + +%THIS FUNCTION WAS ONCE NEEDED +%It gets the list of all programs in a running CDAP app. +%However this is no longer used due to a feature request where people want to start/healthcheck only *some* programs in their application +%So now this information is sourced from the initial PUT request, where those programs are saved as supplemntal state +%However, leaving it here because maybe one day it will be useful +%%%get_app_programs(Appname, Namespace, CDAPURL) -> +%%% %fetch the list of programs from a running CDAP app. +%%% %Parse this into a list of [{ProgramType, ProgramID}] tuples. +%%% %Used as part of healthcheck, and also as part of undeploy so I don't have to keep Programs in MNesia pipeline. +%%% %get informaation about application +%%% URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname)]), +%%% {ReturnCode, RetBody} = httpabs:http_get(URL), +%%% case ReturnCode of +%%% 504 -> 504; +%%% 404 -> 404; +%%% 400 -> 400; +%%% 200 -> +%%% Drb = jiffy:decode(RetBody, [return_maps]), +%%% Programs = maps:get(<<"programs">>, Drb), +%%% lists:map(fun(X) -> #program{ +%%% %stupid CDAP APIs require a different get call then what is returned as the Program Type. For example you need to get "flows" to get a program of type Flow. im filing a bug with them. see program-typeOne of flows, mapreduce, services, spark, workers, or workflows here: http://docs.cask.co/cdap/current/en/reference-manual/http-restful-api/lifecycle.html#details-of-a-deployed-application. I filed an issue: https://issues.cask.co/browse/CDAP-7191?filter=-2 +%%% %From http://docs.cask.co/cdap/current/en/developers-manual/building-blocks/program-lifecycle.html +%%% %All the uppercase ones are: Flow, MapReduce, Service, Spark, Worker, Workflow +%%% %From http://docs.cask.co/cdap/current/en/reference-manual/http-restful-api/lifecycle.html#details-of-a-program +%%% %All the lowercase ones are: flows, mapreduce, services, spark, workers, or workflows +%%% program_type = case maps:get(<<"type">>, X) of +%%% <<"Flow">> -> <<"flows">>; %cdap api fail man +%%% <<"Mapreduce">> -> <<"mapreduce">>; +%%% <<"Service">> -> <<"services">>; +%%% <<"Spark">> -> <<"spark">>; +%%% <<"Worker">> -> <<"workers">>; +%%% <<"Workflow">> -> <<"workflows">> +%%% end, +%%% program_id = maps:get(<<"id">>, X) +%%% } +%%% end, Programs) +%%% end. +%%% +-spec get_app_healthcheck(string(), binary(), binary(), string()) -> integer(). +get_app_healthcheck(XER, Appname, Namespace, CDAPURL) -> + %cdap does not provide a simple "heathcheck" api for apps like it does metrics + %what I am using is: + % making sure the application is there + % making sure all programs (flows, services, etc) are there + %for now. From: http://docs.cask.co/cdap/current/en/reference-manual/http-restful-api/lifecycle.html#details-of-a-deployed-application + + Programs = util:get_programs_for_pfapp_from_db(Appname), + %check each program + M = lists:map(fun(X) -> get_app_healthcheck_program(XER, Appname, Namespace, CDAPURL, X) end, Programs), + case lists:foldl(fun(X, Y) -> X == 200 andalso Y end, true, M) of %check all 200s + true -> 200; + false -> ?BAD_HEALTH_CODE + end. + +push_down_config(XER, Appname, Namespace, CDAPURL, ConfigJson) -> + %http://docs.cask.co/cdap/current/en/reference-manual/http-restful-api/lifecycle.html#update-an-application + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/update"]), + Body = jiffy:encode( + {[ + {<<"config">>, ConfigJson} + ]}), + httpabs:post(XER, URL, "application/json", Body). %returns {ReturnCode, ReturnBody} + +push_down_program_preferences(XER, Appname, Namespace, CDAPURL, ParsedProgramPreferences) -> + FClosure = fun(X) -> push_down_program_preference(XER, Appname, Namespace, CDAPURL, X) end, + workflows:all_200s_else_showerror(FClosure, ParsedProgramPreferences). + +form_service_json_from_service_tuple(Appname, Namespace, CDAPURL, {SN, SE, EM}) -> + %transforms {SN, SE, EM} into {url: foo, method: bar} + URL = list_to_binary(?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/services/", SN, "/methods/", SE])), + {[{<<"url">>, URL}, + {<<"method">>, EM} + ]}. + +form_stream_url_from_streamname(CDAPURL, Namespace, Streamname) -> + list_to_binary(?SC([CDAPURL, "/v3/namespaces/", Namespace, "/streams/", Streamname])). + +-spec exec_programs(string(), binary(), binary(), string(), lprogram(), string()) -> httpstat(). +exec_programs(XER, Appname, Namespace, CDAPURL, Programs, Exec) -> + FClosure = fun(X) -> exec_program(XER, Appname, Namespace, CDAPURL, X, Exec) end, + workflows:all_200s_else_showerror(FClosure, Programs). + +push_down_app_preferences(XER, Appname, Namespace, CDAPURL, AppPreferences) -> + %use app level preferences API if specified + %http://docs.cask.co/cdap/current/en/reference-manual/http-restful-api/preferences.html + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/preferences"]), + httpabs:put(XER, URL, "application/json", jiffy:encode(AppPreferences)). + +deploy_app(XER, Appname, Namespace, CDAPURL, JarBody, ArtifactName, ArtifactVersion, AppConfig) -> + %Create Artifact + %Deploy App + + %post the artifact, OK if already exists, no check + %explicitly set artifact version becausme some JARS do not have it + httpabs:post(XER, ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/artifacts/", ArtifactName]), [{"Artifact-Version", erlang:binary_to_list(ArtifactVersion)}], "application/octet-stream", JarBody), + + %deploy the application + PutBody = jiffy:encode( + {[ + {<<"artifact">>, {[ + {<<"name">>, ArtifactName}, + {<<"version">>, ArtifactVersion}, + {<<"scope">>, <<"user">>} + ]}}, + {<<"config">>, AppConfig} + ]}), + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname)]), + httpabs:put(XER, URL, "application/json", PutBody). + +delete_app(XER, Appname, Namespace, CDAPURL) -> + %delete an application; works for prog-flow and hydrator + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname)]), + httpabs:delete(XER, URL). + +deploy_pipeline(XER, Appname, Namespace, CDAPURL, PipelineJson) -> + %Deploy a hydrator pipeline, assumes namespace has already been set up + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname)]), + httpabs:put(XER, URL, "application/json", PipelineJson). + +exec_pipeline(XER, Appname, Namespace, CDAPURL, Exec) -> + %Exec assumed to be: "resume" or "suspend" + %TODO! REVISIT WHETHER datapipelineschedule is a parameter + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/schedules/dataPipelineSchedule/", Exec]), + httpabs:post(XER, URL, "application/json", ""). %this CDAP API is a POST but there is no body. + +exec_pipeline_workflow(XER, Appname, Namespace, CDAPURL, Exec) -> + %Exec assumed to be: "stop" or + %TODO! REVISIT WHETHER DataPipelineWorkflow is a parameter + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/workflows/DataPipelineWorkflow/", Exec]), + httpabs:post(XER, URL, "application/json", ""). %this CDAP API is a POST but there is no body. + +get_pipeline_healthcheck(XER, Appname, Namespace, CDAPURL, PipelineHealthLimit) -> + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/schedules/dataPipelineSchedule/status"]), + {RC, RB} = httpabs:get(XER, URL), + case RC /= 200 of + true -> ?BAD_HEALTH_CODE; %failed to even hit the status. + false -> + Status = jiffy:decode(RB, [return_maps]), + case maps:is_key(<<"status">>, Status) andalso maps:get(<<"status">>, Status) == <<"SCHEDULED">> of + false -> ?BAD_HEALTH_CODE; %status is malformed or the pipeline is not scheduled, both not good + true -> + %Next, check the last number of runs, and report a failure if they were not sucessful, or report of more than one of them is running at the same time. + %This logic came from Terry. + %His logic is essentially that, if your application is running, but is failing, that should be interpeted as unhealthy and needs investigation. + %His logic was also that if you have two runs running at the same time, that requires investigation as that should not happen. + %RE list_to_binary(integer_to_list( see http://stackoverflow.com/questions/4010713/integer-to-binary-erlang + L = list_to_binary(integer_to_list(PipelineHealthLimit)), + {RC2, RB2} = httpabs:get(XER, ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/workflows/DataPipelineWorkflow/runs?limit=", L])), + case RC2 /= 200 of + true -> RC2; %failed to even hit the status + false -> + LRST = lists:map(fun(S) -> + case maps:is_key(<<"status">>, S) of + false -> critical; + true -> case maps:get(<<"status">>, S) of <<"COMPLETED">> -> ok; <<"RUNNING">> -> running; <<"FAILED">> -> critical end + end end, jiffy:decode(RB2, [return_maps])), + %now process the transformed list + %check if any had failed or if the status JSONs were malformed, or check if more than 2 running at once + case lists:any(fun(X) -> X == critical end, LRST) orelse length(lists:filter(fun(X) -> X == running end, LRST)) > 1 of + true -> ?BAD_HEALTH_CODE; + false -> 200 %ALL TESTS PASS + end + end + end + end. + +get_pipeline_metrics(_Appname, _Namespace, _CDAPURL) -> + lager:warning("WARNING, metrics not actually implemented yet for pipelines!!"), + {200, []}. + +deploy_pipeline_dependencies(XER, Namespace, CDAPURL, ParsedDependencies) -> + FClosure = fun(X) -> deploy_pipeline_dependency(XER, Namespace, CDAPURL, X) end, + workflows:all_200s_else_showerror(FClosure, ParsedDependencies). + +deploy_pipeline_dependencies_properties(XER, Namespace, CDAPURL, ParsedDependencies) -> + FClosure = fun(X) -> deploy_pipeline_dependency_property(XER, Namespace, CDAPURL, X) end, + workflows:all_200s_else_showerror(FClosure, ParsedDependencies). + +create_namespace(_XER, <<"default">>, _) -> {200, ""}; %no-op, already exists +create_namespace(XER, Namespace, CDAPURL) -> + httpabs:put(XER, ?SC([CDAPURL, "/v3/namespaces/", Namespace]), "", ""). + +get_app_config(XER, Appname, Namespace, CDAPURL) -> + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname)]), + {RC, RB} = httpabs:get(XER, URL), + case RC of + 200 -> {200, maps:get(<<"configuration">>, jiffy:decode(RB, [return_maps]))}; + _ -> {RC, RB} + end. + +get_app_preferences(XER, Appname, Namespace, CDAPURL) -> + URL = ?SC([CDAPURL, "/v3/namespaces/", Namespace, "/apps/", map_appname(Appname), "/preferences"]), + {RC, RB} = httpabs:get(XER, URL), + case RC of + 200 -> {200, jiffy:decode(RB, [return_maps])}; + _ -> {RC, RB} + end. + +get_cdap_cluster_version(XER, CDAPURL) -> + %CDAP decided to change their port numbers between release 3 and 4. + %The broker works with both. + %In order to add the correct GUI information into the broker "info endpoint", I have to know what CDAP version we are connected to. + %The GUI information is a convinence function for component developers that hit the broker via the CLI tool. + URL = ?SC([CDAPURL, "/v3/version"]), + {RC, RB} = httpabs:get(XER, URL), + case RC of + 200 -> maps:get(<<"version">>, jiffy:decode(RB, [return_maps])); + _ -> <<"UNKNOWN CDAP VERSION">> + end. + +-spec get_cdap_gui_port_from_version(binary() | string()) -> 9999 | 11011 | binary(). +get_cdap_gui_port_from_version(Version) -> + %given the cdap clsuter version, return the GUI port + case re:run(Version, "3\.\[0-9]+\.[0-9]+") of + nomatch -> + case re:run(Version, "4\.\[0-9]+\.[0-9]+") of + nomatch -> <<"UNKNOWN CDAP VERSION">>; + _ -> 11011 + end; + _ -> 9999 + end. + diff --git a/src/cdap_interface_tests.erl b/src/cdap_interface_tests.erl new file mode 100644 index 0000000..37926a6 --- /dev/null +++ b/src/cdap_interface_tests.erl @@ -0,0 +1,34 @@ +% ============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. + +-module(cdap_interface_tests). +-include_lib("eunit/include/eunit.hrl"). + +get_cdap_gui_port_from_version_test() -> + ?assert(9999 == cdap_interface:get_cdap_gui_port_from_version("3.0.0")), + ?assert(9999 == cdap_interface:get_cdap_gui_port_from_version("3.10.0")), + ?assert(9999 == cdap_interface:get_cdap_gui_port_from_version("3.0.10")), + ?assert(9999 == cdap_interface:get_cdap_gui_port_from_version("3.10.10")), + ?assert(11011 == cdap_interface:get_cdap_gui_port_from_version(<<"4.0.0">>)), + ?assert(11011 == cdap_interface:get_cdap_gui_port_from_version(<<"4.10.0">>)), + ?assert(11011 == cdap_interface:get_cdap_gui_port_from_version(<<"4.0.10">>)), + ?assert(11011 == cdap_interface:get_cdap_gui_port_from_version(<<"4.10.10">>)), + ?assert(<<"UNKNOWN CDAP VERSION">> == cdap_interface:get_cdap_gui_port_from_version("5.0.0")). + diff --git a/src/cdapbroker.app.src b/src/cdapbroker.app.src new file mode 100644 index 0000000..1d04330 --- /dev/null +++ b/src/cdapbroker.app.src @@ -0,0 +1,23 @@ +{application, cdapbroker, + [{description, "Interface between Consul and CDAP in DCAE"}, + {vsn, "4.0.3"}, + {registered, []}, + {mod, { cdapbroker_app, []}}, + {applications, + [kernel, + stdlib, + lager, + inets, + ssl, + jiffy, + mnesia, + leptus, + uuid, + iso8601 + ]}, + {env,[]}, + {modules, []}, + {maintainers, []}, + {licenses, []}, + {links, []} + ]}. diff --git a/src/cdapbroker_app.erl b/src/cdapbroker_app.erl new file mode 100644 index 0000000..13256b0 --- /dev/null +++ b/src/cdapbroker_app.erl @@ -0,0 +1,94 @@ +% ============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. + +%%%------------------------------------------------------------------- +%% @doc cdapbroker public API +%% @end +%%%------------------------------------------------------------------- + +-module(cdapbroker_app). + +-behaviour(application). + +%% Application callbacks +-export([start/2, stop/1]). + +%for application state +-include("application.hrl"). +-define(SC(L), util:concat(L)). + +%%==================================================================== +%% API +%%==================================================================== + +start(_StartType, _StartArgs) -> + %starting inets to make request calls + inets:start(), + %from the HTTPC page: + %"If the scheme https is used, the SSL application must be started. + ssl:start(), + + %EELF hello + audit:info("Audit log initlized"), + metrics:info("Metrics log initlized"), + error:info("Error log initlized"), + + %fail fast; check all failure conditions first + PE = util:get_platform_envs_and_config(), + case PE of + [] -> %crash and burn. Need to exit else supervisor will restart this endlessly. + exit("fatal error, either HOSTNAME or CONSUL_HOST or CONFIG_BINDING_SERVICE is not set as an env variable"); + [_, ConsulURL, CDAPUrl, BoundConfigMap] -> + try + S = dict:new(), + S1 = dict:store("consulurl", ConsulURL, S), + S2 = dict:store("configmap", BoundConfigMap, S1), + State = dict:store("cdapurl", CDAPUrl, S2), + + %initialize database + ok = util:initialize_database(), + + %print out currently registered apps at startup + lager:info("Currently installed apps: ~p~n", [util:get_all_appnames_from_db()]), + + %start the REST server + leptus:start_listener(http, [{'_', [{resource_handler, State}]}], [{port, 7777}, {ip, {0,0,0,0}}]), + + %start the supervisor + lager:info("Starting supervisor"), + cdapbroker_sup:start_link() + catch Class:Reason -> + lager:error("~nError Stacktrace:~s", [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})]), + exit(Reason) + end + end. + +%%-------------------------------------------------------------------- +stop(_State) -> + %need to make sure there are no pending transcations in RAM not written to disk yet on shutdown. + %Two hard problems in CS, this is one of then... + lager:info("Stop recieved."), + case mnesia:sync_log() of + ok -> ok; + {error, Reason} -> + lager:error(io_lib:format("While stopping, MNESIA could not by syncd due to: ~s. This means on bootup the database may be in a bad state!!", [Reason])), + notok + end. + diff --git a/src/cdapbroker_sup.erl b/src/cdapbroker_sup.erl new file mode 100644 index 0000000..b0894e8 --- /dev/null +++ b/src/cdapbroker_sup.erl @@ -0,0 +1,55 @@ +% ============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. + +%%%------------------------------------------------------------------- +%% @doc cdapbroker top level supervisor. +%% @end +%%%------------------------------------------------------------------- + +-module(cdapbroker_sup). + +-behaviour(supervisor). + +%% API +-export([start_link/0]). + +%% Supervisor callbacks +-export([init/1]). + +-define(SERVER, ?MODULE). + +%%==================================================================== +%% API functions +%%==================================================================== + +start_link() -> + supervisor:start_link({local, ?SERVER}, ?MODULE, []). + +%%==================================================================== +%% Supervisor callbacks +%%==================================================================== + +%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules} +init([]) -> + {ok, { {one_for_all, 0, 1}, []} }. + +%%==================================================================== +%% Internal functions +%%==================================================================== diff --git a/src/consul_interface.erl b/src/consul_interface.erl new file mode 100644 index 0000000..e52abd8 --- /dev/null +++ b/src/consul_interface.erl @@ -0,0 +1,139 @@ +% ============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. + +-module(consul_interface). +-export([consul_register/8, + consul_deregister/3, + consul_get_configuration/3, + consul_get_preferences/3, + consul_get_service_ip_port/3, + consul_push_config/4, + consul_push_preferences/4, + consul_bind_config/3, + consul_delete_config/3, + consul_delete_preferences/3 + ]). + +-define(SC(L), util:concat(L)). +-define(PrefKey(Appname), ?SC([Appname, ":preferences"])). + +%the Erlang library linked on the Consul webpage does not seem to be equivelent to python-consul. It does something else: https://github.com/undeadlabs/discovery +%and this one seems to be just elixer: https://github.com/undeadlabs/consul-ex +%so, for now, I'm just doing some HTTP calls directly against the REST API. + +consul_get_service(XER, Appname, ConsulURL) -> + %returns a list of maps + URL = ?SC([ConsulURL, "/v1/catalog/service/", Appname]), + {200, ReturnBody} = httpabs:get(XER, URL), + jiffy:decode(ReturnBody, [return_maps]). + +consul_write_kv(XER, Key, Value, ConsulURL) -> + %generic helper function to write a value into Consul + URL = ?SC([ConsulURL,"/v1/kv/", Key]), + httpabs:put(XER, URL, "application/json", Value). + +consul_read_kv(XER, Key, ConsulURL) -> + %does a get on the KV store, see https://www.consul.io/docs/agent/http/kv.html + %Appname MUST be a binary not a string! + URL = ?SC([ConsulURL, "/v1/kv/", Key]), + {RC, RB} = httpabs:get(XER, URL), + case RC of + 200 -> + [Drb] = jiffy:decode(RB, [return_maps]), + {200, base64:decode(maps:get(<<"Value">>, Drb))}; %NOTE! Does not do a JSON decode here in case you want to read non-JSON from Consul. Leaves the decode to the caller. + _ -> + {RC, RB} + end. + +consul_delete_kv(XER, Key, ConsulURL) -> + %the config has not been jiffy'd prior to this function + URL = ?SC([ConsulURL,"/v1/kv/", Key]), + httpabs:delete(XER, URL). + +%%%%%%%%%%%%%%%%% +%PUBLIC FUNCTIONS +%%%%%%%%%%%%%%%%% + +consul_register(XER, Appname, ConsulURL, SDIP, SDPort, HealthURL, HCInterval, AutoDeregisterAfter) -> + %uses the agent api to register this app as a service and it's healthcheck URL, which is this broker as a proxy. + %/v1/agent/service/register from https://www.consul.io/docs/agent/http/agent.html#agent_service_register + URL = ?SC([ConsulURL, "/v1/agent/service/register"]), + Body = jiffy:encode( + {[{<<"Name">>, Appname}, + {<<"Address">>, SDIP}, + {<<"Port">>, SDPort}, + {<<"Check">> , + {[{<<"HTTP">>, HealthURL}, {<<"Interval">>, HCInterval}, {<<"DeregisterCriticalServiceAfter">>, AutoDeregisterAfter}]} + } + ]}), + httpabs:put(XER, URL, "application/json", Body). + +consul_deregister(XER, Appname, ConsulURL) -> + %/v1/agent/service/deregister/ from https://www.consul.io/docs/agent/http/agent.html#agent_service_register + URL = ?SC([ConsulURL, "/v1/agent/service/deregister/", Appname]), + httpabs:put(XER, URL, "application/json", ""). %kinda weird that this isnt a DELETE + +consul_get_configuration(XER, Appname, ConsulURL) -> + %fetch configuration from consul, assumes it is a json + %returns it as a map. can be encoded again. + {RC, RB} = consul_read_kv(XER, Appname, ConsulURL), + case RC of + 200 -> {200, jiffy:decode(RB, [return_maps])}; %configuration is a JSON + _ -> {RC, RB} + end. + +consul_get_preferences(XER, Appname, ConsulURL) -> + %This function is currently only used in testing and is not used in resource_handler, but could be useful later + %returns it as a map. can be encoded again. + {RC, RB} = consul_read_kv(XER, ?PrefKey(Appname), ConsulURL), + case RC of + 200 -> {200, jiffy:decode(RB, [return_maps])}; %configuration is a JSON + _ -> {RC, RB} + end. + +consul_get_service_ip_port(XER, Appname, ConsulURL) -> + %use when you are expecting consul_get_service to return a list of exactly one service and all you want is ip:port + M = lists:nth(1, consul_get_service(XER, Appname, ConsulURL)), + {maps:get(<<"ServiceAddress">>, M), maps:get(<<"ServicePort">>, M)}. + +consul_push_config(XER, Appname, ConsulURL, Config) -> + %pushes Config into Consul under the key "Appname". + %TODO: Possibly this should be under "Appname:config" to be consistent with preferences but this came first and that's an invasive change. + %the config has not been jiffy'd prior to this function + consul_write_kv(XER, Appname, jiffy:encode(Config), ConsulURL). + +consul_push_preferences(XER, Appname, ConsulURL, Preferences) -> + %pushes the preferences into Consul under the key "Appname:preferences" + %the config has not been jiffy'd prior to this function + consul_write_kv(XER, ?PrefKey(Appname), jiffy:encode(Preferences), ConsulURL). + +consul_delete_config(XER, Appname, ConsulURL) -> + consul_delete_kv(XER, Appname, ConsulURL). + +consul_delete_preferences(XER, Appname, ConsulURL) -> + consul_delete_kv(XER, ?PrefKey(Appname), ConsulURL). + +consul_bind_config(XER, Appname, ConsulURL) -> + URL = ?SC([util:resolve_cbs(XER, ConsulURL), "/service_component/", Appname]), + {ReturnCode, ReturnBody} = httpabs:get(XER, URL), + case ReturnCode of + 200 -> {200, jiffy:decode(ReturnBody)}; + _ -> {ReturnCode, ReturnBody} %do not try to decode if not correct + end. diff --git a/src/httpabs.erl b/src/httpabs.erl new file mode 100644 index 0000000..bc9e068 --- /dev/null +++ b/src/httpabs.erl @@ -0,0 +1,118 @@ +% ============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. + +-module(httpabs). +-export([get/2, + post/4, %I miss python's default arguments.. + post/5, + put/4, + delete/2 + ]). +-include("application.hrl"). +-define(SC(L), util:concat(L)). + +%NOTE +%Consider the Erlang statement: +% +%{ok, {{"HTTP/1.1",ReturnCode, State}, Head, Body}} = httpc:get(URL). +%CDAP returns error messages in the “Body” field above. +% +%However, Consul: +%1) Always (in all HTTP failures I’ve tested) returns Body == “500\n” +%2) Returns the error message in the State field +% +%Example: +% +%{{"HTTP/1.0",404,"Client Error: Not Found for url: http://consul.[...].com:8500/v1/kv/hwtestYOUHAVEFAILEDME:rel"},[{"date","Mon, 14 Nov 2016 14:41:03 GMT"},{"server","Werkzeug/0.11.11 Python/3.5.1"},{"content-length","4"},{"content-type","application/json"}],"500\n"} +% +%This means that error handling in HTTP is not consistent across CDAP and Consul. +% +%Thus below, on a failure, I return the concatenation of State and Body + +%%% +%%%HELPER +%%% +-spec parse_response({error|ok, any()}, string()) -> httpstat(). +parse_response({Status, Response}, URL) -> + case Status of + error -> + lager:error("httpc error: cannot hit: ~s", [URL]), + case Response of + no_scheme -> {400, io_lib:format("ERROR: The following URL is malformed: ~s", [URL])}; + {bad_body, _} -> {400, "ERROR: The request Body is malformed"}; + {bad_body_generator,_} -> {400, "ERROR: The request Body is malformed"}; + _ -> + lager:error(io_lib:format("Unexpected ERROR hitting ~s", [URL])), + {504, list_to_binary(io_lib:format("ERROR: The following URL is unreachable or the request was unable to be parsed due to an unknown error: ~s", [URL]))} %Are there other reasons other than bad body and unreachable that crash request? (Sneak peak: the answer is probably) + end; + ok -> + {{_, ReturnCode, State}, _Head, Body} = Response, + case ReturnCode of + 200 -> + {ReturnCode, Body}; + _ -> + lager:error("Error While hitting ~s, Non-200 status code returned. HTTP Code ~p, State ~s, ResponseBody ~s:", [URL, ReturnCode, State, Body]), + %see Note at the top of this file + RetBody = ?SC(["State: ", State, ". Return Body: ", Body]), + {ReturnCode, RetBody} + end + end. + +sanitize(URL) -> + %allow URL to look like "www.foo.com" or <<"www.foo.com">>, trim it + case is_binary(URL) of + true -> string:strip(binary_to_list(URL)); + false -> string:strip(URL) + end. + +%anywhere you see any() is essentially lazy typing.. fix these someday when time is abundant +-spec post(string(), string()|binary(), string(), any()) -> httpstat(). +post(XER, URL, ContentType, Body) -> + %post that sends the XER, no headers signature + Headers = [{"x-ecomp-requestid", XER}], + U = sanitize(URL), + parse_response(httpc:request(post, {U, Headers, ContentType, Body}, [],[]), U). + +-spec post(string(), string()|binary(), list(), string(), any()) -> httpstat(). +post(XER, URL, Headers, ContentType, Body) -> + %post that sends XER, appends the header onto the list of desired headers + U = sanitize(URL), + parse_response(httpc:request(post, {U, [{"x-ecomp-requestid", XER} | Headers], ContentType, Body}, [],[]), U). + +-spec get(string(), string()|binary()) -> httpstat(). +get(XER, URL) -> + %http get that always sends the XER.. even if the server doesn't want it; maybe this will blow up on me one day. + U = sanitize(URL), + Headers = [{"x-ecomp-requestid", XER}], + parse_response(httpc:request(get, {U, Headers}, [], []), U). + +-spec put(string(), string()|binary(), string(), any()) -> httpstat(). +put(XER, URL, ContentType, Body) -> + %http put that always sends the XER + U = sanitize(URL), + Headers = [{"x-ecomp-requestid", XER}], + parse_response(httpc:request(put, {U, Headers, ContentType, Body}, [],[]), U). + +-spec delete(string(), string()|binary()) -> httpstat(). +delete(XER, URL) -> + %http delete that always sends the XER + U = sanitize(URL), + Headers = [{"x-ecomp-requestid", XER}], + parse_response(httpc:request(delete, {U, Headers}, [],[]), U). diff --git a/src/httpabs_tests.erl b/src/httpabs_tests.erl new file mode 100644 index 0000000..d8ad529 --- /dev/null +++ b/src/httpabs_tests.erl @@ -0,0 +1,33 @@ +% ============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. + +-module(httpabs_tests). +-include_lib("eunit/include/eunit.hrl"). +-import(httpabs, [ + sanitize/1 + ] + ). + +sanitize_test() -> + ?assert(sanitize(<<" www.foo.com ">>) == "www.foo.com"), + ?assert(sanitize(" www.foo.com ") == "www.foo.com"), + ?assert(sanitize(<<"www.foo.com">>) == "www.foo.com"). + + diff --git a/src/logging.erl b/src/logging.erl new file mode 100644 index 0000000..942637d --- /dev/null +++ b/src/logging.erl @@ -0,0 +1,157 @@ +% ============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. + +-module(logging). +-export([ + audit/3, + metrics/3, + err/2 + ]). + +-import(util, [iso/0, iso_elapsed/2, to_str/1, ip_to_str/1]). +%..lazy macros +-define(SC(L), util:concat(L)). +-define(PV(Name, PL), proplists:get_value(Name, PL, "")). + +%This module is intended to support the logging format standard for ONAP/ECOMP components. SOmetimes that is reffered to as "EELF". + +%levels are none | debug | info | notice | warning | error | critical | alert | emergency. + +%%% +%%%Helper functions +%%% +pid() -> pid_to_list(self()). +%they wanted milleseconds but they are getting seconds rounded to ms because I don't have an erlang BIF that gives me this +elapsed(Endtime, Starttime) -> to_str(iso_elapsed(Endtime, Starttime)*1000). + +start_end_elapsed(ArgPropl) -> + %returns start time, end time,... and elapsed time + EndT = iso(), + StartT = ?PV(bts, ArgPropl), + ElapT = elapsed(EndT, StartT), + {StartT, EndT, ElapT}. + +%things this logging class can compute based on the Req so need not be in every logging function +server_add(Req) -> + {MyUrl, _} = cowboy_req:host_url((leptus_req:get_req(Req))), + %discard HTTP portion using Erlang binary matching + <<_:7/binary, URL/binary>> = MyUrl, + URL. + +ip(Req) -> ip_to_str(leptus_req:peer(Req)). + +path(Req) -> + %get us the method and API path that was hit from the request + {Path, {_,_,_,_,_,Method,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_}} = cowboy_req:path(leptus_req:get_req(Req)), + ?SC([Method, " ", Path]). + +%%% +%%%External +%%% + +audit(Sev, Req, ArgPropl) -> + F = case Sev of + info -> fun(M)->audit:info(M) end; %cant use the shorthand "fun -> audit:info/2" because of parse_transform + warning -> fun(M)->audit:warning(M) end + end, + %The audit field list: + % + %1 BeginTimestamp Implemented (bts) + %2 EndTimestamp Auto Injected when this is called + %3 RequestID Implemented (xer) + %4 serviceInstanceID + %5 threadId Auto Injected... however this is a VM language and so this is the Erlang process PID, not the "OS level thread id". Unclear what they want here. + %6 physical/virtual server name  + %7 serviceName Implemented (from Req) + %8 PartnerName + %9 StatusCode + %10 ResponseCode Implemented (rcode) + %11 Response Description Will not implement. This says "human readable description of the *code*. They don't want the response here. I won't do that because this is a generic function that gets called no matter what the code is, so I can't do that. But since this is supposed to be human readable, they can look up the code in the swagger spec. + %12 instanceUUID + %13 Category log level Implemented (Sev) + %14 Severity + %15 Server IP address Implemented (from Req) + %16 ElapsedTime Auto Injected but THIS IS SO DUMB TO BE IN THE STANDARD WASTING DISK SPACE THIS IS DIRECTLY COMPUTABLE FROM 1,2 WTF + %17 Server + %18 ClientIPaddress Implemented (from Req) + %19 class name Implemented (mod), though docs say OOP, I am using the Erlang module here + %20 Unused Implemented.. + %21 ProcessKey + %22 CustomField1 + %23 CustomField2 + %24 CustomField3 + %25 CustomField4 + %26 detailMessage Implemented (msg) + + {StartT, EndT, ElapT} = start_end_elapsed(ArgPropl), + %compute message + Message = ?SC([StartT, "|", EndT, "|", ?PV(xer, ArgPropl), "||", pid(), "||", path(Req), "|||", to_str(?PV(rcode, ArgPropl)), "|see swagger spec||", to_str(Sev), "||", server_add(Req), "|", ElapT, "||", ip(Req), "|", ?PV(mod, ArgPropl), "|||||||", ?PV(msg, ArgPropl)]), + F(Message). + +metrics(Sev, Req, ArgPropl) -> + F = case Sev of + debug -> fun(M)->metrics:debug(M) end; + info -> fun(M)->metrics:info(M) end; + warning -> fun(M)->metrics:warning(M) end + end, + %The metrics field list: + %SAME AS METRICS 1-8 + %_____ + %9 TargetEntity Implemented (tgte) + %10 TargetServiceName Implemented (tgts) + %11 Status Code Implemented (tgtrsc) + %_____ + %SAME AS METRICS 9 -> + %total 29 fields + + {StartT, EndT, ElapT} = start_end_elapsed(ArgPropl), + %compute message + Message = ?SC([StartT, "|", EndT, "|", ?PV(xer, ArgPropl), "||", pid(), "||", path(Req), "||", ?PV(tgte, ArgPropl), "|", ?PV(tgts, ArgPropl), "|", to_str(?PV(tgtrsc, ArgPropl)), "|", to_str(?PV(rcode, ArgPropl)), "|see swagger spec||", to_str(Sev), "||", server_add(Req), "|", ElapT, "||", ip(Req), "|", ?PV(mod, ArgPropl), "||||||||", ?PV(msg, ArgPropl)]), + F(Message). + +err(Sev, ArgPropl) -> + F = case Sev of + warning -> fun(M)->error:warning(M) end; + error -> fun(M)->error:error(M) end; + critical -> fun(M)->error:critical(M) end; + alert -> fun(M)->error:alert(M) end; + emergency -> fun(M)->error:emergency(M) end + end, + SevInLog = case Sev of + warning -> "WARN"; + error -> "ERROR"; + _ -> "FATAL" + end, + %Error field list: + %1 Timestamp Auto Injected when this is called + %2 RequestID Implemented + %3 ThreadId Auto Injected... however this is a VM language and so this is the Erlang thread PID. Not the "OS level pid". Unclear what they want here. + %4 ServiceName Implemented + %5 PartnerName + %6 TargetEntity + %7 TargetServiceName + %8 ErrorCategory Implemented + %9 ErrorCode + %10 ErrorDescription This is what I'm using detailMessage for, these seem to be the same to me. + %11 detailMessage Implemented + + Message = ?SC([iso(), "|", ?PV(xer, ArgPropl), "|", pid(), "|", ?PV(servn, ArgPropl), "||||", SevInLog, "|||", ?PV(msg, ArgPropl)]), + F(Message). + diff --git a/src/resource_handler.erl b/src/resource_handler.erl new file mode 100644 index 0000000..a9703fc --- /dev/null +++ b/src/resource_handler.erl @@ -0,0 +1,465 @@ +-module(resource_handler). +-compile({parse_transform, leptus_pt}). + +%% leptus callbacks +-export([init/3]). +-export([terminate/4]). +-export([get/3, put/3, delete/3, post/3]). +-export([cross_domains/3]). + +%%for keeping state +%%The application record is defined in application.hrl +%%In Mnesia, the first element is the type of record and the second element is the key +%%http://erlang.org/doc/apps/mnesia/Mnesia_chap2.html +-include("application.hrl"). + +-define(CONSURL, dict:fetch("consulurl", State)). +-define(CDAPURL, dict:fetch("cdapurl", State)). +%below come from config map +-define(HCInterval, maps:get(<<"hcinterval">>, dict:fetch("configmap", State))). +-define(AutoDeregisterAfter, maps:get(<<"autoderegisterafter">>, dict:fetch("configmap", State))). +-define(PipelineHealthLimit, maps:get(<<"pipelinehealthlimit">>, dict:fetch("configmap", State))). +-define(PUBLICFIELDS, [<<"appname">>, <<"apptype">>, <<"namespace">>, <<"healthcheckurl">>, <<"metricsurl">>, <<"url">>, <<"connectionurl">>, <<"serviceendpoints">>]). + +%super lazy macros/imports... +-import(logging, [audit/3, metrics/3, err/2]). +-import(util, [iso/0, to_str/1]). +%lazy concat +-define(SC(L), util:concat(L)). +%lazy shorthand to write info audit records. man I miss defines in python. c ftw. +-define(AUDI(Req, Bts, XER, Rcode), audit(info, Req, [{bts, Bts}, {xer,XER}, {rcode, RCode}, {mod, mod()}])). + + +%%% +%%Helper functions +%%% +mod() -> to_str(?MODULE). + +get_request_id(Req) -> + %ECOMP request tracing + %see if we got a X-ECOMP-REQUESTID, or generate a new one if not + HXER = leptus_req:header(Req, <<"x-ecomp-requestid">>), + case HXER of + undefined -> + XER = util:gen_uuid(), + %LOL, use the client ip here to shame them into their request id + audit(warning, Req, [{bts, iso()}, {xer, XER}, {mod, mod()}, {msg, "Request is missing requestID. Assigned this one."}]), %eelf documentation says to log this message if requestid was missing + XER; + _ -> + binary_to_list(HXER) %httpc expects strings as headers, so this needs to be str for subsequent passing + end. + +%shared-code function initlization that creates a begining timestamp and gets or generates a request ID +init_api_call(Req) -> + Bts = iso(), %record begining timestamp + XER = get_request_id(Req), %get or generate XER + {Bts, XER}. + +lookup_application(Appname) -> + %do a lookup in mnesia of an appname + Ret = mnesia:transaction(fun() -> mnesia:match_object(application, {application, Appname, '_', '_', '_', '_', '_', '_', '_', '_'}, read) end), + case Ret of + {atomic, []} -> none; %no matches + {atomic, [Rec]} -> Rec + %fail hard if there was more than one result + end. + +appname_to_application_map(Appname) -> + %return a Map of an Mnesia record + Rec = lookup_application(Appname), + case Rec of + none -> none; + {application, Appname, AppType, Namespace, Healthcheckurl, Metricsurl, Url, Connectionurl, ServiceEndpoints, CreationTime} -> + #{<<"appname">> => Appname, + <<"apptype">> => AppType, + <<"namespace">> => Namespace, + <<"healthcheckurl">> => Healthcheckurl, + <<"metricsurl">> => Metricsurl, + <<"url">> => Url, + <<"connectionurl">> => Connectionurl, + <<"serviceendpoints">> => ServiceEndpoints, + <<"creationtime">> => CreationTime + } + end. + +appname_to_field_vals(Appname, FieldList) -> + %Return just a list of values of an application with fields FieldList + M = appname_to_application_map(Appname), + case M of + none -> none; + _ -> [maps:get(F, M) || F <- FieldList] + end. + +appname_to_application_http(XER, Appname, State) -> + %Return an HTTP response of an application record. If this is a program flowlet style app, additionally return it's bound and unbound config + A = appname_to_application_map(Appname), + case A of + none -> {404, "", State}; + _ -> + Body = maps:with(?PUBLICFIELDS, A), + case maps:get(<<"apptype">>, Body) of + %if program-flowlet style app, append the bound and unbound config into the return JSON + <<"program-flowlet">> -> + UB = case consul_interface:consul_get_configuration(XER, Appname, ?CONSURL) of + {200, Unbound} -> Unbound; + {_, _} -> <<"WARNING: COULD NOT FETCH CONFIG FROM CONSUL">> + end, + B = case cdap_interface:get_app_config(XER, Appname, maps:get(<<"namespace">>, Body), ?CDAPURL) of + {200, Bound} -> Bound; + {_, _} -> <<"WARNING: COULD NOT FETCH CONFIG FROM CDAP">> + end, + CM = #{<<"unbound_config">> => UB, + <<"bound_config">> => B}, + {200, {json, maps:merge(Body, CM)}, State}; + %TODO! can we do something for hydrator apps? + <<"hydrator-pipeline">> -> + {200, {json, Body}, State} + end + end. + +-spec parse_progflow_put_body_map(map()) -> + {binary(), binary(), string(), binary(), binary(), map(), map(), any(), lprogram(), any()}. %TODO! Spec parsedservices and parsedprogrampreferences so we don't have any() here... +parse_progflow_put_body_map(Body) -> + Namespace = maps:get(<<"namespace">>, Body), + Streamname = maps:get(<<"streamname">>, Body), + JarURL = maps:get(<<"jar_url">>, Body), + ArtifactName = maps:get(<<"artifact_name">>, Body), + ArtifactVersion = maps:get(<<"artifact_version">>, Body), + AppConfig = maps:get(<<"app_config">>, Body), + AppPreferences = maps:get(<<"app_preferences">>, Body), + ParsedServices = lists:map(fun(S) -> {maps:get(<<"service_name">>, S), + maps:get(<<"service_endpoint">>, S), + maps:get(<<"endpoint_method">>, S)} + end, maps:get(<<"services">>, Body)), + Programs = lists:map(fun(P) -> #program{type=maps:get(<<"program_type">>, P), + id= maps:get(<<"program_id">>, P)} + end, maps:get(<<"programs">>, Body)), + ParsedProgramPreferences = lists:map(fun(P) -> {maps:get(<<"program_type">>, P), + maps:get(<<"program_id">>, P), + maps:get(<<"program_pref">>, P)} + end, maps:get(<<"program_preferences">>, Body)), + {Namespace, Streamname, JarURL, ArtifactName, ArtifactVersion, AppConfig, AppPreferences, ParsedServices, Programs, ParsedProgramPreferences}. + +parse_hydrator_pipeline_put_body_map(Body) -> + Namespace = maps:get(<<"namespace">>, Body), + Streamname = maps:get(<<"streamname">>, Body), + PipelineConfigJsonURL = maps:get(<<"pipeline_config_json_url">>, Body), + + %Dependencies is optional. This function will normalize it's return with [] if the dependencies key was not passed in. + ParsedDependencies = case maps:is_key(<<"dependencies">>, Body) of + true -> + D = maps:get(<<"dependencies">>, Body), + %crash and let caller deal with it if not a list or if required keys are missing. Else parse it into + % {artifact-extends-header, artifact_name, artifact-version-header, artifact_url} + %tuples + % + %regarding the binart_to_lists: these all come in as binaries but they need to be "strings" (which are just lists of integers in erlang) + %for headers requiring strings, see http://stackoverflow.com/questions/28292576/setting-headers-in-a-httpc-post-request-in-erlang + % + lists:map(fun(X) -> {binary_to_list(maps:get(<<"artifact_extends_header">>, X)), + maps:get(<<"artifact_name">>, X), + binary_to_list(maps:get(<<"artifact_version_header">>, X)), + maps:get(<<"artifact_url">>, X), + %even if dependencies is specified, ui_properties is optional. This will normalize it's return with 'none' if not passed in + case maps:is_key(<<"ui_properties_url">>, X) of true -> maps:get(<<"ui_properties_url">>, X); false -> none end + } end, D); + false -> [] %normalize optional user input into []; just prevents user from having to explicitly pass in [] + end, + + {Namespace, Streamname, PipelineConfigJsonURL, ParsedDependencies}. + +parse_put_body(B) -> + Body = jiffy:decode(B, [return_maps]), + Type = maps:get(<<"cdap_application_type">>, Body), + case Type of + <<"program-flowlet">> -> + {pf, <<"program-flowlet">>, parse_progflow_put_body_map(Body)}; + <<"hydrator-pipeline">> -> + {hp, <<"hydrator-pipeline">>, parse_hydrator_pipeline_put_body_map(Body)}; + _ -> + unsupported + end. + +delete_app_helper(Appname, State, XER, Req) -> + %Helper because it is used by both delete and rollback on failed deploy + % + %%Internal Crisis Alert: + % + %I pondered this for some time. There are three points of state for this: the cdap cluster, consul, and the broker's internal database + %The question is, if something in the delete fails, do we: + %1) Tell the user to try again later + %2) Clean up as much as we can, log the error, and keep going + % + %I have decided for now on taking number 2). This is the "Cloudify" way of doing things where you don't raise a NonRecoerable in a Delete operation. + %This has the benefit that this delete operation can be used as the *rollback*, so if anything fails in the deploy, this delete function is called to clean up any dirty state. + % + %Number 1 is not so straitforward, because "putting back things the way they were" is difficult. For example, the deletion from CDAP succeeds, but Consul can't be reached. + %What happens? Do I *redeploy* the CDAP app to try to make their state as it was before the botched delete was called? + % + %My conclusion is that transactions across distributed systems is hard. It's much easier if it is all local (e.g., Transactions in a single Postgres DB) + % + %SO, as a result of this decision, the broker does *NOT* assert the status code of any delete operations to be 200. + %The only way this function does not return a 200 is if I can't even delete from my own database. + % + metrics(info, Req, [{bts, iso()}, {xer, XER}, {mod, mod()}, {msg, io_lib:format("Delete recieved for ~s", [Appname])}]), + case appname_to_field_vals(Appname, [<<"apptype">>, <<"namespace">>]) of + none -> {404, "Tried to delete an application that was not registered", State}; + [AppType, Namespace] -> + try + case AppType of + <<"program-flowlet">> -> + ok = workflows:undeploy_cdap_app(Req, XER, Appname, ?CDAPURL, ?CONSURL, Namespace), + %delete from the program-flowlet supplementary table + {atomic, ok} = mnesia:transaction(fun() -> mnesia:delete(prog_flow_supp, Appname, write) end); + <<"hydrator-pipeline">> -> ok = workflows:undeploy_hydrator_pipeline(Req, XER, Appname, Namespace, ?CDAPURL, ?CONSURL) + end, + %delete from application table (shared between both types of apps) + {atomic, ok} = mnesia:transaction(fun() -> mnesia:delete(application, Appname, write) end), + {200, "", State} %Return + catch + %this is really bad, means I can't even delete from my own database. For now, log and pray. + %generic failure catch-all, catastrophic + Class:Reason -> + err(emergency, [{xer, XER}, {msg, io_lib:format("Catastrophic failure, can't delete ~s from my database. ~s:~s", [Appname, Class, Reason])}]), + err(error, [{xer, XER}, {msg, io_lib:format("~nError Stacktrace:~s", [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})])}]), + {500, "Please report this error", State} + end + end. + +%%%CALLBACKS %%% +init(_Route, _Req, State) -> + {ok, State}. +terminate(_Reason, _Route, _Req, _State) -> + ok. +%%%FOR Cors support +%%%Note! only matches on host. Does not handle ports. See: https://github.com/s1n4/leptus/issues/55 +cross_domains(_Route, _Req, State) -> + {['_'], State}. + +%%%GET Methods +get("/", Req, State) -> + %The broker's "info" endpoint; returns some possibly useful information + {Bts, XER} = init_api_call(Req), + Apps = util:get_all_appnames_from_db(), + {UT, _} = statistics(wall_clock), + CDAPVer = cdap_interface:get_cdap_cluster_version(XER, ?CDAPURL), + RB = {[ + {<<"cdap cluster version">>, CDAPVer}, + {<<"managed cdap url">>, ?CDAPURL}, + {<<"cdap GUI port">>, cdap_interface:get_cdap_gui_port_from_version(CDAPVer)}, + {<<"number of applications registered">>, length(Apps)}, + {<<"uptime (s)">>, UT/1000}, + {<<"broker API version">>, util:get_my_version()} + ]}, + {RCode, RBody, RState} = {200, {json, RB}, State}, + ?AUDI(Req, Bts, XER, Rcode), + {RCode, RBody, RState}; +get("/application", Req, State) -> + %get a list of all registered apps + {Bts, XER} = init_api_call(Req), + {RCode, RBody, RState} = {200, {json, util:get_all_appnames_from_db()}, State}, + ?AUDI(Req, Bts, XER, Rcode), + {RCode, RBody, RState}; +get("/application/:appname", Req, State) -> + %get information about a registered application + {Bts, XER} = init_api_call(Req), + Appname = leptus_req:param(Req, appname), + {RCode, RBody, RState} = appname_to_application_http(XER, Appname, State), + ?AUDI(Req, Bts, XER, Rcode), + {RCode, RBody, RState}; +get("/application/:appname/metrics", Req, State) -> + %get metrics for a registered application + {Bts, XER} = init_api_call(Req), + Appname = leptus_req:param(Req, appname), + {RCode, RBody, RState} = case appname_to_field_vals(Appname, [<<"apptype">>, <<"namespace">>]) of + none -> {404, "", State}; + [<<"program-flowlet">>, Namespace] -> + {ReturnCode, ReturnBody} = cdap_interface:get_app_metrics(XER, Appname, Namespace, ?CDAPURL), %warning, see note in README, this always reutrns 200 + {ReturnCode, {json, ReturnBody}, State}; + [<<"hydrator-pipeline">>, Namespace] -> + lager:warning("WARNING, metrics not actually implemented yet for pipelines!!"), + {ReturnCode, ReturnBody} = cdap_interface:get_pipeline_metrics(Appname, Namespace, ?CDAPURL), + {ReturnCode, {json, ReturnBody}, State} + end, + ?AUDI(Req, Bts, XER, Rcode), + {RCode, RBody, RState}; +get("/application/:appname/healthcheck", Req, State) -> + %get healthcheck of an application + {Bts, XER} = init_api_call(Req), + Appname = leptus_req:param(Req, appname), + lager:info(io_lib:format("Get Healthcheck recieved for ~s", [Appname])), + {RCode, RBody, RState} = case appname_to_field_vals(Appname, [<<"apptype">>, <<"namespace">>]) of + none -> {404, "", State}; + [<<"program-flowlet">>, Namespace] -> + {cdap_interface:get_app_healthcheck(XER, Appname, Namespace, ?CDAPURL), "", State}; + [<<"hydrator-pipeline">>, Namespace] -> + {cdap_interface:get_pipeline_healthcheck(XER, Appname, Namespace, ?CDAPURL, ?PipelineHealthLimit), "", State} + end, + ?AUDI(Req, Bts, XER, Rcode), + {RCode, RBody, RState}. + +%%%DELETE Methods +delete("/application/:appname", Req, State) -> + %Uninstall and delete a CDAP app + {Bts, XER} = init_api_call(Req), + Appname = leptus_req:param(Req, appname), + {RCode, RBody, RState} = delete_app_helper(Appname, State, XER, Req), + ?AUDI(Req, Bts, XER, Rcode), + {RCode, RBody, RState}. + +%%%PUT Methods +put("/application/:appname", Req, State) -> + %create a new registration; deploys and starts a cdap application + {Bts, XER} = init_api_call(Req), + Appname = leptus_req:param(Req, appname), + {RCode, RBody, RState} = case appname_to_field_vals(Appname, [<<"appname">>]) of + [Appname] -> + {400, "Put recieved on /application/:appname but appname is already registered. Call /application/:appname/reconfigure if trying to reconfigure or delete first", State}; + none -> %no matches, create the resource, return the application record + %Initial put requires the put body parameters + case try parse_put_body(leptus_req:body_raw(Req)) catch _:_ -> invalid end of + %could not parse the body + invalid -> {400, "Invalid PUT Body or unparseable URL", State}; + + %unsupported cdap application type + unsupported -> {404, "Unsupported CDAP Application Type", State}; + + {Type, AppType, Params} -> + %form shared info + %hateaos cuz they aintaos + {RequestUrl,_} = cowboy_req:url((leptus_req:get_req(Req))), + Metricsurl = <>/binary>>, + Healthcheckurl = <>/binary>>, + + try + case Type of + hp -> + {Namespace, Streamname, PipelineConfigJsonURL, ParsedDependencies} = Params, + ConnectionURL = cdap_interface:form_stream_url_from_streamname(?CDAPURL, Namespace, Streamname), + + %TODO: This! + ServiceEndpoints = [], %unclear if this is possible with pipelines + + %write into mnesia, deploy + A = #application{appname = Appname, apptype = AppType, namespace = Namespace, healthcheckurl = Healthcheckurl, metricsurl = Metricsurl, url = RequestUrl, connectionurl = ConnectionURL, serviceendpoints = ServiceEndpoints, creationtime=erlang:system_time()}, + {atomic,ok} = mnesia:transaction(fun() -> mnesia:write(A) end), + ok = workflows:deploy_hydrator_pipeline(Req, XER, Appname, Namespace, ?CDAPURL, PipelineConfigJsonURL, ParsedDependencies, ?CONSURL, RequestUrl, Healthcheckurl, ?HCInterval, ?AutoDeregisterAfter), + metrics(info, Req, [{bts, iso()}, {xer, XER}, {mod, mod()}, {msg, io_lib:format("New Hydrator Application Created: ~p", [lager:pr(A, ?MODULE)])}]), %see Record Pretty Printing: https://github.com/basho/lager + ok; + pf -> + {Namespace, Streamname, JarURL, ArtifactName, ArtifactVersion, AppConfig, AppPreferences, ParsedServices, Programs, ParsedProgramPreferences} = Params, + %Form URLs that are part of the record + %NOTE: These are both String concatenation functions and neither make an HTTP call so not catching normal {Code, Status} return here + ConnectionURL = cdap_interface:form_stream_url_from_streamname(?CDAPURL, Namespace, Streamname), + ServiceEndpoints = lists:map(fun(X) -> cdap_interface:form_service_json_from_service_tuple(Appname, Namespace, ?CDAPURL, X) end, ParsedServices), + + %write into mnesia. deploy + A = #application{appname = Appname, apptype = AppType, namespace = Namespace, healthcheckurl = Healthcheckurl, metricsurl = Metricsurl, url = RequestUrl, connectionurl = ConnectionURL, serviceendpoints = ServiceEndpoints, creationtime=erlang:system_time()}, + ASupplemental = #prog_flow_supp{appname = Appname, programs = Programs}, + {atomic,ok} = mnesia:transaction(fun() -> mnesia:write(A) end), %warning, here be mnesia magic that knows what table you want to write to based on the record type + {atomic,ok} = mnesia:transaction(fun() -> mnesia:write(ASupplemental) end), %warning: "" + ok = workflows:deploy_cdap_app(Req, XER, Appname, ?CONSURL, ?CDAPURL, ?HCInterval, ?AutoDeregisterAfter, AppConfig, JarURL, ArtifactName, ArtifactVersion, Namespace, AppPreferences, ParsedProgramPreferences, Programs, RequestUrl, Healthcheckurl), + metrics(info, Req, [{bts, iso()}, {xer, XER}, {mod, mod()}, {msg, io_lib:format("New Program-Flowlet Application Created: ~p with supplemental data: ~p", [lager:pr(A, ?MODULE), lager:pr(ASupplemental, ?MODULE)])}]), + ok + end, + appname_to_application_http(XER, Appname, State) + + catch + %catch a bad HTTP error code + error:{badmatch, {BadErrorCode, BadStatusMsg}} -> + err(error, [{xer, XER}, {msg, io_lib:format("Badmatch caught in Deploy. Rolling Back. ~p ~s", [BadErrorCode, BadStatusMsg])}]), + {_,_,_} = delete_app_helper(Appname, State, XER, Req), + {BadErrorCode, BadStatusMsg, State}; %pass the bad error/status back to user + Class:Reason -> + %generic failure catch-all, catastrophic + err(error, [{xer, XER}, {msg, io_lib:format("~nUnexpected Exception caught in Deploy. Error Stacktrace:~s", [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})])}]), + {_,_,_} = delete_app_helper(Appname, State, XER, Req), + {500, "Please report this error", State} + end + end + end, + ?AUDI(Req, Bts, XER, Rcode), + {RCode, RBody, RState}; +put("/application/:appname/reconfigure", Req, State) -> + %if appname already is registerd, trigger a consul pull and reconfigure + {Bts, XER} = init_api_call(Req), + Appname = leptus_req:param(Req, appname), + {RCode, RBody, RState} = case appname_to_field_vals(Appname, [<<"namespace">>]) of + none -> {404, "Reconfigure recieved but the app is not registered", State}; + [Namespace] -> + D = jiffy:decode(leptus_req:body_raw(Req), [return_maps]), + case try maps:get(<<"config">>, D) catch _:_ -> invalid end of + invalid -> {400, "Invalid PUT Reconfigure Body: key 'config' is missing", State}; + Config -> + case try maps:get(<<"reconfiguration_type">>, D) catch _:_ -> invalid end of + invalid -> {400, "Invalid PUT Reconfigure Body: key 'reconfiguration_type' is missing", State}; + <<"program-flowlet-app-config">> -> + %reconfigure a program-flowlet style app's app config + try + ok = workflows:app_config_reconfigure(Req, XER, Appname, Namespace, ?CONSURL, ?CDAPURL, Config), + {200, "", State} + catch Class:Reason -> + err(error, [{xer,XER}, {msg, io_lib:format("~nError Stacktrace:~s", [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})])}]), + {500, "", State} + end; + <<"program-flowlet-app-preferences">> -> + %reconfigure a program-flowlet style app's app config + try + ok = workflows:app_preferences_reconfigure(Req, XER, Appname, Namespace, ?CONSURL, ?CDAPURL, Config), + {200, "", State} + catch Class:Reason -> + err(error, [{xer,XER}, {msg, io_lib:format("~nError Stacktrace:~s", [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})])}]), + {500, "", State} + end; + <<"program-flowlet-smart">> -> + %try to "figure out" whether the supplied JSON contains keys in appconfig, app preferences, or both + try + ok = workflows:smart_reconfigure(Req, XER, Appname, Namespace, ?CONSURL, ?CDAPURL, Config), + {200, "", State} + catch + %catch a bad HTTP error code; also catches the non-overlapping configuration case + error:{badmatch, {BadErrorCode, BadStatusMsg}} -> + err(error, [{xer, XER}, {msg, io_lib:format("~p ~s", [BadErrorCode, BadStatusMsg])}]), + {BadErrorCode, BadStatusMsg, State}; + Class:Reason -> + err(error, [{xer,XER}, {msg, io_lib:format("~nError Stacktrace:~s", [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})])}]), + {500, "", State} + end; + NI -> + %TODO! Implement other types of reconfig once CDAP APIs exis + {501, io_lib:format("This type (~s) of reconfiguration is not implemented", [NI]), State} + end + end + end, + ?AUDI(Req, Bts, XER, Rcode), + {RCode, RBody, RState}. + +%%%POST methods +post("/application/delete", Req, State) -> + %This follows the AWS S3 Multi Key Delete: http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html + %Except I added an additional special value called "*" + {Bts, XER} = init_api_call(Req), + {RCode, RBody, RState} = case try + B = maps:get(<<"appnames">>, jiffy:decode(leptus_req:body_raw(Req), [return_maps])), + true = erlang:is_list(B), + B + catch _:_ -> + invalid + end + of + invalid -> {400, "Invalid PUT Body", State}; + IDs -> + case IDs of + [] -> {200, "EMPTY PUT BODY", State}; + _ -> + %<<"*">> -> + %this block deleted all apps, but decided this backdoor wasn't very RESTy + %% {atomic, Apps} = mnesia:transaction(fun() -> mnesia:match_object(application, {application, '_', '_', '_', '_', '_', '_', '_', '_', '_'}, read) end), + % AppsToDelete = lists:map(fun(X) -> {application, Appname, _,_,_,_,_,_,_,_} = X, Appname end, Apps), + Returns = lists:map(fun(X) -> delete_app_helper(X, State, XER, Req) end, IDs), + RL = lists:map(fun({RC, _, _}) -> RC end, Returns), + {200, jiffy:encode(RL), State} + end + end, + ?AUDI(Req, Bts, XER, Rcode), + {RCode, RBody, RState}. diff --git a/src/util.erl b/src/util.erl new file mode 100644 index 0000000..d96675b --- /dev/null +++ b/src/util.erl @@ -0,0 +1,192 @@ +% ============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. + +-module(util). +-include("application.hrl"). + +-export([concat/1, + get_platform_envs_and_config/0, + resolve_cbs/2, + initialize_database/0, + get_all_appnames_from_db/0, + get_my_version/0, + get_programs_for_pfapp_from_db/1, + gen_uuid/0, + iso/0, + iso_elapsed/2, + to_str/1, + ip_to_str/1, + update_with_new_config_map/2, + ejson_to_map/1 + ]). + +%http://stackoverflow.com/questions/39757020/erlang-drying-up-stringbinary-concatenation +%NOTE! Does not work or bomb when an element in the list is an atom. Must be a string or binary. Maybe add a check for this +to_string(Value) when is_binary(Value) -> binary_to_list(Value); +to_string(Value) -> Value. +concat(List) -> + lists:flatten(lists:map(fun to_string/1, List)). + +resolve_cbs(XER, ConsulURL) -> + %Ideally this function would dissapear if we get real DNS. This essentially is doing an SRV record lookup every time someone needs the bindng URL + %This allows the broker to handle the case where the CBS moves IP or Ports + %New as of 6/28/17: Uses the hardcoded short name for the CBS + {IP, Port} = consul_interface:consul_get_service_ip_port(XER, "config_binding_service", ConsulURL), + concat(["http://", IP, ":", integer_to_binary(Port)]). + +get_platform_envs_and_config() -> + %Get platform envs needed for broker operation, then fetch my config. + %If something critical fails, returns [], else [ConsulURL, CDAPUrl, BoundConfigMap] + MyName = os:getenv("HOSTNAME"), + ConsulHost = os:getenv("CONSUL_HOST"), + case MyName == false orelse ConsulHost == false of + true -> []; + false -> + %build Consul URL + ConsulURL = concat(["http://", ConsulHost, ":8500"]), + + %Bind my own config map + %generate my own XER here + XER = gen_uuid(), + {200, BoundConfig} = consul_interface:consul_bind_config(XER, MyName, ConsulURL), + BoundConfigMap = jiffy:decode(jiffy:encode(BoundConfig), [return_maps]), %kind of an interesting way to turn an erlang proplist into a map + + %Here, we waterfall looking for "CDAP_CLUSTER_TO_MANAGE". + %First, we will check for environmnental variables for a cluster *NAME* + %If that is not found, then we will check out bound config for a fully bound URL + %If that is also not found, let it crash baby. + CDAPURL = case os:getenv("CDAP_CLUSTER_TO_MANAGE") of + false -> + list_to_binary(concat(["http://", lists:nth(1, maps:get(<<"cdap_cluster_to_manage">>, BoundConfigMap))])); %cbs returns ip:port. need http:// or will get "no adaptors found" error + CDAPName -> + {IP, Port} = consul_interface:consul_get_service_ip_port(XER, CDAPName, ConsulURL), + list_to_binary(concat(["http://", IP, ":", integer_to_binary(Port)])) + end, + [MyName, ConsulURL, CDAPURL, BoundConfigMap] + end. + +initialize_database() -> + %Create the database (currently MNesia) if it does not exist, and the application table. + %Or, do nothing. + N = node(), + lager:info(io_lib:format("Initializing database. My node name is ~s", [N])), + + %set MNesia dir + application:set_env(mnesia, dir, "/var/mnesia/"), + + %stop if running, can't create schema if it is. Dont check status, OK if stopped + mnesia:stop(), + + %create the schema if it does not already exist. Dont check status, ok if exists + %erlang:display(mnesia:delete_schema([N])), + mnesia:create_schema([N]), + %start MNesia, assert it works + + ok = mnesia:start(), %start MNesia, bomb if alreay started, should not happen + lager:info("Mnesia started"), + + %try to create the table, or if it exists, do nothing + %erlang:display(mnesia:delete_table(application)), + case mnesia:create_table(application, [{attributes, record_info(fields, application)}, {disc_copies, [N]}]) of + {aborted,{already_exists,application}} -> + lager:info("Application table already exists"); + {atomic,ok} -> + lager:info(io_lib:format("Created application table on ~s", [N])) + end, + + %try to create the app supplementaty table, or if it exists, do nothing + %erlang:display(mnesia:delete_table(application)), + case mnesia:create_table(prog_flow_supp, [{attributes, record_info(fields, prog_flow_supp)}, {disc_copies, [N]}]) of + {aborted,{already_exists, prog_flow_supp}} -> + lager:info("prog_flow_supp table already exists"); + {atomic,ok} -> + lager:info(io_lib:format("Created prog_flow_supp table on ~s", [N])) + end, + + %wait up to 30s for the table to come up. Usually instantaneous. If it takes more crash abd burn + ok = mnesia:wait_for_tables([application, prog_flow_supp], 30000), + ok. + +get_all_appnames_from_db() -> + {atomic, Apps} = mnesia:transaction(fun() -> mnesia:match_object(application, #application{_ = '_'}, read) end), + lists:map(fun(X) -> {application, Appname,_,_,_,_,_,_,_,_} = X, + Appname + end, Apps). + +-spec get_programs_for_pfapp_from_db(binary()) -> lprogram(). +get_programs_for_pfapp_from_db(Appname) -> + {atomic, [#prog_flow_supp{appname = Appname, programs=Programs}]} = mnesia:transaction(fun() -> mnesia:match_object(prog_flow_supp, #prog_flow_supp{appname = Appname, _ = '_'}, read) end), + Programs. + +get_my_version() -> + %stolen from the SO post I asked about: http://stackoverflow.com/questions/43147530/erlang-programmatically-get-application-version/43152182#43152182 + case lists:keyfind(cdapbroker, 1, application:loaded_applications()) of + {_, _, Ver} -> list_to_binary(Ver); + false -> <<"error">> + end. + +gen_uuid() -> + %generate an RFC compliant v1 uuid using lib + uuid:to_string(uuid:uuid1()). + +iso() -> + %generate 8601 ts + iso8601:format(erlang:timestamp()). + +iso_elapsed(Endtime, Starttime) -> + %%%...subtract two isos and return the number of seconds elapsed between Starttime and Endtime + Edt = iso8601:parse(Endtime), + Sdt = iso8601:parse(Starttime), + Egs = calendar:datetime_to_gregorian_seconds(Edt), + Sgs = calendar:datetime_to_gregorian_seconds(Sdt), + Egs - Sgs. + +to_str("") -> ""; +to_str(Term) -> lists:flatten(io_lib:format("~p", [Term])). + +-spec ip_to_str({inet:ip_address(), inet:port_number()}) -> binary(). +%nasty.. I miss pythons x <= Foo <= Y syntax.. or something mathematical like Foo in [X..Y].. erlang not good 4 math +ip_to_str({{A,B,C,D}, Port}) when A >= 0 andalso A =< 255 andalso B >= 0 andalso B =< 255 andalso C >= 0 andalso C =< 255 andalso D >= 0 andalso D =< 255 andalso port >= 0 andalso Port =<65535 -> + concat([to_str(A),".",to_str(B),".", to_str(C),".",to_str(D),":",to_str(Port)]); +ip_to_str({_,_}) -> invalid. + +update_with_new_config_map(NewConfig, OldConfig) -> + %helper for smart_reconfigure, broken out so we can unit test it. + % + %Takes in a new config, some keys in which may be shared with OldConfig, and returns a new map with the same keys as OldConfig, except values that had overlap were replaced by NewConfig + %if no keys in NewConfig overlap with OldConfig, returns the atom 'nooverlap' + % + %This is very similar to the maps:merge/2 builtin but that will inject keys of newconfig that were not in oldconfig. We need a "RIGHT JOIN" + NCKeys = maps:keys(NewConfig), + ConfigOverlaps = [X || X <- NCKeys, maps:is_key(X, OldConfig)], + case ConfigOverlaps of + [] -> nooverlap; + _ -> + %we have an entry that should be in app config + %build a new map with just the keys to update + Pred = fun(X,_) -> lists:member(X, ConfigOverlaps) end, + NewVals = maps:filter(Pred, NewConfig), + maps:merge(OldConfig, NewVals) + end. + +ejson_to_map(E) -> + %takes the jiffy "ejson: format of {[{<<"foo">>, <<"bar">>}, {<<"foo2">>, <<"bar2">>}]} and turns it into a map, + %usefu because ejsons do not appear to be order-independent-comparable, but maps are (e.g., two maps are equal if all their k+v are equal but agnostic to order) + jiffy:decode(jiffy:encode(E), [return_maps]). diff --git a/src/util_tests.erl b/src/util_tests.erl new file mode 100644 index 0000000..e37e492 --- /dev/null +++ b/src/util_tests.erl @@ -0,0 +1,53 @@ +% ============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. + +-module(util_tests). +-include_lib("eunit/include/eunit.hrl"). +-import(util, [ + iso_elapsed/2, + ip_to_str/1, + update_with_new_config_map/2, + ejson_to_map/1]). + +iso_elapsed_test() -> + ?assert(iso_elapsed(<<"2017-04-27T18:38:10Z">>, <<"2017-04-27T18:38:08Z">>) == 2), + ?assert(iso_elapsed(<<"2017-04-29T18:38:10Z">>, <<"2017-04-27T18:38:08Z">>) == 60*60*24*2+2). + +ip_to_str_test() -> + ?assert(ip_to_str({{6,6,6,6}, 666}) == "6.6.6.6:666"), + ?assert(ip_to_str({{196,196,196,196}, 1}) == "196.196.196.196:1"), + ?assert(ip_to_str({{6,6,6,6666}, 666}) == invalid), + ?assert(ip_to_str({{6,6,6,6}, 66666}) == invalid), + ?assert(ip_to_str({{6,6,-6,6}, 666}) == invalid), + ?assert(ip_to_str({{6,6,six,6}, 666}) == invalid). + +update_with_new_config_map_test() -> + ?assert(update_with_new_config_map(#{<<"foo">>=><<"smartbar">>, <<"preffoo">>=><<"smartprefbar">>}, #{<<"foo">>=><<"bar">>}) == #{<<"foo">>=><<"smartbar">>}), + ?assert(update_with_new_config_map(#{<<"fooD">>=><<"smartbar">>}, #{<<"foo">>=><<"bar">>}) == nooverlap), + ?assert(update_with_new_config_map(#{<<"foo">>=><<"smartbar">>,<<"foo2">>=><<"smartbar2">>}, #{<<"foo">>=><<"bar">>, <<"foo2">>=><<"bar2">>}) == #{<<"foo">>=><<"smartbar">>, <<"foo2">>=><<"smartbar2">>}). + +ejson_to_map_test() -> + EJ1 = {[{<<"foo">>, <<"bar">>}, {<<"foo2">>, <<"bar2">>}]}, + EJ2 = {[{<<"foo2">>, <<"bar2">>}, {<<"foo">>, <<"bar">>}]}, + M1 = ejson_to_map(EJ1), + M2 = ejson_to_map(EJ2), + ?assert(EJ1 /= EJ2), %HERE LIES THE PROBLEM HUDSON + ?assert(M1 == M2). %GREAT SUCCESS! + diff --git a/src/workflows.erl b/src/workflows.erl new file mode 100644 index 0000000..a8c6abb --- /dev/null +++ b/src/workflows.erl @@ -0,0 +1,324 @@ +% ============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. + +-module(workflows). + +%Module holds functions that execute big workflows, like deploying a CDAP application. + +-include("application.hrl"). +-export([deploy_cdap_app/17, %super offensive arity.. should probably start using some structs to cut this + undeploy_cdap_app/6, + undeploy_hydrator_pipeline/6, + deploy_hydrator_pipeline/12, + all_200s_else_showerror/2, + app_config_reconfigure/7, + app_preferences_reconfigure/7, + smart_reconfigure/7 + ]). + +-import(util, [iso/0, to_str/1]). +-import(logging, [metrics/3]). + +-define(MET(Sev, Req, Bts, XER, TgtE, TgtS, TgtRSC, Msg), metrics(Sev, Req, [{bts, Bts}, {xer,XER}, {tgte, TgtE}, {tgts, TgtS}, {tgtrsc, TgtRSC}, {mod, to_str(?MODULE)}, {msg, Msg}])). +-define(CDAPE, "cdap cluster"). +-define(CNSE, "consul cluster"). + +%private +attempt( Req, XER, { Mod, Func, Args }, ServiceName, Action, LogResponse) -> + %Thanks Garry!! + %Helper function to + %1. log the start timestamp + %2. Do an action specificed by mod:func(args). Assumes XER always first arg + %3. Log a metrics info statement about the API cll + %4. assert the return code was a 200, let it crash otehrwise, caller catches + Start = iso(), + {RC, RB} = apply( Mod, Func, [XER | Args] ), + ?MET(info, Req, Start, XER, ServiceName, Action, RC, case LogResponse of true -> to_str(RB); false -> "" end), + {RC, RB}. + +%public +-spec all_200s_else_showerror(fun((any()) -> httpstat()), list()) -> httpstat(). +all_200s_else_showerror(FClosure, ListToMap) -> + %Takes a "partial" with the spec: f(X) -> {HTTP_Status_Code, HTTP_Response}, maps it onto ListToMap, and either + %returns {200, ""} or else the first error encountered after executing the entire list (does not short circuit!) + % + %I say "partial" because there are no real "partials" in Erlang but you can make them using Closure's out of funs (anonymous functions), so FClosure is a Closure just waiting for the last argument + %See: + %https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwjtyeiC6LbSAhVH0FQKHffhAr0QFggcMAA&url=http%3A%2F%2Fstackoverflow.com%2Fquestions%2F13355544%2Ferlang-equivalents-of-haskell-where-partial-lambda&usg=AFQjCNHnEZjQHtQhKXN67DBKKoJpqRXztg&cad=rja + %http://stackoverflow.com/questions/16183971/currying-functions-erlang + L = lists:filter(fun({X, _}) -> X /= 200 end, lists:map(FClosure, ListToMap)), + case L of + [] -> {200, ""}; + _ -> lists:nth(1, L) + end. + +deploy_cdap_app(Req, XER, Appname, ConsulURL, CDAPURL, HCInterval, AutoDeregisterAfter, AppConfig, JarURL, ArtifactName, ArtifactVersion, Namespace, AppPreferences, ParsedProgramPreferences, Programs, RequestUrl, Healthcheckurl) -> + %push the UNBOUND config and preferences into Consul. + %I don't think we should push bound configs because triggering a "rebind" will suffer if the templating language is lost. + {200,_} = attempt(Req, XER, { consul_interface, consul_push_config, [ Appname, ConsulURL, AppConfig ] }, ?CNSE, "push config", true), + + %push the preferences + {200,_} = attempt(Req, XER, { consul_interface, consul_push_preferences, [ Appname, ConsulURL, AppPreferences ] }, ?CNSE, "push preferences", true), + + %get the bound config + {200,BoundConfig} = attempt(Req, XER, { consul_interface, consul_bind_config, [ Appname, ConsulURL ] }, "config binding service", "bind config", false), + + %fetch the JAR. + {200,JarBody} = attempt(Req, XER, { httpabs, get, [ JarURL ] }, "nexus", "file get", false), + + %create the Namespace + {200,_} = attempt( Req, XER, { cdap_interface, create_namespace, [ Namespace, CDAPURL ] }, ?CDAPE, "create namespace", true), + + %deploy the application + {200,_} = attempt( Req, XER, { cdap_interface, deploy_app, [ Appname, Namespace, CDAPURL, JarBody, ArtifactName, ArtifactVersion, BoundConfig ] }, ?CDAPE, "deploy application", true), + + %set app preferences + {200,_} = attempt( Req, XER, { cdap_interface, push_down_app_preferences, [ Appname, Namespace, CDAPURL, AppPreferences ] }, ?CDAPE, "set app preferences", true), + + %push down the program preferences + {200,_} = attempt( Req, XER, { cdap_interface, push_down_program_preferences, [ Appname, Namespace, CDAPURL, ParsedProgramPreferences ] }, ?CDAPE, "set program preferences", true), + + %start the CDAP application services + {200,_} = attempt( Req, XER, { cdap_interface, exec_programs, [ Appname, Namespace, CDAPURL, Programs, "start" ] }, ?CDAPE, "start program", true), + + %Parse my IP and port + {ok, {http, _, IPaS, Port, _, _}} = http_uri:parse(binary_to_list(RequestUrl)), + + %register with Consul; We will register the broker's URL as the address in Consul then the upstream service can do a GET on this Broker to get the resource object + {200,_} = attempt( Req, XER, { consul_interface, consul_register, [ Appname, ConsulURL, list_to_binary(IPaS), Port, Healthcheckurl, HCInterval, AutoDeregisterAfter ] }, ?CNSE, "service register", true), + + ok. %if got to here, all went well. + +-spec undeploy_cdap_app(any(), string(), binary(), string(), string(), binary()) -> ok. +undeploy_cdap_app(Req, XER, Appname, CDAPURL, ConsulURL, Namespace) -> + %stop the CDAP programs assuming they are valid + Programs = util:get_programs_for_pfapp_from_db(Appname), + Bts = iso(), %record begining timestamp + {RC, RB} = cdap_interface:exec_programs(XER, Appname, Namespace, CDAPURL, Programs, "stop"), + case RC of + 200 -> ?MET(info, Req, Bts, XER, ?CDAPE, "program stop", RC, "OK"); + 400 -> ?MET(warning, Req, Bts, XER, ?CDAPE, "program stop", RC, io_lib:format("Delete called on ~s but it's programs were not running, probably indicates the app crashed in some way: ~s", [Appname, RB])); + 404 -> ?MET(warning, Req, Bts, XER, ?CDAPE, "program stop", RC, io_lib:format("Delete called on ~s but it's gone, probably indicates a horrible manual deletion from CDAP: ~s", [Appname, RB])); + _ -> ?MET(warning, Req, Bts, XER, ?CDAPE, "program stop", RC, io_lib:format("Delete called on ~s but CDAP returned a ~p. This likely means things will NOT be cleaned up properly!! ~s", [Appname, RC, RB])) + end, + + %delete the application + Bts2 = iso(), + {RC2, RB2} = cdap_interface:delete_app(XER, Appname, Namespace, CDAPURL), + case RC2 of + 200 -> ?MET(info, Req, Bts2, XER, ?CDAPE, "app delete", RC2, "OK"); + 404 -> ?MET(warning, Req, Bts2, XER, ?CDAPE, "app delete", RC2, io_lib:format("Delete called on ~s but it's gone, probably indicates a horrible manual deletion from CDAP: ~s", [Appname, RB2])); + _ -> ?MET(warning, Req, Bts2, XER, ?CDAPE, "app delete", RC2, io_lib:format("Delete called on ~s but CDAP returned a ~p. This likely means things will NOT be cleaned up properly!! ~s", [Appname, RC2, RB2])) + end, + + %deregister with consul + Bts3 = iso(), + {RC3, RB3} = consul_interface:consul_deregister(XER, Appname, ConsulURL), + case RC3 of + 200 -> ?MET(info, Req, Bts3, XER, ?CNSE, "service deregister", RC3, "OK"); + _ -> ?MET(warning, Req, Bts3, XER, ?CNSE, "service deregister", RC3, io_lib:format("Delete called on ~s but Consul returned a ~p. This likely means a service is not cleaned up properly! ~s", [Appname, RC3, RB3])) + end, + + %delete the config key stored earlier + Bts4 = iso(), + {RC4, RB4} = consul_interface:consul_delete_config(XER, Appname, ConsulURL), + case RC4 of + 200 -> ?MET(info, Req, Bts4, XER, ?CNSE, "key (config) delete", RC4, "OK"); + 404 -> ?MET(warning, Req, Bts4, XER, ?CNSE, "key (config) delete", RC4, io_lib:format("Delete called on ~s but it's consul key is gone, probably indicates a horrible manual deletion from Consul: ~s", [Appname, RB4])); + _ -> ?MET(warning, Req, Bts4, XER, ?CNSE, "key (config) delete", RC4, io_lib:format("Delete called on ~s but Consul returned a ~p. This likely means a key is not cleaned up properly! ~s", [Appname, RC4, RB4])) + end, + + %delete the config key stored earlier + Bts5 = iso(), + {RC5, RB5} = consul_interface:consul_delete_preferences(XER, Appname, ConsulURL), + case RC5 of + 200 -> ?MET(info, Req, Bts5, XER, ?CNSE, "key (preferences) delete", RC5, "OK"); + 404 -> ?MET(warning, Req, Bts5, XER, ?CNSE, "key (preferences) delete", RC5, io_lib:format("Delete called on ~s but it's consul key is gone, probably indicates a horrible manual deletion from Consul: ~s", [Appname, RB5])); + _ -> ?MET(warning, Req, Bts5, XER, ?CNSE, "key (preferences) delete", RC5, io_lib:format("Delete called on ~s but Consul returned a ~p. This likely means a key is not cleaned up properly! ~s", [Appname, RC5, RB5])) + end, + + ok. + +deploy_hydrator_pipeline(Req, XER, Appname, Namespace, CDAPURL, PipelineConfigJsonURL, Dependencies, ConsulURL, RequestUrl, Healthcheckurl, HCInterval, AutoDeregisterAfter) -> + %fetch the JSON + {200,PipelineJson} = attempt(Req, XER, { httpabs, get, [ PipelineConfigJsonURL ] }, "nexus", "file get", false), + + %TODO! Config + + %create the Namespace + {200,_} = attempt( Req, XER, { cdap_interface, create_namespace, [ Namespace, CDAPURL ] }, ?CDAPE, "create namespace", true), + + %deploy pipeline dependencies% + {200,_} = attempt( Req, XER, { cdap_interface, deploy_pipeline_dependencies, [ Namespace, CDAPURL, Dependencies ] }, ?CDAPE, "deploy dependencies", true), + + %deploy pipeline dependencies UI properties + %NOTE! There is a bit of redundancy with the above call. I debated merging the two. + %I decided against it because I want failures to load the deps seperated from failures to load the properties files, because they are different URLs. + %Splitting them like this allows me to return the error to the user on the exact step that failed + {200,_} = attempt( Req, XER, { cdap_interface, deploy_pipeline_dependencies_properties, [ Namespace, CDAPURL, Dependencies ] }, ?CDAPE, "deploy dependency properties", true), + + %deploy the pipeline + {200,"Deploy Complete"} = attempt( Req, XER, { cdap_interface, deploy_pipeline, [ Appname, Namespace, CDAPURL, PipelineJson ] }, ?CDAPE, "deploy pipeline", true), + + %start the pipeline + {200,_} = attempt( Req, XER, { cdap_interface, exec_pipeline, [ Appname, Namespace, CDAPURL, "resume" ] }, ?CDAPE, "start pipeline", true), + + %Parse my IP and port + {ok, {http, _, IPaS, Port, _, _}} = http_uri:parse(binary_to_list(RequestUrl)), + + %register with Consul; We will register the broker's URL as the address in Consul, then the upstream service can do a GET on this Broker to get the resource object + {200,_} = attempt( Req, XER, { consul_interface, consul_register, [ Appname, ConsulURL, list_to_binary(IPaS), Port, Healthcheckurl, HCInterval, AutoDeregisterAfter] }, ?CNSE, "service register", true), + + ok. + +undeploy_hydrator_pipeline(Req, XER, Appname, Namespace, CDAPURL, ConsulURL) -> + %UNDEPLOY NOTES: + % 1 Never fail on undeploy, log and continue. + % 2 Leave artifact dependencies on the cluster. We can revisit this if we need a "LEAVE NO TRACE" solution. TODO. + % 3 I noticed an asymetry in deploy/undeplopy here: there is no need to start workflows. Terry clarified this is correct: "Batch pipelines contain a schedule, but deploying the pipeline does not activate the schedule. Resuming the schedule makes it active so the pipeline will run at its next scheduled time. When undeploying, if you only suspend the schedule which prevents future runs from starting, then any currently active runs will continue until they finish (or not finish if they are hung). So we follow up with a stop workflow to kill any run that may be in progress so the following commands will not fail (delete pipeline or delete namespace). + %We avoid a race condition by suspending the schedule first. + + %suspend the pipeline + Bts = iso(), + {RC1, RB1} = cdap_interface:exec_pipeline(XER, Appname, Namespace, CDAPURL, "suspend"), + case RC1 of + 200 -> ?MET(info, Req, Bts, XER, ?CDAPE, "pipeline suspend", RC1, "OK"); + 400 -> ?MET(warning, Req, Bts, XER, ?CDAPE, "pipeline suspend", RC1, io_lib:format("Pipeline suspend called on ~s but it's was not running, probably OK, probably it is on a schedule ~s", [Appname, RB1])); + 404 -> ?MET(warning, Req, Bts, XER, ?CDAPE, "pipeline suspend", RC1, io_lib:format("Pipeline suspend called on ~s but it's gone, probably indicates a horrible manual deletion from CDAP: ~s", [Appname, RB1])); + _ -> ?MET(warning, Req, Bts, XER, ?CDAPE, "pipeline suspend", RC1, io_lib:format("Pipeline suspend called on ~s but CDAP unexpectedly return a ~p. This likely means things will NOT be cleaned up properly!! ~s", [Appname, RC1, RB1])) + end, + + %stop the workflow + Bts2 = iso(), + {RC2, RB2} = cdap_interface:exec_pipeline_workflow(XER, Appname, Namespace, CDAPURL, "stop"), + case RC2 of + 200 -> ?MET(info, Req, Bts2, XER, ?CDAPE, "workflow stop", RC2, "OK"); + 400 -> ?MET(warning, Req, Bts2, XER, ?CDAPE, "workflow stop", RC2, io_lib:format("Workflow stop called on ~s but it's was not running, probably OK, probably it is on a schedule ~s", [Appname, RB2])); + 404 -> ?MET(warning, Req, Bts2, XER, ?CDAPE, "workflow stop", RC2, io_lib:format("Workflow stop called on ~s but it's gone, probably indicates a horrible manual deletion from CDAP: ~s", [Appname, RB2])); + _ -> ?MET(warning, Req, Bts2, XER, ?CDAPE, "workflow stop", RC2, io_lib:format("Workflow stop called on ~s but CDAP unexpectedly return a ~p. This likely means things will NOT be cleaned up properly!! ~s", [Appname, RC2, RB2])) + end, + + %?MET(warning, Req, Bts2, XER, ?CDAPE, "workflow stop", RC2, io_lib:format()); + + %TODO! Delete config (Configs are currently not pushed for hydrator pipelines, so have to do that first) + + %delete the application + Bts3 = iso(), + {RC3, RB3} = cdap_interface:delete_app(XER, Appname, Namespace, CDAPURL), + case RC3 of + 200 -> ?MET(info, Req, Bts3, XER, ?CDAPE, "app delete", RC3, "OK"); + 404 -> ?MET(warning, Req, Bts3, XER, ?CDAPE, "app delete", RC3, io_lib:format("Delete called on ~s but it's gone, probably indicates a horrible manual deletion from CDAP: ~s", [Appname, RB3])); + _ -> ?MET(warning, Req, Bts3, XER, ?CDAPE, "app delete", RC3, io_lib:format("Delete called on ~s but CDAP returned a ~p. This likely means things will NOT be cleaned up properly!! ~s", [Appname, RC3, RB3])) + end, + + %deregister with consul + Bts4 = iso(), + {RC4, RB4} = consul_interface:consul_deregister(XER, Appname, ConsulURL), + case RC4 of + 200 -> ?MET(info, Req, Bts4, XER, ?CNSE, "service deregister", RC4, "OK"); + _ -> ?MET(warning, Req, Bts4, XER, ?CNSE, "service deregister", RC3, io_lib:format("Delete called on ~s but Consul returned a ~p. This likely means a service is not cleaned up properly! ~s", [Appname, RC4, RB4])) + end, + ok. + +app_config_reconfigure(Req, XER, Appname, Namespace, ConsulURL, CDAPURL, AppConfig) -> + %Reconfigure CDAP App's App Config + + %push the UNBOUND config into Consul. I don't think we should push bound configs because triggering a "rebind" will suffer if the templating language is lost. + {200,_} = attempt( Req, XER, { consul_interface, consul_push_config, [ Appname, ConsulURL, AppConfig ] }, ?CNSE, "push config", true), + + %get the bound config + {200,BoundConfig} = attempt(Req, XER, { consul_interface, consul_bind_config, [ Appname, ConsulURL ] }, "config binding service", "bind config", false), + + %push it to CDAP + %TODO! What happens when we push to consul but connection to CDAP fails? Then CDAP and Consul are out of sync. + %Maybe create a "BACKUP" key in Consul for the old config and "rollback" if the below fails + %Transactions across distributed systems is hard =( + {200,_} = attempt( Req, XER, { cdap_interface, push_down_config, [ Appname, Namespace, CDAPURL, BoundConfig ] }, ?CDAPE, "reconfigure app config", true), + + ok. + +app_preferences_reconfigure(Req, XER, Appname, Namespace, ConsulURL, CDAPURL, AppPreferences) -> + %Workflow: + % 1) push the new preferences to Cosnul + % 2) stop all the programs + % 3) push the programs to CDAP + % 4) start all the programs + % + % NOTE! Currently it is assumed that preferences do not need to be bound by the config_binding_service, + % as only app config contains service discovery items. + + Programs = util:get_programs_for_pfapp_from_db(Appname), + + %1 push the new prefs up to Consul + {200,_} = attempt(Req, XER, { consul_interface, consul_push_preferences, [ Appname, ConsulURL, AppPreferences ] }, ?CNSE, "push preferences", true), + + %2 stop the programs + {200,_} = attempt( Req, XER, { cdap_interface, exec_programs, [ Appname, Namespace, CDAPURL, Programs, "stop" ] }, ?CDAPE, "stop programs", true), + + %3 set app preferences + {200,_} = attempt( Req, XER, { cdap_interface, push_down_app_preferences, [ Appname, Namespace, CDAPURL, AppPreferences ] }, ?CDAPE, "set app preferences", true), + + %4 start er' up again + {200,_} = attempt( Req, XER, { cdap_interface, exec_programs, [ Appname, Namespace, CDAPURL, Programs, "start" ] }, ?CDAPE, "start program", true), + + ok. + +smart_reconfigure(Req, XER, Appname, Namespace, ConsulURL, CDAPURL, NewConfig) -> + %Smart reconfigure takes in a JSON (NewConfig) and tries to be "smart"; it tries to figure out whether Config is a reconfiguration of + %app config, app preferences, or both. + % + %Specifically this workflow works as follows; + %1) pull down AppConfig in consul + %2) pull down Prefernces in consul + %3) see if any keynames in this function's input (NewConfig) are keynames in AppConfig + % 3a if so, reconfigure it + % 3b write the delta'd AppConfig back to consul + %4) see if any keynames in this fucntion's input (NewConfig) are keynames in Preferences + % 4a if so, reconfigure ppreferences + % 4b write the delta'd preferences back to consul + %5) Return a status + + + %see if we have app config overlaps + {200, ConsulAppConfig} = consul_interface:consul_get_configuration(XER, Appname, ConsulURL), + NewAppConfig = util:update_with_new_config_map(NewConfig, ConsulAppConfig), + WasNewAppConfig = case NewAppConfig of + nooverlap -> nooverlap; + _ -> + ok = app_config_reconfigure(Req, XER, Appname, Namespace, ConsulURL, CDAPURL, NewAppConfig) + end, + + %see if we have preferences overlap + {200, ConsulPreferences} = consul_interface:consul_get_preferences(XER, Appname, ConsulURL), + NewAppPreferences = util:update_with_new_config_map(NewConfig, ConsulPreferences), + WasNewAppPreferences = case NewAppPreferences of + nooverlap -> nooverlap; + _ -> + ok = app_preferences_reconfigure(Req, XER, Appname, Namespace, ConsulURL, CDAPURL, NewAppPreferences) + end, + + case WasNewAppConfig == nooverlap andalso WasNewAppPreferences == nooverlap of + true -> + {400, "non-overlapping configuration was sent"}; + false -> + ok + end. + + diff --git a/src/workflows_tests.erl b/src/workflows_tests.erl new file mode 100644 index 0000000..1b7b51c --- /dev/null +++ b/src/workflows_tests.erl @@ -0,0 +1,27 @@ +% ============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. + +-module(workflows_tests). +-include_lib("eunit/include/eunit.hrl"). + +all_200s_else_showerror_test() -> + ?assert({200, ""} == workflows:all_200s_else_showerror(fun(_) -> {200, "all good"} end, [1,"A", foo])), + ?assert({500, "constant dissapointment"} == workflows:all_200s_else_showerror(fun(X) -> if X < 5 -> {200, "all good"}; true -> {500, "constant dissapointment"} end end, [0,10])). + diff --git a/swagger/swagger.html b/swagger/swagger.html new file mode 100644 index 0000000..3d51590 --- /dev/null +++ b/swagger/swagger.html @@ -0,0 +1,1899 @@ + + + + + + CDAP Broker API + + +

+

CDAP Broker API

+

Version: 4.0.3

+

+ + +
+ Schemes: + +
+ +

Summary

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PathOperationDescription
+ / + + GET + + +
+ /application + + GET + + +
+ /application*/{appname} + + PUT + + +
+ /application/delete + + POST + + +
+ /application/{appname} + + DELETE + + +
+ GET + + +
+ PUT + + +
+ /application/{appname}/healthcheck + + GET + + +
+ /application/{appname}/metrics + + GET + + +
+ /application/{appname}/reconfigure + + PUT + + +
+ + + +

Paths

+ + + +
+ + + +
+
+
+

PUT /application*/{appname}

+
+
+
+

(This is a hacky way of supporting "oneOf" because Swagger does not support oneOf https://github.com/OAI/OpenAPI-Specification/issues/333. This is the same endpoint as PUT /application/appname, except the PUT body is different.)

+

Register a hydrator app for service and configuration discovery. This will light up a metrics and health endpoint for this app. appname is assumed to also be the key in consul.

+ +
+ +
+ +

application/json +

+
+
+

required put body

+

+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ appname +

Name of the application.

+
pathstring (text) + + + + +
+
+ +
+

application/json +

+ +
+
+ 200 OK + +
+
+
+
+

Successful response

+ +
+
+
+ +
+
+ +
+ +
+
+ 400 Bad Request + +
+
+
+
+

put was performed but the appname was already registered with the broker, or Invalid PUT body

+ +
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+

POST /application/delete

+
+
+
+

endpoint to delete multiple applications at once. Returns an array of status codes, where statuscode[i] = response returned from DELETE(application/i)

+ +
+ +
+ +
+
+

required post body

+

+
+
+
+ +
+
+
+ +
+ +
+
+ 200 OK + +
+
+
+
+

successful response

+ +
+
+
+ +
+
+
+ +
+ returncode + + + +
+ +
+
+
+ +
+
+
+
+
+ +
+
+
+

DELETE /application/{appname}

+
+
+
+

Remove an app for service and configuration discovery. This will remove the metrics and health endpoints for this app.

+ +
+ +
+ + + + + + + + + + + + + + + + + + +
+ appname +

Name of the application.

+
pathstring (text) + + + + +
+
+ +
+ +
+
+ 200 OK + +
+
+
+
+

Successful response

+ +
+
+
+ +
+
+ +
+
+ 404 Not Found + +
+
+
+
+

no app with name 'appname' registered with this broker.

+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+

GET /application/{appname}

+
+
+
+

Returns the representation of the application resource, including the links for healthcheck and metrics.

+ +
+ +
+ + + + + + + + + + + + + + + + + + +
+ appname +

Name of the application.

+
pathstring (text) + + + + +
+
+ +
+ +
+
+ 200 OK + +
+
+
+
+

Successful response

+ +
+
+
+ +
+
+ +
+ +
+
+ 404 Not Found + +
+
+
+
+

no app with name 'appname' registered with this broker.

+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+

PUT /application/{appname}

+
+
+
+

Register an app for service and configuration discovery. This will light up a metrics and health endpoint for this app. appname is assumed to also be the key in consul.

+ +
+ +
+ +

application/json +

+
+
+

required put body

+

+
+
+
+
+ appput +
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ appname +

Name of the application.

+
pathstring (text) + + + + +
+
+ +
+

application/json +

+ +
+
+ 200 OK + +
+
+
+
+

Successful response

+ +
+
+
+ +
+
+ +
+ +
+
+ 400 Bad Request + +
+
+
+
+

put was performed but the appname was already registered with the broker, or Invalid PUT body

+ +
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+

GET /application/{appname}/healthcheck

+
+
+
+

Perform a healthcheck on the running app appname.

+ +
+ +
+ + + + + + + + + + + + + + + + + + +
+ appname +

Name of the application to get the healthcheck for.

+
pathstring (test) + + + + +
+
+ +
+ +
+
+ 200 OK + +
+
+
+
+

Successful response, healthcheck pass

+ +
+
+
+ +
+
+ +
+
+ 404 Not Found + +
+
+
+
+

no app with name 'appname' registered with this broker, or the healthcheck has failed (though I would like to disambiguiate from the first case, CDAP returns a 404 for this).

+ +
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+

GET /application/{appname}/metrics

+
+
+
+

Get live (real-time) app specific metrics for the running app appname. Metrics are customized per each app by the component developer

+ +
+ +
+ + + + + + + + + + + + + + + + + + +
+ appname +

Name of the application to get metrics for.

+
pathstring (test) + + + + +
+
+ +
+ +
+
+ 200 OK + +
+
+
+
+

Successful response

+ +
+
+
+ +
+
+ +
+ +
+
+ 404 Not Found + +
+
+
+
+

no app with name 'appname' registered with this broker.

+ +
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+

PUT /application/{appname}/reconfigure

+
+
+
+

Reconfigures the application.

+ +
+ +
+ +
+
+

required put body

+

+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ appname +

Name of the application.

+
pathstring (text) + + + + +
+
+ +
+ +
+
+ 200 OK + +
+
+
+
+

Successful response

+ +
+
+
+ +
+
+ +
+
+ 400 Bad Request + +
+
+
+
+

Bad request. Can happen with 1) {appname} is not registered with the broker, 2) the required PUT body is wrong, or 3) the smart interface was chosen and none of the config keys match anything in app_config or app_preferences

+ +
+
+
+ +
+
+ +
+
+
+
+
+ + + +

Schema definitions

+ + +
+
+

Application: + object + + + +

+
+
+ +
+
+
+ appname: + string + + +
+
+

application name

+ +
+ +
+
+
+ healthcheckurl: + string + + +
+
+

fully qualified url to perform healthcheck

+ +
+ +
+
+
+ metricsurl: + string + + +
+
+

fully qualified url to get metrics from

+ +
+ +
+
+
+ url: + string + + +
+
+

fully qualified url of the resource

+ +
+ +
+
+
+ connectionurl: + string + + +
+
+

input URL that you can POST data into (URL of the CDAP stream)

+ +
+ +
+
+
+ serviceendpoints: + object[] + + +
+
+

a list of HTTP services exposed by this CDAP application

+ +
+ +
+ service_method + + + +
+ +
+
+
+
+
+
+
+
+
+

appname: + string + + + +

+
+
+
+

an application name

+ +
+ +
+
+
+
+

appput: + object + + + +

+
+
+ +
+
+
+ cdap_application_type: + string , x ∈ { + program-flowlet + + } + + + +
+
+

denotes whether this is a program-flowlet style application or a hydrator pipeline. For program-flowlet style apps, this value must be "program-flowlet"

+ +
+ +
+
+
+ streamname: + string + + +
+
+

name of the CDAP stream to ingest data into this app. Should come from the developer and Tosca model.

+ +
+ +
+
+
+ namespace: + string + + +
+
+

the cdap namespace this is deployed into

+ +
+ +
+
+
+ jar_url: + string + + +
+
+

the URL that the JAR you're deploying resides

+ +
+ +
+
+
+ artifact_name: + string + + +
+
+

the name of the CDAP artifact to be added

+ +
+ +
+
+
+ artifact_ver: + object + + +
+
+

the version of the artifact. Must be in X.Y.Z form

+ +
+ +
+
+
+ app_config: + object + + +
+
+

the application config JSON

+ +
+ +
+
+
+ app_preferences: + object + + +
+
+

the application preferences JSON

+ +
+ +
+
+
+ programs: + object[] + + +
+
+ +
+ +
+ programs + + + +
+ +
+
+
+
+ program_preferences: + object[] + + +
+
+ +
+ +
+ programpref + + + +
+ +
+
+
+
+ services: + object[] + + +
+
+ +
+ +
+ service_endpoint + + + +
+ +
+
+
+
+
+
+
+
+
+

hydratorappput: + object + + + +

+
+
+ +
+
+
+ cdap_application_type: + string , x ∈ { + hydrator-pipeline + + } + + + + +
+
+

denotes whether this is a program-flowlet style application or a hydrator pipeline. For hydrator, this value must be "hydrator-pipeline"

+ +
+ +
+
+
+ namespace: + string + + + +
+
+

the cdap namespace this is deployed into

+ +
+ +
+
+
+ pipeline_config_json_url: + string + + + +
+
+

the URL of the config.json for this pipeline

+ +
+ +
+
+
+ streamname: + string + + + +
+
+

name of the CDAP stream to ingest data into this app. Should come from the developer and Tosca model.

+ +
+ +
+
+
+ dependencies: + object[] + + +
+
+

represents a list of dependencies to be loaded for this pipeline. Not required.

+ +
+ +
+ hydratordep + + + +
+ +
+
+
+
+
+
+
+
+
+

hydratordep: + object + + + +

+
+
+
+

represents a hydrator pipeline dependency. An equivelent to the following CURLs are formed with the below four params shown in CAPS "curl -v -w"\n" -X POST http://cdapurl:11015/v3/namespaces/setelsewhere/artifacts/ARTIFACT_NAME -H "Artifact-Extends:ARTIFACT_EXTENDS_HEADER" -H “Artifact-Version:ARTIFACT_VERSION_HEADER” --data-binary @(DOWNLOADED FROM ARTIFACT_URL)","curl -v -w"\n" -X PUT http://cdapurl:11015/v3/namespaces/setelsewhere/artifacts/ARTIFACT_NAME/versions/ARTIFACT_VERSION_HEADER/properties -d (DOWNLOADED FROM UI_PROPERTIES_URL)"

+ +
+ +
+
+
+ artifact_extends_header: + string + + + +
+
+

the value of the header that gets passed in for artifact-extends, e.g., "Artifact-Extends:system:cdap-data-pipeline[4.0.1,5.0.0)"

+ +
+ +
+
+
+ artifact_name: + string + + + +
+
+

the name of the artifact

+ +
+ +
+
+
+ artifact_version_header: + string + + + +
+
+

the value of the header that gets passed in for artifact-version, e.g., "Artifact-Version:1.0.0-SNAPSHOT"

+ +
+ +
+
+
+ artifact_url: + string + + + +
+
+

the URL of the artifact JAR

+ +
+ +
+
+
+ ui_properties_url: + string + + +
+
+

the URL of the properties.json if the custom artifact has UI properties. This is optional.

+ +
+ +
+
+
+
+
+
+
+
+

info: + object + + + +

+
+
+
+

some broker information

+ +
+ +
+
+
+ managed cdap url: + string + + +
+
+

the url of the CDAP cluster API this broker is managing

+ +
+ +
+
+
+ number of applications registered: + integer + + +
+
+ +
+ +
+
+
+ uptime (s): + integer + + +
+
+ +
+ +
+
+
+ cdap GUI port: + integer + + +
+
+

The GUI port of the CDAP cluster this broker is managing. Mostly to help users of this API check their application in cdap. Note, will return UNKNOWN_CDAP_VERSION if it cannot be determined.

+ +
+ +
+
+
+ cdap cluster version: + string + + +
+
+

the version of the CDAP cluster this broker is managing. Note, will return UKNOWN_CDAP_VERSION if it cannot be determined.

+ +
+ +
+
+
+ broker API version: + string + + +
+
+

the API version of this running broker

+ +
+ +
+
+
+
+
+
+
+
+

MetricsObject: + object + + + +

+
+
+
+

key,value object where the key is 'appmetrics' and the value is an app dependent json and specified by the component developer

+ +
+ +
+
+
+ appmetrics: + object + + +
+
+ +
+ +
+
+
+
+
+
+
+
+

multideleteput: + object + + + +

+
+
+ +
+
+
+ appnames: + object[] + + +
+
+ +
+ +
+ appname + + + +
+ +
+
+
+
+
+
+
+
+
+

programpref: + object + + + +

+
+
+
+

the list of programs in this CDAP app

+ +
+ +
+
+
+ program_type: + string + + +
+
+

must be one of flows, mapreduce, schedules, spark, workflows, workers, or services

+ +
+ +
+
+
+ program_id: + string + + +
+
+

the name of the program

+ +
+ +
+
+
+ program_pref: + object + + +
+
+

the preference JSON to set for this program

+ +
+ +
+
+
+
+
+
+
+
+

programs: + object + + + +

+
+
+
+

the list of programs in this CDAP app

+ +
+ +
+
+
+ program_type: + string + + +
+
+

must be one of flows, mapreduce, schedules, spark, workflows, workers, or services

+ +
+ +
+
+
+ program_id: + string + + +
+
+

the name of the program

+ +
+ +
+
+
+
+
+
+
+
+

reconfigput: + object + + + +

+
+
+ +
+
+
+ reconfiguration_type: + string , x ∈ { + program-flowlet-app-config + , + program-flowlet-app-preferences + , + program-flowlet-smart + + } + + + + +
+
+

the type of reconfiguration

+ +
+ +
+
+
+ config: + object + + + +
+
+

the config JSON

+ +
+ +
+
+
+
+
+
+
+
+

returncode: + integer + + + +

+
+
+
+

an httpreturncode

+ +
+ +
+
+
+
+

service_endpoint: + object + + + +

+
+
+
+

descirbes a service endpoint, including the service name, the method name, and the method type (GET, PUT, etc, most of the time will be GET)

+ +
+ +
+
+
+ service_name: + string + + +
+
+

the name of the service

+ +
+ +
+
+
+ service_endpoint: + string + + +
+
+

the name of the endpoint on the service

+ +
+ +
+
+
+ endpoint_method: + string + + +
+
+

GET, POST, PUT, etc

+ +
+ +
+
+
+
+
+
+
+
+

service_method: + object + + + +

+
+
+
+

a URL and HTTP method exposed via a CDAP service

+ +
+ +
+
+
+ url: + string + + +
+
+

the fully qualified URL in CDAP for this service

+ +
+ +
+
+
+ method: + string + + +
+
+

HTTP method you can perform on the URL, e.g., GET, PUT, etc

+ +
+ +
+
+
+
+
+
+
+ + diff --git a/swagger/swagger.json b/swagger/swagger.json new file mode 100644 index 0000000..4490a99 --- /dev/null +++ b/swagger/swagger.json @@ -0,0 +1,560 @@ +{ + "swagger": "2.0", + "info": { + "version": "4.0.3", + "title": "CDAP Broker API" + }, + "paths": { + "/": { + "get": { + "description": "shows some information about this service", + "responses": { + "200": { + "description": "successful response", + "schema": { + "$ref": "#/definitions/info" + } + } + } + } + }, + "/application": { + "get": { + "description": "get all applications registered with this broker", + "responses": { + "200": { + "description": "successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/appname" + } + } + } + } + } + }, + "/application/delete": { + "post": { + "description": "endpoint to delete multiple applications at once. Returns an array of status codes, where statuscode[i] = response returned from DELETE(application/i)", + "parameters": [ + { + "name": "postbody", + "in": "body", + "description": "required post body", + "required": true, + "schema": { + "$ref": "#/definitions/multideleteput" + } + } + ], + "responses": { + "200": { + "description": "successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/returncode" + } + } + } + } + } + }, + "/application/{appname}": { + "parameters": [ + { + "name": "appname", + "in": "path", + "description": "Name of the application.", + "required": true, + "type": "string", + "format": "text" + } + ], + "get": { + "description": "Returns the representation of the application resource, including the links for healthcheck and metrics.", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Application" + } + }, + "404": { + "description": "no app with name 'appname' registered with this broker." + } + } + }, + "put": { + "description": "Register an app for service and configuration discovery. This will light up a metrics and health endpoint for this app. `appname` is assumed to also be the key in consul.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "putbody", + "in": "body", + "description": "required put body", + "required": true, + "schema": { + "$ref": "#/definitions/appput" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Application" + } + }, + "400": { + "description": "put was performed but the appname was already registered with the broker, or Invalid PUT body" + } + } + }, + "delete": { + "description": "Remove an app for service and configuration discovery. This will remove the metrics and health endpoints for this app.", + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "no app with name 'appname' registered with this broker." + } + } + } + }, + "/application*/{appname}": { + "parameters": [ + { + "name": "appname", + "in": "path", + "description": "Name of the application.", + "required": true, + "type": "string", + "format": "text" + } + ], + "put": { + "description": "(This is a hacky way of supporting \"oneOf\" because Swagger does not support oneOf https://github.com/OAI/OpenAPI-Specification/issues/333. This is the same endpoint as PUT /application/appname, except the PUT body is different.)\n\nRegister a hydrator app for service and configuration discovery. This will light up a metrics and health endpoint for this app. `appname` is assumed to also be the key in consul.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "putbody", + "in": "body", + "description": "required put body", + "required": true, + "schema": { + "$ref": "#/definitions/hydratorappput" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Application" + } + }, + "400": { + "description": "put was performed but the appname was already registered with the broker, or Invalid PUT body" + } + } + } + }, + "/application/{appname}/metrics": { + "get": { + "description": "Get live (real-time) app specific metrics for the running app appname. Metrics are customized per each app by the component developer", + "parameters": [ + { + "name": "appname", + "in": "path", + "description": "Name of the application to get metrics for.", + "required": true, + "type": "string", + "format": "test" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/MetricsObject" + } + }, + "404": { + "description": "no app with name 'appname' registered with this broker." + } + } + } + }, + "/application/{appname}/healthcheck": { + "get": { + "description": "Perform a healthcheck on the running app appname.", + "parameters": [ + { + "name": "appname", + "in": "path", + "description": "Name of the application to get the healthcheck for.", + "required": true, + "type": "string", + "format": "test" + } + ], + "responses": { + "200": { + "description": "Successful response, healthcheck pass" + }, + "404": { + "description": "no app with name 'appname' registered with this broker, or the healthcheck has failed (though I would like to disambiguiate from the first case, CDAP returns a 404 for this)." + } + } + } + }, + "/application/{appname}/reconfigure": { + "parameters": [ + { + "name": "appname", + "in": "path", + "description": "Name of the application.", + "required": true, + "type": "string", + "format": "text" + } + ], + "put": { + "description": "Reconfigures the application.", + "parameters": [ + { + "name": "putbody", + "in": "body", + "description": "required put body", + "required": true, + "schema": { + "$ref": "#/definitions/reconfigput" + } + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "400": { + "description": "Bad request. Can happen with 1) {appname} is not registered with the broker, 2) the required PUT body is wrong, or 3) the smart interface was chosen and none of the config keys match anything in app_config or app_preferences" + } + } + } + } + }, + "definitions": { + "MetricsObject": { + "type": "object", + "description": "key,value object where the key is 'appmetrics' and the value is an app dependent json and specified by the component developer", + "properties": { + "appmetrics": { + "type": "object" + } + } + }, + "Application": { + "type": "object", + "properties": { + "appname": { + "description": "application name", + "type": "string" + }, + "healthcheckurl": { + "description": "fully qualified url to perform healthcheck", + "type": "string" + }, + "metricsurl": { + "description": "fully qualified url to get metrics from", + "type": "string" + }, + "url": { + "description": "fully qualified url of the resource", + "type": "string" + }, + "connectionurl": { + "description": "input URL that you can POST data into (URL of the CDAP stream)", + "type": "string" + }, + "serviceendpoints": { + "description": "a list of HTTP services exposed by this CDAP application", + "type": "array", + "items": { + "$ref": "#/definitions/service_method" + } + } + } + }, + "reconfigput": { + "type": "object", + "properties": { + "reconfiguration_type": { + "description": "the type of reconfiguration", + "type": "string", + "enum": [ + "program-flowlet-app-config", + "program-flowlet-app-preferences", + "program-flowlet-smart" + ] + }, + "config": { + "description": "the config JSON", + "type": "object" + } + }, + "required": [ + "reconfiguration_type", + "config" + ] + }, + "multideleteput": { + "type": "object", + "properties": { + "appnames": { + "type": "array", + "items": { + "$ref": "#/definitions/appname" + } + } + } + }, + "appname": { + "description": "an application name", + "type": "string" + }, + "hydratorappput": { + "type": "object", + "properties": { + "cdap_application_type": { + "description": "denotes whether this is a program-flowlet style application or a hydrator pipeline. For hydrator, this value must be \"hydrator-pipeline\"", + "type": "string", + "enum": [ + "hydrator-pipeline" + ] + }, + "namespace": { + "description": "the cdap namespace this is deployed into", + "type": "string" + }, + "pipeline_config_json_url": { + "description": "the URL of the config.json for this pipeline", + "type": "string" + }, + "streamname": { + "description": "name of the CDAP stream to ingest data into this app. Should come from the developer and Tosca model.", + "type": "string" + }, + "dependencies": { + "description": "represents a list of dependencies to be loaded for this pipeline. Not required.", + "type": "array", + "items": { + "$ref": "#/definitions/hydratordep" + } + } + }, + "required": [ + "cdap_application_type", + "namespace", + "pipeline_config_json_url", + "streamname" + ] + }, + "appput": { + "type": "object", + "properties": { + "cdap_application_type": { + "description": "denotes whether this is a program-flowlet style application or a hydrator pipeline. For program-flowlet style apps, this value must be \"program-flowlet\"", + "type": "string", + "enum": [ + "program-flowlet" + ] + }, + "streamname": { + "description": "name of the CDAP stream to ingest data into this app. Should come from the developer and Tosca model.", + "type": "string" + }, + "namespace": { + "description": "the cdap namespace this is deployed into", + "type": "string" + }, + "jar_url": { + "description": "the URL that the JAR you're deploying resides", + "type": "string" + }, + "artifact_name": { + "description": "the name of the CDAP artifact to be added", + "type": "string" + }, + "artifact_ver": { + "description": "the version of the artifact. Must be in X.Y.Z form" + }, + "app_config": { + "description": "the application config JSON", + "type": "object" + }, + "app_preferences": { + "description": "the application preferences JSON", + "type": "object" + }, + "programs": { + "type": "array", + "items": { + "$ref": "#/definitions/programs" + } + }, + "program_preferences": { + "type": "array", + "items": { + "$ref": "#/definitions/programpref" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/definitions/service_endpoint" + } + } + } + }, + "service_endpoint": { + "description": "descirbes a service endpoint, including the service name, the method name, and the method type (GET, PUT, etc, most of the time will be GET)", + "type": "object", + "properties": { + "service_name": { + "type": "string", + "description": "the name of the service" + }, + "service_endpoint": { + "type": "string", + "description": "the name of the endpoint on the service" + }, + "endpoint_method": { + "type": "string", + "description": "GET, POST, PUT, etc" + } + } + }, + "service_method": { + "description": "a URL and HTTP method exposed via a CDAP service", + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "the fully qualified URL in CDAP for this service" + }, + "method": { + "type": "string", + "description": "HTTP method you can perform on the URL, e.g., GET, PUT, etc" + } + } + }, + "programs": { + "description": "the list of programs in this CDAP app", + "type": "object", + "properties": { + "program_type": { + "description": "must be one of flows, mapreduce, schedules, spark, workflows, workers, or services", + "type": "string" + }, + "program_id": { + "description": "the name of the program", + "type": "string" + } + } + }, + "returncode": { + "description": "an httpreturncode", + "type": "integer" + }, + "hydratordep": { + "description": "represents a hydrator pipeline dependency. An equivelent to the following CURLs are formed with the below four params shown in CAPS \"curl -v -w\"\\n\" -X POST http://cdapurl:11015/v3/namespaces/setelsewhere/artifacts/ARTIFACT_NAME -H \"Artifact-Extends:ARTIFACT_EXTENDS_HEADER\" -H “Artifact-Version:ARTIFACT_VERSION_HEADER” --data-binary @(DOWNLOADED FROM ARTIFACT_URL)\",\"curl -v -w\"\\n\" -X PUT http://cdapurl:11015/v3/namespaces/setelsewhere/artifacts/ARTIFACT_NAME/versions/ARTIFACT_VERSION_HEADER/properties -d (DOWNLOADED FROM UI_PROPERTIES_URL)\"", + "properties": { + "artifact_extends_header": { + "description": "the value of the header that gets passed in for artifact-extends, e.g., \"Artifact-Extends:system:cdap-data-pipeline[4.0.1,5.0.0)\"", + "type": "string" + }, + "artifact_name": { + "description": "the name of the artifact", + "type": "string" + }, + "artifact_version_header": { + "description": "the value of the header that gets passed in for artifact-version, e.g., \"Artifact-Version:1.0.0-SNAPSHOT\"", + "type": "string" + }, + "artifact_url": { + "description": "the URL of the artifact JAR", + "type": "string" + }, + "ui_properties_url": { + "description": "the URL of the properties.json if the custom artifact has UI properties. This is optional.", + "type": "string" + } + }, + "required": [ + "artifact_extends_header", + "artifact_name", + "artifact_version_header", + "artifact_url" + ] + }, + "programpref": { + "description": "the list of programs in this CDAP app", + "type": "object", + "properties": { + "program_type": { + "description": "must be one of flows, mapreduce, schedules, spark, workflows, workers, or services", + "type": "string" + }, + "program_id": { + "description": "the name of the program", + "type": "string" + }, + "program_pref": { + "description": "the preference JSON to set for this program", + "type": "object" + } + } + }, + "info": { + "description": "some broker information", + "type": "object", + "properties": { + "managed cdap url": { + "description": "the url of the CDAP cluster API this broker is managing", + "type": "string" + }, + "number of applications registered": { + "type": "integer" + }, + "uptime (s)": { + "type": "integer" + }, + "cdap GUI port": { + "type": "integer", + "description": "The GUI port of the CDAP cluster this broker is managing. Mostly to help users of this API check their application in cdap. Note, will return UNKNOWN_CDAP_VERSION if it cannot be determined." + }, + "cdap cluster version": { + "type": "string", + "description": "the version of the CDAP cluster this broker is managing. Note, will return UKNOWN_CDAP_VERSION if it cannot be determined." + }, + "broker API version": { + "type": "string", + "description": "the API version of this running broker" + } + } + } + } +} diff --git a/swagger/swagger.yaml b/swagger/swagger.yaml new file mode 100644 index 0000000..506908f --- /dev/null +++ b/swagger/swagger.yaml @@ -0,0 +1,418 @@ +# Example YAML to get you started quickly. +# Be aware that YAML has indentation based scoping. +# Code completion support is available so start typing for available options. +swagger: '2.0' + +# This is your document metadata +info: + version: "4.0.3" + title: CDAP Broker API + +paths: + /: + get: + description: shows some information about this service + responses: + 200: + description: successful response + schema: + $ref: '#/definitions/info' + + /application: + get: + description: get all applications registered with this broker + responses: + 200: + description: successful response + schema: + type: array + items: + $ref: '#/definitions/appname' + + /application/delete: + post: + description: endpoint to delete multiple applications at once. Returns an array of status codes, where statuscode[i] = response returned from DELETE(application/i) + parameters: + - name: postbody + in: body + description: required post body + required: true + schema: + $ref: '#/definitions/multideleteput' + responses: + 200: + description: successful response + schema: + type: array + items: + $ref: '#/definitions/returncode' + + /application/{appname}: + parameters: + - name: appname + in: path + description: Name of the application. + required: true + type: string + format: text + + get: + description: Returns the representation of the application resource, including the links for healthcheck and metrics. + responses: + 200: + description: Successful response + schema: + $ref: '#/definitions/Application' + 404: + description: no app with name 'appname' registered with this broker. + + put: + description: Register an app for service and configuration discovery. This will light up a metrics and health endpoint for this app. `appname` is assumed to also be the key in consul. + consumes: + - application/json + produces: + - application/json + parameters: + - name: putbody + in: body + description: required put body + required: true + schema: + $ref: '#/definitions/appput' + + responses: + 200: + description: Successful response + schema: + $ref: '#/definitions/Application' + 400: + description: put was performed but the appname was already registered with the broker, or Invalid PUT body + + + delete: + description: Remove an app for service and configuration discovery. This will remove the metrics and health endpoints for this app. + responses: + 200: + description: Successful response + 404: + description: no app with name 'appname' registered with this broker. + + /application*/{appname}: + parameters: + - name: appname + in: path + description: Name of the application. + required: true + type: string + format: text + + put: + description: (This is a hacky way of supporting "oneOf" because Swagger does not support oneOf https://github.com/OAI/OpenAPI-Specification/issues/333. This is the same endpoint as PUT /application/appname, except the PUT body is different.) + + + Register a hydrator app for service and configuration discovery. This will light up a metrics and health endpoint for this app. `appname` is assumed to also be the key in consul. + consumes: + - application/json + produces: + - application/json + parameters: + - name: putbody + in: body + description: required put body + required: true + schema: + $ref: '#/definitions/hydratorappput' + + responses: + 200: + description: Successful response + schema: + $ref: '#/definitions/Application' + 400: + description: put was performed but the appname was already registered with the broker, or Invalid PUT body + + + /application/{appname}/metrics: + get: + # This is array of GET operation parameters: + description: Get live (real-time) app specific metrics for the running app appname. Metrics are customized per each app by the component developer + parameters: + # An example parameter that is in query and is required + - name: appname + in: path + description: Name of the application to get metrics for. + required: true + type: string + format: test + + # Expected responses for this operation: + responses: + 200: + description: Successful response + schema: + $ref: '#/definitions/MetricsObject' + 404: + description: no app with name 'appname' registered with this broker. + + /application/{appname}/healthcheck: + get: + # This is array of GET operation parameters: + description: Perform a healthcheck on the running app appname. + parameters: + # An example parameter that is in query and is required + - name: appname + in: path + description: Name of the application to get the healthcheck for. + required: true + type: string + format: test + + # Expected responses for this operation: + responses: + # Response code + 200: + description: Successful response, healthcheck pass + 404: + description: no app with name 'appname' registered with this broker, or the healthcheck has failed (though I would like to disambiguiate from the first case, CDAP returns a 404 for this). + + /application/{appname}/reconfigure: + parameters: + - name: appname + in: path + description: Name of the application. + required: true + type: string + format: text + put: + description: Reconfigures the application. + parameters: + - name: putbody + in: body + description: required put body + required: true + schema: + $ref: '#/definitions/reconfigput' + responses: + 200: + description: Successful response + 400: + description: Bad request. Can happen with 1) {appname} is not registered with the broker, 2) the required PUT body is wrong, or 3) the smart interface was chosen and none of the config keys match anything in app_config or app_preferences + +definitions: + MetricsObject: + type: object + description: key,value object where the key is 'appmetrics' and the value is an app dependent json and specified by the component developer + properties: + appmetrics: + type: object + + Application: + type: object + properties: + appname: + description: application name + type: string + healthcheckurl: + description: fully qualified url to perform healthcheck + type: string + metricsurl: + description: fully qualified url to get metrics from + type: string + url: + description: fully qualified url of the resource + type: string + connectionurl: + description: input URL that you can POST data into (URL of the CDAP stream) + type: string + serviceendpoints: + description: a list of HTTP services exposed by this CDAP application + type: array + items: + $ref: '#/definitions/service_method' + + reconfigput: + type: object + properties: + reconfiguration_type: + description: the type of reconfiguration + type: string + enum: ["program-flowlet-app-config", "program-flowlet-app-preferences", "program-flowlet-smart"] + config: + description: the config JSON + type: object + required: ["reconfiguration_type", "config"] + + multideleteput: + type: object + properties: + appnames: + type: array + items: + $ref: '#/definitions/appname' + + appname: + description: an application name + type: string + + hydratorappput: + type: object + properties: + cdap_application_type: + description: denotes whether this is a program-flowlet style application or a hydrator pipeline. For hydrator, this value must be "hydrator-pipeline" + type: string + enum: ["hydrator-pipeline"] + namespace: + description: the cdap namespace this is deployed into + type: string + pipeline_config_json_url: + description: the URL of the config.json for this pipeline + type: string + streamname: + description: name of the CDAP stream to ingest data into this app. Should come from the developer and Tosca model. + type: string + dependencies: + description: represents a list of dependencies to be loaded for this pipeline. Not required. + type: array + items: + $ref: '#/definitions/hydratordep' + required: ["cdap_application_type", "namespace", "pipeline_config_json_url", "streamname"] + + appput: + type: object + properties: + cdap_application_type: + description: denotes whether this is a program-flowlet style application or a hydrator pipeline. For program-flowlet style apps, this value must be "program-flowlet" + type: string + enum: ["program-flowlet"] + streamname: + description: name of the CDAP stream to ingest data into this app. Should come from the developer and Tosca model. + type: string + namespace: + description: the cdap namespace this is deployed into + type: string + jar_url: + description: the URL that the JAR you're deploying resides + type: string + artifact_name: + description: the name of the CDAP artifact to be added + type: string + artifact_ver: + description: the version of the artifact. Must be in X.Y.Z form + app_config: + description: the application config JSON + type: object + app_preferences: + description: the application preferences JSON + type: object + programs: + type: array + items: + $ref: '#/definitions/programs' + program_preferences: + type: array + items: + $ref: '#/definitions/programpref' + services: + type: array + items: + $ref: '#/definitions/service_endpoint' + + service_endpoint: + description: descirbes a service endpoint, including the service name, the method name, and the method type (GET, PUT, etc, most of the time will be GET) + type: object + properties: + service_name: + type: string + description: the name of the service + service_endpoint: + type: string + description: the name of the endpoint on the service + endpoint_method: + type: string + description: GET, POST, PUT, etc + + service_method: + description: a URL and HTTP method exposed via a CDAP service + type: object + properties: + url: + type: string + description: the fully qualified URL in CDAP for this service + method: + type: string + description: HTTP method you can perform on the URL, e.g., GET, PUT, etc + + programs: + description: the list of programs in this CDAP app + type: object + properties: + program_type: + description: must be one of flows, mapreduce, schedules, spark, workflows, workers, or services + type: string + program_id: + description: the name of the program + type: string + + returncode: + description: an httpreturncode + type: integer + + hydratordep: + description: represents a hydrator pipeline dependency. An equivelent to the following CURLs are formed with the below four params shown in CAPS "curl -v -w"\n" -X POST http://cdapurl:11015/v3/namespaces/setelsewhere/artifacts/ARTIFACT_NAME -H "Artifact-Extends:ARTIFACT_EXTENDS_HEADER" -H “Artifact-Version:ARTIFACT_VERSION_HEADER” --data-binary @(DOWNLOADED FROM ARTIFACT_URL)","curl -v -w"\n" -X PUT http://cdapurl:11015/v3/namespaces/setelsewhere/artifacts/ARTIFACT_NAME/versions/ARTIFACT_VERSION_HEADER/properties -d (DOWNLOADED FROM UI_PROPERTIES_URL)" + properties: + artifact_extends_header: + description: the value of the header that gets passed in for artifact-extends, e.g., "Artifact-Extends:system:cdap-data-pipeline[4.0.1,5.0.0)" + type: string + artifact_name: + description: the name of the artifact + type: string + artifact_version_header : + description: the value of the header that gets passed in for artifact-version, e.g., "Artifact-Version:1.0.0-SNAPSHOT" + type: string + artifact_url: + description: the URL of the artifact JAR + type: string + ui_properties_url: + description: the URL of the properties.json if the custom artifact has UI properties. This is optional. + type: string + required: ["artifact_extends_header", "artifact_name", "artifact_version_header", "artifact_url"] + + programpref: + description: the list of programs in this CDAP app + type: object + properties: + program_type: + description: must be one of flows, mapreduce, schedules, spark, workflows, workers, or services + type: string + program_id: + description: the name of the program + type: string + program_pref: + description: the preference JSON to set for this program + type: object + + info: + description: some broker information + type: object + properties: + managed cdap url: + description: the url of the CDAP cluster API this broker is managing + type: string + number of applications registered: + type: integer + uptime (s): + type: integer + cdap GUI port: + type: integer + description: The GUI port of the CDAP cluster this broker is managing. Mostly to help users of this API check their application in cdap. Note, will return UNKNOWN_CDAP_VERSION if it cannot be determined. + cdap cluster version: + type: string + description: the version of the CDAP cluster this broker is managing. Note, will return UKNOWN_CDAP_VERSION if it cannot be determined. + broker API version: + type: string + description: the API version of this running broker + + + + + diff --git a/test/apitest/apitest_SUITE.erl b/test/apitest/apitest_SUITE.erl new file mode 100644 index 0000000..971204c --- /dev/null +++ b/test/apitest/apitest_SUITE.erl @@ -0,0 +1,826 @@ +% ============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. +-module(apitest_SUITE). +-include_lib("common_test/include/ct.hrl"). +-include("../../src/application.hrl"). +-export([all/0, groups/0, init_per_suite/1, end_per_suite/1]). +-export([server_health_test/1, app_deploy/1, hydrator_deploy/1, app_teardown/1, app_test/1, app_reconfigure/1, test_failures/1, app_botch_flows/1, app_botch_delete/1, app_botch_consul_delete/1, invalid_reconfigure/1, delete_all/1, + hydrator_app_teardown/1, hydrator_test/1, + hydrator_wdeps_deploy/1, + hydrator_wdeps_test/1, + hydrator_wdeps_teardown/1 + ]). + +%lazy shorthands (yay C style macros! miss these in python) +-define(SC(L), util:concat(L)). +-define(PLG(K, PL), proplists:get_value(K, PL)). +-define(XER, "testing-XER"). +-define(D(X), erlang:display(X)). + +all() -> [ + {group, progapi}, + {group, hydratorapi}, + {group, apibotchedflows}, + {group, apibotcheddeleted}, + {group, apibotchedconsuldeleted}, + {group, invalidreconfig}, + {group, apideleteall} + ]. +groups() -> [ + {progapi, %prog-flow test + [], + [ + server_health_test, + test_failures, + app_deploy, + app_test, + app_reconfigure, + app_test, + app_teardown + ]}, + {hydratorapi, %hydrator test + [], + [ + server_health_test, + test_failures, + hydrator_deploy, + hydrator_test, + hydrator_app_teardown, + hydrator_wdeps_deploy, + hydrator_wdeps_test, + hydrator_wdeps_teardown + ]}, + {apibotchedflows, %deploy, manually stop flows, then try to delete + [], + [ + server_health_test, + app_deploy, + app_botch_flows, + app_teardown + ]}, + {apibotcheddeleted, %deploy, manually stop flows, delete it manually from cdap, then try to delete + [], + [ + server_health_test, + app_deploy, + app_botch_delete, + app_teardown + ]}, + {apibotchedconsuldeleted, %deploy, manually stop flows, delete it manually from cdap, then try to delete + [], + [ + server_health_test, + app_deploy, + app_botch_consul_delete, + app_teardown + ]}, + {invalidreconfig, %call reconfigure on an app that DNE + [], + [ + server_health_test, + app_deploy, + invalid_reconfigure, + app_teardown + ]}, + {apideleteall, + [], + [ + server_health_test, + app_deploy, + delete_all + ]} + ]. + +%HELPER FUNCTIONS +setup_rels(Config, D) -> + %deploy/delete the testing keys into Consul. This would normally be done by the Cloudify plugin + % + %#NOTE: This is weird. The sequence of steps is: + % 1 Cloudify populates rels key + % 2 Cloudify sends broker the unbound config + % 3 Broker pushes unbound config to consul + % 4 Broker binds config + % 5 Broker pushes bound config to CDAP + % Between state 1 and 3 consul is in an inconsistent state where it has only the rels key but not the config key. Not so sure about this. They seem to be a pair. Maybe the rels key should be pushed to the source node to be dealt with. + % #Here, we are mocking step 1 + URL = ?SC([?PLG(consul_url, Config), "/v1/kv/", ?PLG(appname, Config), ":rel"]), + case D of + setup -> {200,"true"} = httpabs:put(?XER, URL, "application/json", jiffy:encode([<<"666_fake_testing_service">>])); + teardown -> {200,"true"} = httpabs:delete(?XER, URL) + end, + httpabs:get(?XER, URL). + +setup_fake_testing_service(Config, D) -> + %register a fake testing service to test that the CDAP app recieved it's bound configuration properly + Name = <<"666_fake_testing_service">>, + SrvURL = ?SC([?PLG(consul_url, Config), "/v1/catalog/service/", Name]), + case D of + setup -> + URL = ?SC([?PLG(consul_url, Config), "/v1/agent/service/register"]), + Body = {[{<<"name">>, Name}, + {<<"Address">>, <<"666.666.666.666">>}, + {<<"Port">>, 13} + ]}, + {200, []} = httpabs:put(?XER, URL, "application/json", jiffy:encode(Body)), + httpabs:get(?XER, SrvURL); + teardown -> + %total failure on Consul's part for this not to be a delete on the same endpoint + URL = ?SC([?PLG(consul_url, Config), "/v1/agent/service/deregister/", Name]), + {200, []} = httpabs:put(?XER, URL, "application/json", ""), + httpabs:get(?XER, SrvURL) + end. + +get_config_consul(C) -> + %get config from consul. returns the code too for tests testing for a 404 + {RC, RB} = consul_interface:consul_get_configuration(?XER, ?PLG(appname, C), ?PLG(consul_url, C)), + case RC of + 200 -> {RC, util:ejson_to_map(RB)}; + _ -> {RC, RB} + end. + +get_config_cdap(C) -> + {RC, RB} = cdap_interface:get_app_config(?XER, ?PLG(appname, C), ?PLG(namespace, C),?PLG(cdap_url, C)), + case RC of + 200 -> + %I think CDAP is DOUBLY encoding JSON!! + {RC, jiffy:decode(jiffy:decode(jiffy:encode(RB)), [return_maps])}; + _ -> {RC, RB} + end. + +get_preferences_cdap(C) -> + {RC, RB} = cdap_interface:get_app_preferences(?XER, ?PLG(appname, C), ?PLG(namespace, C),?PLG(cdap_url, C)), + case RC of + 200 -> {RC, util:ejson_to_map(RB)}; + _ -> {RC, RB} + end. + +get_preferences_consul(C) -> + %get preferences from consul. returns the code too for tests testing for a 404 + {RC, RB} = consul_interface:consul_get_preferences(?XER, ?PLG(appname, C), ?PLG(consul_url, C)), + case RC of + 200 -> {RC, util:ejson_to_map(RB)}; + _ -> {RC, RB} + end. + +valid_deploy_body(C) -> + {[ + {<<"cdap_application_type">>, <<"program-flowlet">>}, + {<<"namespace">>, ?PLG(namespace, C)}, + {<<"streamname">>, ?PLG(streamname, C)}, + {<<"jar_url">>, ?PLG(jar_url, C)}, + {<<"artifact_name">>, ?PLG(art_name, C)}, + {<<"artifact_version">>, ?PLG(art_ver, C)}, + {<<"app_config">>, ?PLG(init_config, C)}, + {<<"app_preferences">>, ?PLG(init_preferences, C)}, + {<<"services">>, [{[{<<"service_name">>, <<"Greeting">>}, + {<<"service_endpoint">>, <<"greet">>}, + {<<"endpoint_method">>, <<"GET">>}]}]}, + {<<"programs">>, [ + {[{<<"program_type">>, <<"flows">>}, + {<<"program_id">>, <<"WhoFlow">>}]}, + {[{<<"program_type">>, <<"services">>}, + {<<"program_id">>, <<"Greeting">>}]}]}, + {<<"program_preferences">>, [ + {[{<<"program_type">>,<<"flows">>}, + {<<"program_id">>, <<"WhoFlow">>}, + {<<"program_pref">>, ?PLG(whoflowpref, C)}]} + ]} + ]}. + +%%%%%%%%%%%%%%% +%TEST FUNCTIONS +init_per_suite(_C) -> + %get platform ENVs + [MyName, ConsulURL, _, _] = util:get_platform_envs_and_config(), + + BrokerUrl = case os:getenv("BROKER_TEST_TYPE") of + false -> %no env variable means start the broker on localhost + %start a local broker + {ok,[syntax_tools,compiler,goldrush,lager,jiffy,mnesia,ranch,cowlib,cowboy,leptus,uuid,iso8601,cdapbroker]} = application:ensure_all_started(cdapbroker), + "http://localhost:7777"; + "DOCKER" -> + "http://localhost:7777"; + "REMOTE" -> + %Using MyName, fetch from Consul the broker info + {MyIP, MyPort} = consul_interface:consul_get_service_ip_port(MyName, ConsulURL), + ?SC(["http://", MyIP, ":", integer_to_binary(MyPort)]) + end, + + %get NEXUS_ROOT for testing purposes. + Nexus = os:getenv("NEXUS_RAW_ROOT"), + true = (Nexus /= false), %blow if this wasn't set, we need it. + + {200, RB} = httpabs:get(?XER, BrokerUrl), + CDAPUrl = maps:get(<<"managed cdap url">>, jiffy:decode(RB, [return_maps])), + + %set properties that are shared between program-flowlet and hydrator + Namespace = <<"testns">>, + CDAPUrlNS = ?SC([CDAPUrl, "/v3/namespaces/", Namespace]), + + %set up config for program-flowlet app + Appname = <<"hwtest">>, + Streamname = <<"who">>, + + %setup config for hydrator pipeline + HydratorAppname = <<"hydratortest">>, + HydratorAppURL = ?SC([CDAPUrlNS, "/apps/", HydratorAppname]), + HydratorStreamname = <<"s1">>, %horrible name but not made by me + + HydratorWDepsAppname = <<"hydratorwdepstest">>, + HydratorWDepsAppURL = ?SC([CDAPUrlNS, "/apps/", HydratorWDepsAppname]), + HydratorWDepsStreamname = <<"t1">>, %horrible name but not made by me + + %Set up this test suites configuration + [{broker_url, BrokerUrl}, + {cdap_url, CDAPUrl}, + {cdap_ns_url, CDAPUrlNS}, + {jar_url, ?SC([Nexus, "/jar_files/HelloWorld-3.4.3.jar"])}, + {consul_url, ConsulURL}, + {consul_app_url, ?SC([ConsulURL, "/v1/catalog/service/", Appname])}, + {app_url, ?SC([CDAPUrlNS, "/apps/", Appname])}, + {namespace, Namespace}, + {appname, Appname}, + {broker_app_url, ?SC([BrokerUrl, "/application/", Appname])}, + {stream_url, ?SC([CDAPUrlNS, "/streams/", Streamname])}, + {art_ver, <<"3.4.3">>}, + {art_name, <<"HelloWorld">>}, + {streamname, Streamname}, + {init_config, {[ + {<<"streams_produces">>, <<"\{\{fake_testing_service\}\}">>}, + {<<"services_calls">>, <<"\{\{fake_testing_service\}\}">>}, + {<<"donotresolveme">>, <<"donotabsolveme">>} + ]}}, + {whoflowpref, {[{<<"progfoo">>, <<"progbar">>}]}}, + {init_preferences, {[{<<"preffoo">>, <<"prefbar">>}]}}, + {reconfig, {[{<<"foo">>, <<"bar">>}]}}, + + %hydrator test properties + {hydrator_appname, HydratorAppname}, + {broker_hydrator_app_url, ?SC([BrokerUrl, "/application/", HydratorAppname])}, + {hydrator_app_url, HydratorAppURL}, + {hydrator_json_url, ?SC([Nexus, "/json_files/t1-4.1.2.json "])}, + {hydrator_pipeline_status_url, ?SC([HydratorAppURL, "/schedules/dataPipelineSchedule/status"])}, + {hydrator_stream_url, ?SC([CDAPUrlNS, "/streams/", HydratorStreamname])}, + {hydrator_streamname, HydratorStreamname}, + {consul_hydrator_app_url, ?SC([ConsulURL, "/v1/catalog/service/", HydratorAppname])}, + + %hydrator with deps test properties + {hydrator_wdeps_appname, HydratorWDepsAppname}, + {hydrator_wdeps_artname, <<"demoTCA">>}, + {hydrator_wdeps_artver, <<"1.0.0-SNAPSHOT">>}, + {hydrator_wdeps_app_url, HydratorWDepsAppURL}, + {broker_hydrator_wdeps_app_url, ?SC([BrokerUrl, "/application/", HydratorWDepsAppname])}, + {hydrator_wdeps_streamname, HydratorWDepsStreamname}, + {hydrator_wdeps_stream_url, ?SC([CDAPUrlNS, "/streams/", HydratorWDepsStreamname])}, + {hydrator_wdeps_json_url, ?SC([Nexus, "/json_files/t1-4.1.2.json"])}, + {hydrator_wdeps_properties_json_url, ?SC([Nexus, "/json_files/demoTCA-1.0.0-SNAPSHOT-properties.json"])}, + {hydrator_wdeps_jar_url, ?SC([Nexus, "/json_files/demoTCA-1.0.0-SNAPSHOT.jar"])}, + {hydrator_wdeps_test_data_url, ?SC([Nexus, "/txt_files/tcaDemoData100k.txt"])}, + {consul_hydrator_wdeps_app_url, ?SC([ConsulURL, "/v1/catalog/service/", HydratorWDepsAppname])}, + {hydrator_pipeline_wdeps_status_url, ?SC([HydratorWDepsAppURL, "/schedules/dataPipelineSchedule/status"])} + ] + . + +end_per_suite(_C) -> + _ = application:stop(cdapbroker). + +server_health_test(C) -> + {200, RB} = httpabs:get(?XER, ?PLG(broker_url,C)), + M = jiffy:decode(RB, [return_maps]), + true = maps:is_key(<<"managed cdap url">>, M), + true = maps:is_key(<<"number of applications registered">>, M), + true = maps:is_key(<<"uptime (s)">>, M), + true = maps:is_key(<<"cdap cluster version">>, M), + true = maps:is_key(<<"cdap GUI port">>, M), + true = maps:is_key(<<"broker API version">>, M) + . + +app_deploy(C) -> %C == Config + %Deploy the test application + + %Deploy the rel key + {200, _} = setup_rels(C, setup), + + %Register the fake testing service to test config binding. Make sure it's not empty + {200, F} = setup_fake_testing_service(C, setup), + true = F /= [], + + ExpectedBoundConfg = maps:from_list([ + {<<"services_calls">> , [<<"666.666.666.666:13">>]}, + {<<"streams_produces">>, [<<"666.666.666.666:13">>]}, + {<<"donotresolveme">> , <<"donotabsolveme">>} + ]), + + %Maps can be used safely with the == operator but appears proplists cannot be + Expected = maps:from_list([ + {<<"appname">>, ?PLG(appname, C)}, + {<<"apptype">>, <<"program-flowlet">>}, + {<<"namespace">>, ?PLG(namespace, C)}, + {<<"healthcheckurl">>, list_to_binary(?SC([?PLG(broker_app_url, C), "/healthcheck"]))}, + {<<"metricsurl">>, list_to_binary(?SC([?PLG(broker_app_url, C), "/metrics"]))}, + {<<"url">>, list_to_binary(?PLG(broker_app_url, C))}, + {<<"connectionurl">>, list_to_binary(?PLG(stream_url, C))}, + {<<"serviceendpoints">>, [#{<<"url">> => list_to_binary(?SC([?PLG(app_url, C), "/services/Greeting/methods/greet"])), + <<"method">> => <<"GET">>}]}, + {<<"unbound_config">>, #{<<"streams_produces">> => <<"\{\{fake_testing_service\}\}">>, <<"services_calls">> => <<"\{\{fake_testing_service\}\}">>, <<"donotresolveme">> => <<"donotabsolveme">>}}, + {<<"bound_config">>, ExpectedBoundConfg} + ]), + + %assert the current appliccation list does not contain our test app + {200,RB0} = httpabs:get(?XER, ?SC([?PLG(broker_url, C), "/application"])), + true = lists:all(fun(X) -> X /= ?PLG(appname, C) end, jiffy:decode(RB0)), + + %deploy the app + Body = valid_deploy_body(C), + {200, RB} = httpabs:put(?XER, ?PLG(broker_app_url, C), "application/json", jiffy:encode(Body)), + + %The CDAP APIs return the config as a JSON dumped to a string, so we need to get that back into a real JSON to have key-order-independent equality testing + Fix = fun(X) -> + RBMap = jiffy:decode(X, [return_maps]), + maps:update(<<"bound_config">>, jiffy:decode(maps:get(<<"bound_config">>, RBMap), [return_maps]), RBMap) + end, + + %assert that the return and get matches what we put in + true = Fix(RB) == Expected, + + %assert hitting the get application endpoint works + {200, RB2} = httpabs:get(?XER, ?PLG(broker_app_url, C)), + true = Fix(RB2) == Expected, + + %assert the current application list now includes our new app + {200, RB3} = httpabs:get(?XER, ?SC([?PLG(broker_url, C), "/application"])), + true = lists:any(fun(X) -> X == ?PLG(appname, C) end, jiffy:decode(RB3)), + + %make sure it is in CDAP + {200, _} = httpabs:get(?XER, ?PLG(app_url, C)), + + %check metrics + {200, _} = httpabs:get(?XER, ?SC([?PLG(broker_app_url, C), "/metrics"])), + + %check healthcheck + {200, _} = httpabs:get(?XER,?SC([?PLG(broker_app_url, C), "/healthcheck"])), + + %make sure that the service is registered. TODO! Could get more fancy by manually checking a healthcheck + {200, RBHC} = httpabs:get(?XER,?PLG(consul_app_url, C)), + true = jiffy:decode(RBHC) /= [], + + %check that the UNbound config is correct + true = {200, util:ejson_to_map(?PLG(init_config, C))} == get_config_consul(C), + + %check that the preferences in Consul is correct + InitPrefMap = util:ejson_to_map(?PLG(init_preferences, C)), + true = {200, InitPrefMap} == get_preferences_consul(C), + + %make sure CDAP has right preferences + true = {200, InitPrefMap} == get_preferences_cdap(C), + + %make sure the config binding service and pulling config out of CDAP all match + %> get it strait from CBS + CBSUrl = util:resolve_cbs(?XER, ?PLG(consul_url, C)), + {200, RB4} = httpabs:get(?XER, ?SC([CBSUrl, "/service_component/", ?PLG(appname, C)])), + %get it from cdap + {200, CDAPConfig} = get_config_cdap(C), + %make sure everythng is as expected + true = ExpectedBoundConfg == jiffy:decode(RB4, [return_maps]), + true = ExpectedBoundConfg == CDAPConfig, + + %try to put the same app again and assert you get a 400 + {400,"State: Bad Request. Return Body: Put recieved on /application/:appname but appname is already registered. Call /application/:appname/reconfigure if trying to reconfigure or delete first"} = + httpabs:put(?XER, ?PLG(broker_app_url, C), "application/json", jiffy:encode(Body)). + +hydrator_deploy(C) -> + Body = {[ + {<<"cdap_application_type">>, <<"hydrator-pipeline">>}, + {<<"namespace">>, ?PLG(namespace, C)}, + {<<"streamname">>, ?PLG(hydrator_streamname, C)}, + {<<"pipeline_config_json_url">>, ?PLG(hydrator_json_url, C)} + ]}, + Expected = maps:from_list([ + {<<"appname">>, ?PLG(hydrator_appname, C)}, + {<<"apptype">>, <<"hydrator-pipeline">>}, + {<<"namespace">>, ?PLG(namespace, C)}, + {<<"healthcheckurl">>, list_to_binary(?SC([?PLG(broker_hydrator_app_url, C), "/healthcheck"]))}, + {<<"metricsurl">>, list_to_binary(?SC([?PLG(broker_hydrator_app_url, C), "/metrics"]))}, + {<<"url">>, list_to_binary(?PLG(broker_hydrator_app_url, C))}, + {<<"connectionurl">>, list_to_binary(?PLG(hydrator_stream_url, C))}, + {<<"serviceendpoints">>, []} + ]), + + %assert the current appliccation list does not contain our test app + {200,RB0} = httpabs:get(?XER, ?SC([?PLG(broker_url, C), "/application"])), + true = lists:all(fun(X) -> X /= ?PLG(hydrator_appname, C) end, jiffy:decode(RB0)), + + %try the deploy + {200, RB1} = httpabs:put(?XER, ?PLG(broker_hydrator_app_url, C), "application/json", jiffy:encode(Body)), + true = jiffy:decode(RB1, [return_maps]) == Expected, + + %make sure the Execution resume worked + {200, RB2} = httpabs:get(?XER, ?PLG(hydrator_pipeline_status_url, C)), + true = jiffy:decode(RB2) == {[{<<"status">>, <<"SCHEDULED">>}]}, + + %make sure it is in CDAP + {200, _} = httpabs:get(?XER, ?PLG(hydrator_app_url, C)), + + %assert the current application list now includes our new app + {200, RB3} = httpabs:get(?XER, ?SC([?PLG(broker_url, C), "/application"])), + true = lists:any(fun(X) -> X == ?PLG(hydrator_appname, C) end, jiffy:decode(RB3)), + + %check healthcheck + {200, _} = httpabs:get(?XER,?SC([?PLG(broker_hydrator_app_url, C), "/healthcheck"])), + + %check metrics + {200, _} = httpabs:get(?XER,?SC([?PLG(broker_hydrator_app_url, C), "/metrics"])), + + %make sure that the service is registered. TODO! Could get more fancy by manually checking a healthcheck + {200, RBHC} = httpabs:get(?XER,?PLG(consul_hydrator_app_url, C)), + true = jiffy:decode(RBHC) /= [] + . + +hydrator_wdeps_deploy(C) -> + Body = {[ + {<<"cdap_application_type">>, <<"hydrator-pipeline">>}, + {<<"namespace">>, ?PLG(namespace, C)}, + {<<"streamname">>, ?PLG(hydrator_wdeps_streamname, C)}, + {<<"pipeline_config_json_url">>, ?PLG(hydrator_wdeps_json_url, C)}, + {<<"dependencies">>, [ + {[ + {<<"artifact_extends_header">>, <<"system:cdap-data-pipeline[4.1.0,5.0.0)">>}, + {<<"artifact_name">>, ?PLG(hydrator_wdeps_artname, C)}, + {<<"artifact_version_header">>, ?PLG(hydrator_wdeps_artver, C)}, + {<<"artifact_url">>, ?PLG(hydrator_wdeps_jar_url, C)}, + {<<"ui_properties_url">>, ?PLG(hydrator_wdeps_properties_json_url, C)} + ]} + ]} + ]}, + Expected = maps:from_list([ + {<<"appname">>, ?PLG(hydrator_wdeps_appname, C)}, + {<<"apptype">>, <<"hydrator-pipeline">>}, + {<<"namespace">>, ?PLG(namespace, C)}, + {<<"healthcheckurl">>, list_to_binary(?SC([?PLG(broker_hydrator_wdeps_app_url, C), "/healthcheck"]))}, + {<<"metricsurl">>, list_to_binary(?SC([?PLG(broker_hydrator_wdeps_app_url, C), "/metrics"]))}, + {<<"url">>, list_to_binary(?PLG(broker_hydrator_wdeps_app_url, C))}, + {<<"connectionurl">>, list_to_binary(?PLG(hydrator_wdeps_stream_url, C))}, + {<<"serviceendpoints">>, []} + ]), + %assert the current appliccation list does not contain our test app + {200,RB0} = httpabs:get(?XER,?SC([?PLG(broker_url, C), "/application"])), + true = lists:all(fun(X) -> X /= ?PLG(hydrator_wdeps_appname, C) end, jiffy:decode(RB0)), + + %try the deploy + {200, RB1} = httpabs:put(?XER, ?PLG(broker_hydrator_wdeps_app_url, C), "application/json", jiffy:encode(Body)), + true = jiffy:decode(RB1, [return_maps]) == Expected, + + %make sure properties are loaded, test artifact + {200, _} = httpabs:get(?XER,?SC([?PLG(cdap_ns_url, C), "/artifacts/", ?PLG(hydrator_wdeps_artname, C), "/versions/", ?PLG(hydrator_wdeps_artver, C), "/properties"])), + + %make sure the Execution resume worked + {200, RB2} = httpabs:get(?XER,?PLG(hydrator_pipeline_wdeps_status_url, C)), + true = jiffy:decode(RB2) == {[{<<"status">>, <<"SCHEDULED">>}]}, + + %make sure it is in CDAP + {200, _} = httpabs:get(?XER,?PLG(hydrator_wdeps_app_url, C)), + + %assert the current application list now includes our new app + {200, RB3} = httpabs:get(?XER,?SC([?PLG(broker_url, C), "/application"])), + true = lists:any(fun(X) -> X == ?PLG(hydrator_wdeps_appname, C) end, jiffy:decode(RB3)), + + %check healthcheck + {200, _} = httpabs:get(?XER,?SC([?PLG(broker_hydrator_wdeps_app_url, C), "/healthcheck"])), + + %check metrics + {200, _} = httpabs:get(?XER,?SC([?PLG(broker_hydrator_wdeps_app_url, C), "/metrics"])), + + %make sure that the service is registered. TODO! Could get more fancy by manually checking a healthcheck + {200, RBHC} = httpabs:get(?XER,?PLG(consul_hydrator_wdeps_app_url, C)), + true = jiffy:decode(RBHC) /= [] + . + +hydrator_test(C) -> + %test te app by injecting some data into the stream and getting it out + %Sleeping since HTTP services may still be booting up: see https://issues.cask.co/browse/CDAP-812 + ok = timer:sleep(30000), %30s + %curl into stream + {200, _} = httpabs:post(?XER, ?PLG(hydrator_stream_url, C), "text/plain", "beer, vodka, gin"), + %query data out + PB = jiffy:encode({[{<<"query">>, <<"select v1, v2, v3 from dataset_pf1">>}]}), + {200, RB} = httpabs:post(?XER, ?SC([?PLG(cdap_ns_url, C), "/data/explore/queries"]), "text/plain", PB), + {[{<<"handle">>, Handle}]} = jiffy:decode(RB), + %results can take time, sleep again + ok = timer:sleep(30000), + Expected = {[ + {<<"status">>,<<"FINISHED">>}, + {<<"hasResults">>,true} + ]}, + {200, RB2} = httpabs:get(?XER, ?SC([?PLG(cdap_url, C), "/v3/data/explore/queries", "/", Handle, "/status"])), + true = Expected == jiffy:decode(RB2), + {200, _} = httpabs:post(?XER, ?SC([?PLG(cdap_url, C), "/v3/data/explore/queries", "/", Handle, "/next"]), "text/plain", "") + . + +app_test(C) -> + %Sleeping since HTTP services may still be booting up: see https://issues.cask.co/browse/CDAP-812 + ok = timer:sleep(30000), %30s + {200, _} = httpabs:post(?XER, ?PLG(stream_url, C), "text/plain", "'Prince of Darkness'"), + {200, "Hello 'Prince of Darkness'!"} = httpabs:get(?XER,?SC([?PLG(app_url, C), "/services/Greeting/methods/greet"])). + +app_reconfigure(C) -> + %Test app reconfiguration + %test new config right in Consul + true = {200, util:ejson_to_map(?PLG(init_config, C))} == get_config_consul(C), + + %do the reconfig + ReconfigMap = util:ejson_to_map({[{<<"foo REDUX EDITION">>, <<"bar">>}, {<<"LEAVE ME ALONE">>, <<"CONFIG EDITION">>}]}), + %test httpabs bad body (not encoded as JSON) + {400,"ERROR: The request Body is malformed"} = httpabs:put(?XER, ?SC([?PLG(broker_app_url, C), "/reconfigure"]), "application/json", {[{<<"reconfiguration_type">>, <<"program-flowlet-app-config">>}, {<<"config">>, ReconfigMap}]}), + %do it properly + {200, _} = httpabs:put(?XER, ?SC([?PLG(broker_app_url, C), "/reconfigure"]), "application/json", jiffy:encode({[{<<"reconfiguration_type">>, <<"program-flowlet-app-config">>},{<<"config">>, ReconfigMap}]})), + %test new config right in consul + true = {200, ReconfigMap} == get_config_consul(C), + %test new config right in cdap + true = {200, ReconfigMap} == get_config_cdap(C), + + %Test preferences reconfiguration + %check that the preferences in Consul is correct + InitMap = util:ejson_to_map(?PLG(init_preferences, C)), + true = {200, InitMap} == get_preferences_consul(C), + %check that the preferences in CDAP are correct + true = {200, InitMap} == get_preferences_cdap(C), + %reconfigure the preferences + PreferencesReconfigMap = util:ejson_to_map({[{<<"preffoo REDUX EDITION">>, <<"prefbar REMIXXX">>}, {<<"LEAVE ME ALONE">>, <<"PREFERENCES EDITION">>}]}), + {200, _} = httpabs:put(?XER, ?SC([?PLG(broker_app_url, C), "/reconfigure"]), "application/json", jiffy:encode({[{<<"reconfiguration_type">>, <<"program-flowlet-app-preferences">>},{<<"config">>, PreferencesReconfigMap}]})), + %make sure consul has right preferences + true = {200, PreferencesReconfigMap} == get_preferences_consul(C), + %make sure CDAP has right preferences + true = {200, PreferencesReconfigMap} == get_preferences_cdap(C), + + %test the smart reconfiguration call + %try to give it a smart where there are keys in just preferences + SmartReconfigPrefMap = util:ejson_to_map({[{<<"preffoo REDUX EDITION">>, <<"BAR'D AGAIN">>}]}), + {200, _} = httpabs:put(?XER, ?SC([?PLG(broker_app_url, C), "/reconfigure"]), "application/json", jiffy:encode({[{<<"reconfiguration_type">>, <<"program-flowlet-smart">>},{<<"config">>, SmartReconfigPrefMap}]})), + ExpectedNewPreferences = #{<<"LEAVE ME ALONE">>=><<"PREFERENCES EDITION">>,<<"preffoo REDUX EDITION">>=><<"BAR'D AGAIN">>}, + true = {200, ExpectedNewPreferences} == get_preferences_consul(C), + true = {200, ExpectedNewPreferences} == get_preferences_cdap(C), + + %try to give it a smart where there are keys in just config + SmartReconfigConfig = {[{<<"foo REDUX EDITION">>, <<"FOO'D AGAIN">>}]}, + {200, _} = httpabs:put(?XER, ?SC([?PLG(broker_app_url, C), "/reconfigure"]), "application/json", jiffy:encode({[{<<"reconfiguration_type">>, <<"program-flowlet-smart">>},{<<"config">>, SmartReconfigConfig}]})), + %make sure CDAP and Consul agree and are equal to what we expected + ExpectedNewConfig = #{<<"LEAVE ME ALONE">>=><<"CONFIG EDITION">>,<<"foo REDUX EDITION">>=><<"FOO'D AGAIN">>}, + true = {200, ExpectedNewConfig} == get_config_consul(C), + true = {200, ExpectedNewConfig} == get_config_cdap(C), + + %try to give it a smart where there are keys in both preferences and config + SmartReconfigBoth = {[{<<"foo REDUX EDITION">>, <<"FOO'D AGAIN AGAIN">>}, {<<"preffoo REDUX EDITION">>, <<"BAR'D AGAIN AGAIN">>}]}, + {200, _} = httpabs:put(?XER, ?SC([?PLG(broker_app_url, C), "/reconfigure"]), "application/json", jiffy:encode({[{<<"reconfiguration_type">>, <<"program-flowlet-smart">>},{<<"config">>, SmartReconfigBoth}]})), + ExpectedNewPreferencesBoth = #{<<"LEAVE ME ALONE">>=><<"PREFERENCES EDITION">>,<<"preffoo REDUX EDITION">>=><<"BAR'D AGAIN AGAIN">>}, + ExpectedNewConfigBoth = #{<<"LEAVE ME ALONE">>=><<"CONFIG EDITION">>,<<"foo REDUX EDITION">>=><<"FOO'D AGAIN AGAIN">>}, + true = {200, ExpectedNewPreferencesBoth} == get_preferences_consul(C), + true = {200, ExpectedNewPreferencesBoth} == get_preferences_cdap(C), + true = {200, ExpectedNewConfigBoth} == get_config_consul(C), + true = {200, ExpectedNewConfigBoth} == get_config_cdap(C), + + %try to give it a smart where there are no overlaps + SmartReconfigNone = {[{<<"EMPTY">>, <<"LIKE YOUR SOUL">>}]}, + {400, _} = httpabs:put(?XER, ?SC([?PLG(broker_app_url, C), "/reconfigure"]), "application/json", jiffy:encode({[{<<"reconfiguration_type">>, <<"program-flowlet-smart">>},{<<"config">>, SmartReconfigNone}]})), + true = {200, ExpectedNewPreferencesBoth} == get_preferences_consul(C), + true = {200, ExpectedNewPreferencesBoth} == get_preferences_cdap(C), + true = {200, ExpectedNewConfigBoth} == get_config_consul(C), + true = {200, ExpectedNewConfigBoth} == get_config_cdap(C) + . + +app_botch_flows(C) -> + %check healthcheck + {200, _} = httpabs:get(?XER,?SC([?PLG(broker_app_url, C), "/healthcheck"])), + + %purposely shut down a flow "manually" to test that undeploy works with a "partially deployed" app + {200, []} = cdap_interface:exec_programs(?XER, ?PLG(appname, C), ?PLG(namespace, C), ?PLG(cdap_url, C), + [#program{type = <<"flows">>, id = <<"WhoFlow">>}, #program{type = <<"services">>, id = <<"Greeting">>}], "stop"), + %make sure healthcheck now fails + {400, _} = httpabs:get(?XER,?SC([?PLG(broker_app_url, C), "/healthcheck"])) + . + +app_botch_delete(C) -> + %purposely shut down flows and then delete the app from the CDAP api to test undeploy works with a [gone] app + {200, []} = cdap_interface:exec_programs(?XER, ?PLG(appname, C), ?PLG(namespace, C), ?PLG(cdap_url, C), + [#program{type = <<"flows">>, id = <<"WhoFlow">>}, #program{type = <<"services">>, id = <<"Greeting">>}], "stop"), + {200, []} = cdap_interface:delete_app(?XER, ?PLG(appname, C), ?PLG(namespace, C), ?PLG(cdap_url, C)), + + %make sure healthcheck now fails + {400, _} = httpabs:get(?XER,?SC([?PLG(broker_app_url, C), "/healthcheck"])) + . + +app_botch_consul_delete(C) -> + %purposefully delete the config in consul to make sure delete doesnt blow up + {200, "true"} = consul_interface:consul_delete_config(?XER, ?PLG(appname, C),?PLG(consul_url, C)). + +app_teardown(C) -> + %Test app teardown and delete + %app is there for now in broker + {200,_ } = httpabs:get(?XER,?PLG(broker_app_url, C)), + + %teardown the test application + {200, []} = httpabs:delete(?XER, ?PLG(broker_app_url, C)), + + %make sure the broker deleted the config from Consul + {404, _} = get_config_consul(C), + + %make sure broker deleted the preferences + {404, _} = get_preferences_consul(C), + + %make sure the broker app url no longer exists + {404, _ } = httpabs:get(?XER,?PLG(broker_app_url, C)), + + %teardown the testing rels + {404, _} = setup_rels(C, teardown), + + %teardown the fake service and make sure it is gone + {200, Srv} = setup_fake_testing_service(C, teardown), + true = Srv == "[]", + + %cdap app gone + {404,"State: Not Found. Return Body: 'application:testns.hwtest.-SNAPSHOT' was not found."} = httpabs:get(?XER,?PLG(app_url, C)), + + %make sure that the service is not registered. TODO! Could get more fancy by manually checking a healthcheck + {200, RBHC} = httpabs:get(?XER,?PLG(consul_app_url, C)), + true = jiffy:decode(RBHC) == []. + +hydrator_app_teardown(C) -> + %Test app teardown and delete + %app is there for now in cdap + {200, _} = httpabs:get(?XER,?PLG(hydrator_app_url, C)), + %app is in broker + {200,_ } = httpabs:get(?XER,?PLG(broker_hydrator_app_url, C)), + %teardown the test application + {200, []} = httpabs:delete(?XER, ?PLG(broker_hydrator_app_url, C)), + %make sure the broker deleted the config from Consul + ?D(<<"todo! put this back:">>), + %{404, _} = get_config_consul(C), + %make sure the broker app url no longer exists + {404, _ } = httpabs:get(?XER,?PLG(broker_hydrator_app_url, C)), + %make sure gone from CDAP + {404,"State: Not Found. Return Body: 'application:testns.hydratortest.-SNAPSHOT' was not found."} = httpabs:get(?XER,?PLG(hydrator_app_url, C)), + %make sure that the service is not registered. TODO! Could get more fancy by manually checking a healthcheck + {200, RBHC} = httpabs:get(?XER,?PLG(consul_hydrator_app_url, C)), + true = jiffy:decode(RBHC) == [] + . + +hydrator_wdeps_test(C) -> + %test te app by injecting some data into the stream and getting it out + %Sleeping since HTTP services may still be booting up: see https://issues.cask.co/browse/CDAP-812 + ok = timer:sleep(30000), %30s + %curl into stream + %grab the test data + {200, TestData} = httpabs:get(?XER,?PLG(hydrator_wdeps_test_data_url, C)), + %push it in + {200, _} = httpabs:post(?XER, ?SC([?PLG(hydrator_wdeps_stream_url, C), "/batch"]), "text/plain", TestData), + %query data out + PB = jiffy:encode({[{<<"query">>, <<"select ts from dataset_t1file">>}]}), + {200, RB} = httpabs:post(?XER, ?SC([?PLG(cdap_ns_url, C), "/data/explore/queries"]), "text/plain", PB), + {[{<<"handle">>, Handle}]} = jiffy:decode(RB), + %results can take time, sleep again + ok = timer:sleep(30000), + Expected = {[ + {<<"status">>,<<"FINISHED">>}, + {<<"hasResults">>,true} + ]}, + {200, RB2} = httpabs:get(?XER,?SC([?PLG(cdap_url, C), "/v3/data/explore/queries", "/", Handle, "/status"])), + true = Expected == jiffy:decode(RB2), + {200, _} = httpabs:post(?XER, ?SC([?PLG(cdap_url, C), "/v3/data/explore/queries", "/", Handle, "/next"]), "text/plain", "") + . + +hydrator_wdeps_teardown(C) -> + %Test app teardown and delete + %app is there for now in cdap + {200, _} = httpabs:get(?XER,?PLG(hydrator_wdeps_app_url, C)), + %app is in broker + {200,_ } = httpabs:get(?XER,?PLG(broker_hydrator_wdeps_app_url, C)), + %teardown the test application + {200, []} = httpabs:delete(?XER, ?PLG(broker_hydrator_wdeps_app_url, C)), + %make sure the broker deleted the config from Consul + ?D(<<"todo! put this back:">>), + %{404, _} = get_config_consul(C), + %make sure the broker app url no longer exists + {404, _ } = httpabs:get(?XER,?PLG(broker_hydrator_wdeps_app_url, C)), + %make sure gone from CDAP + {404,"State: Not Found. Return Body: 'application:testns.hydratortest.-SNAPSHOT' was not found."} = httpabs:get(?XER,?PLG(hydrator_app_url, C)), + %make sure that the service is not registered. TODO! Could get more fancy by manually checking a healthcheck + {200, RBHC} = httpabs:get(?XER,?PLG(consul_hydrator_wdeps_app_url, C)), + true = jiffy:decode(RBHC) == [] + . + +test_failures(C) -> + %test things that should fail + %delete a non-existent app + {404, "State: Not Found. Return Body: Tried to delete an application that was not registered"} = + httpabs:delete(?XER, ?SC([?PLG(broker_app_url, C), "MYFRIENDOFMISERY"])), + + %malformed Broker put + URL = ?SC([?PLG(broker_app_url, C), "FAILURETEST"]), + Body = {[ + {<<"malformed">>, <<"i am">>} + ]}, + {400, "State: Bad Request. Return Body: Invalid PUT Body or unparseable URL"} = httpabs:put(?XER, URL, "application/json", jiffy:encode(Body)), + + %deploy a bad CDAP app with a bad program_id + Body2 = {[ + {<<"cdap_application_type">>, <<"program-flowlet">>}, + {<<"namespace">>, ?PLG(namespace, C)}, + {<<"streamname">>, ?PLG(streamname, C)}, + {<<"jar_url">>, ?PLG(jar_url, C)}, + {<<"artifact_name">>, ?PLG(art_name, C)}, + {<<"artifact_version">>, ?PLG(art_ver, C)}, + {<<"app_config">>, ?PLG(init_config, C)}, + {<<"app_preferences">>, ?PLG(init_preferences, C)}, + {<<"services">>, [{[{<<"service_name">>, <<"Greeting">>}, + {<<"service_endpoint">>, <<"greet">>}, + {<<"endpoint_method">>, <<"GET">>}]}]}, + {<<"programs">>, [ + {[{<<"program_type">>, <<"flows">>}, + {<<"program_id">>, <<"DISSAPOINTMENT">>}]} + ]}, + {<<"program_preferences">>, []} + ]}, + %WORKS IN CDAP 3: + %{404,"State: Not Found. Return Body: State: Not Found. Return Body: 'program:testns.hwtestFAILURETEST.flow.DISSAPOINTMENT' was not found."} = httpabs:put(?XER, URL, "application/json", jiffy:encode(Body2)), + %WORKS IN CDAP 4 (looks like they are doing more intrispection on the jar name) + {404,_} = httpabs:put(?XER, URL, "application/json", jiffy:encode(Body2)), + %make sure the rollback happened + {200, "[]"} = httpabs:get(?XER,?SC([?PLG(broker_url, C), "/application"])), + + %try to deploy with a bad URL where bad means nonexistent (504) + Body3 = {[ + {<<"cdap_application_type">>, <<"program-flowlet">>}, + {<<"namespace">>, ?PLG(namespace, C)}, + {<<"streamname">>, ?PLG(streamname, C)}, + {<<"jar_url">>, ?SC([?PLG(jar_url, C), "DOESNOTEXISTMOSTLIKELY"])}, + {<<"artifact_name">>, ?PLG(art_name, C)}, + {<<"artifact_version">>, ?PLG(art_ver, C)}, + {<<"app_config">>, ?PLG(init_config, C)}, + {<<"app_preferences">>, ?PLG(init_preferences, C)}, + {<<"services">>, [{[{<<"service_name">>, <<"Greeting">>}, {<<"service_endpoint">>, <<"greet">>}, {<<"endpoint_method">>, <<"GET">>}]}]}, + {<<"programs">>, [{[{<<"program_type">>, <<"flows">>},{<<"program_id">>, <<"WhoFlow">>}]},{[{<<"program_type">>, <<"services">>},{<<"program_id">>, <<"Greeting">>}]}]}, + {<<"program_preferences">>, [{[{<<"program_type">>,<<"flows">>}, {<<"program_id">>, <<"WhoFlow">>}, {<<"program_pref">>, ?PLG(whoflowpref, C)}]}]} + ]}, + {404, _} = httpabs:put(?XER, URL, "application/json", jiffy:encode(Body3)), + + %try to deploy with a bad URL where bad means malformed + Body4 = {[ + {<<"cdap_application_type">>, <<"program-flowlet">>}, + {<<"namespace">>, ?PLG(namespace, C)}, + {<<"streamname">>, ?PLG(streamname, C)}, + {<<"jar_url">>, <<"THIS IS NOT EVEN A URL WHAT ARE YOU DOING TO ME">>}, + {<<"artifact_name">>, ?PLG(art_name, C)}, + {<<"artifact_version">>, ?PLG(art_ver, C)}, + {<<"app_config">>, ?PLG(init_config, C)}, + {<<"app_preferences">>, ?PLG(init_preferences, C)}, + {<<"services">>, [{[{<<"service_name">>, <<"Greeting">>}, {<<"service_endpoint">>, <<"greet">>}, {<<"endpoint_method">>, <<"GET">>}]}]}, + {<<"programs">>, [{[{<<"program_type">>, <<"flows">>},{<<"program_id">>, <<"WhoFlow">>}]},{[{<<"program_type">>, <<"services">>},{<<"program_id">>, <<"Greeting">>}]}]}, + {<<"program_preferences">>, [{[{<<"program_type">>,<<"flows">>}, {<<"program_id">>, <<"WhoFlow">>}, {<<"program_pref">>, ?PLG(whoflowpref, C)}]}]} + ]}, + {400,"State: Bad Request. Return Body: ERROR: The following URL is malformed: THIS IS NOT EVEN A URL WHAT ARE YOU DOING TO ME"} = httpabs:put(?XER, URL, "application/json", jiffy:encode(Body4)) + . + +invalid_reconfigure(C) -> + %test reconfiguring an app that does not exist despite put body being correct + {404,"State: Not Found. Return Body: Reconfigure recieved but the app is not registered"} = httpabs:put(?XER, ?SC([?PLG(broker_app_url, C), "THE_VOID", "/reconfigure"]), "application/json", jiffy:encode({[{<<"reconfiguration_type">>, <<"program-flowlet-app-config>">>}, {<<"config">>, {[{<<"foo">>, <<"bar">>}]}}]})), + + %test reconfiguring with an invalid PUT body (missing "reconfiguration_type") + {400,"State: Bad Request. Return Body: Invalid PUT Reconfigure Body: key 'reconfiguration_type' is missing"} = httpabs:put(?XER, ?SC([?PLG(broker_app_url,C), "/reconfigure"]), "application/json", jiffy:encode({[{<<"config">>, <<"bar">>}]})), + + %test reconfiguring with an invalid PUT body (missing app_config) + {400,"State: Bad Request. Return Body: Invalid PUT Reconfigure Body: key 'config' is missing"} = httpabs:put(?XER, ?SC([?PLG(broker_app_url,C), "/reconfigure"]), "application/json", jiffy:encode({[{<<"reconfiguration_type">>, <<"program-flowlet-app-config">>}, {<<"foo">>, <<"bar">>}]})), + + %test reconfiguring an invalid (unimplemented) type + {501, "State: Not Implemented. Return Body: This type (EMPTINESS) of reconfiguration is not implemented"} = httpabs:put(?XER, ?SC([?PLG(broker_app_url,C), "/reconfigure"]), "application/json", jiffy:encode({[{<<"config">>, <<"bar">>}, {<<"reconfiguration_type">>, <<"EMPTINESS">>}]})) + . + +delete_all(C) -> + %test invalid key + Body1 = jiffy:encode({[{<<"ids">>, [<<"hwtest">>]}]}), + {400,"State: Bad Request. Return Body: Invalid PUT Body"} = httpabs:post(?XER, ?SC([?PLG(broker_url, C), "/application/delete"]), "application/json", Body1), + %test invalid: not a list + Body2 = jiffy:encode({[{<<"appnames">>, <<"hwtest">>}]}), + {400,"State: Bad Request. Return Body: Invalid PUT Body"} = httpabs:post(?XER, ?SC([?PLG(broker_url, C), "/application/delete"]), "application/json", Body2), + %test undeploy a real app and also an app that is not deployed + Body3 = jiffy:encode({[{<<"appnames">>, [<<"hwtest">>, <<"dissapointment">>]}]}), + {200, "[200,404]"} = httpabs:post(?XER, ?SC([?PLG(broker_url, C), "/application/delete"]), "application/json", Body3), + %teardown the fake service and make sure it is gone + {200, Srv} = setup_fake_testing_service(C, teardown), + true = Srv == "[]". + -- 2.16.6