├── my_object_0 ├── my_example_consumer ├── Dockerfile ├── my_example_consumer.sh ├── Makefile └── service.json ├── Dockerfile ├── pattern.json ├── watch.sh ├── service.json ├── LICENSE ├── .gitignore ├── README.md ├── helper ├── mms_helper.py └── Makefile /my_object_0: -------------------------------------------------------------------------------- 1 | Hello, world. 2 | -------------------------------------------------------------------------------- /my_example_consumer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | COPY *.sh / 4 | WORKDIR / 5 | CMD /my_example_consumer.sh 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt update && apt install -y python3 python3-pip curl 4 | 5 | COPY ./mms_helper.py / 6 | WORKDIR / 7 | 8 | CMD ["python3", "-u", "mms_helper.py"] 9 | 10 | -------------------------------------------------------------------------------- /my_example_consumer/my_example_consumer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Example MMS user..." 4 | while true; do 5 | echo "Files in /shared_dir:" 6 | ls -al /shared_dir 7 | sleep 3 8 | done 9 | 10 | -------------------------------------------------------------------------------- /pattern.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "$PATTERN_NAME", 3 | "services": [ 4 | { 5 | "serviceUrl": "$SERVICE_NAME", 6 | "serviceOrgid": "$HZN_ORG_ID", 7 | "serviceArch": "$ARCH", 8 | "serviceVersions": [ { "version": "$SERVICE_VERSION" } ] 9 | } 10 | ] 11 | } 12 | 13 | -------------------------------------------------------------------------------- /my_example_consumer/Makefile: -------------------------------------------------------------------------------- 1 | all: build publish-service 2 | 3 | DOCKERHUB_ID:=ibmosquito 4 | 5 | build: 6 | docker build -t $(DOCKERHUB_ID)/my_example_consumer:1.0.0 . 7 | 8 | dev: 9 | docker run -it $(DOCKERHUB_ID)/my_example_consumer:1.0.0 /bin/sh 10 | 11 | push: 12 | docker push $(DOCKERHUB_ID)/my_example_consumer:1.0.0 13 | 14 | publish-service: 15 | hzn exchange service publish -O -f service.json 16 | 17 | -------------------------------------------------------------------------------- /my_example_consumer/service.json: -------------------------------------------------------------------------------- 1 | { 2 | "org": "$HZN_ORG_ID", 3 | "label": "", 4 | "url": "my_example_consumer", 5 | "version": "1.0.0", 6 | "arch": "amd64", 7 | "public": false, 8 | "sharable": "singleton", 9 | "requiredServices": [], 10 | "userInput": [], 11 | "deployment": { 12 | "services": { 13 | "my_example_consumer": { 14 | "image": "ibmosquito/my_example_consumer:1.0.0", 15 | "binds": ["my_mms_helper_shared_volume:/shared_dir:rw"] 16 | } 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /watch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while true; do 4 | clear 5 | whazzup=`docker ps | grep my_example_consumer | wc -l` 6 | if [[ "1" == "$whazzup" ]]; then 7 | container=`docker ps | grep my_example_consumer | awk '{print $1;}'` 8 | echo "my_example_consumer is running with container id $container" 9 | count=`docker exec -it "$container" ls -al /shared_dir | wc -l` 10 | if [[ "3" == "$count" ]]; then 11 | echo "(no files)" 12 | else 13 | files=`docker exec -it "$container" ls -al /shared_dir` 14 | echo "Shared volume (/shared_dir) contents inside this container:" 15 | echo "$files" 16 | contents=`docker exec -it "$container" cat /shared_dir/my_object_0` 17 | echo "$contents" 18 | exit 0 19 | fi 20 | fi 21 | sleep 2 22 | done 23 | 24 | -------------------------------------------------------------------------------- /service.json: -------------------------------------------------------------------------------- 1 | { 2 | "org": "$HZN_ORG_ID", 3 | "label": "$SERVICE_NAME for $ARCH", 4 | "url": "$SERVICE_NAME", 5 | "version": "$SERVICE_VERSION", 6 | "arch": "$ARCH", 7 | "public": true, 8 | "sharable": "singleton", 9 | "requiredServices": [ 10 | { 11 | "org": "$HZN_ORG_ID", 12 | "url": "$YOUR_SERVICE_NAME", 13 | "version": "$YOUR_SERVICE_VERSION", 14 | "arch": "$ARCH" 15 | } 16 | ], 17 | "userInput": [ 18 | { "name": "MMS_HELPER_OBJECT_TYPE", "label": "", "type": "string", "defaultValue": "$YOUR_OBJECT_TYPE" }, 19 | { "name": "MMS_HELPER_VOLUME_MOUNT", "label": "", "type": "string", "defaultValue": "/shared_dir" } 20 | ], 21 | "deployment": { 22 | "services": { 23 | "$SERVICE_NAME": { 24 | "image": "$SERVICE_CONTAINER", 25 | "binds": ["$MMS_HELPER_SHARED_VOLUME:/shared_dir:rw"] 26 | } 27 | } 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Glen Darling 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MMS_Helper 2 | 3 | This project is glue code that I use for the Open Horizon Model Management System (MMS). I wrote this because I have difficulty following the [official Open Horizon documentation](https://github.com/open-horizon/examples/tree/master/edge/services/helloMMS) for the MMS. I hope you will find this helpful too, but if you run into troubles please go to the official documentation and follow the procedures there. 4 | 5 | NOTE: Only amd64 (x86/64) and arm64 architectures are currently supported, but it should be easy to build this for arrm32 too (I just haven't had a reason to try on a little machine like that, yet). 6 | 7 | 1. Begin by installing the Open-Horizon Agent, and configuring your creds: 8 | 9 | ``` bash 10 | $ agent-install.sh 11 | $ export HZN_ORG_ID=... 12 | $ export HZN_EXCHANGE_USER_AUTH=... 13 | $ hzn key create ... 14 | ``` 15 | 16 | 2. Edit the Makefile variables below as described: 17 | 18 | `YOUR_SERVICE_NAME` - the name of your dependent MMS consuming Service 19 | 20 | `YOUR_SERVICE_VERSION` - the version of your dependent MMS consuming Service 21 | 22 | `MMS_HELPER_SHARED_VOLUME` - a Docker volume for these conainers to share. 23 | 24 | Note that if you use a host **directory** here instead of a **volume name**, 25 | then you need to ensure the directory is writeable by the contaiiner 26 | processes (which run under a different user ID). 27 | 28 | Note also that you need to mount this in your consuming Service, e.g., in 29 | you Service defiinition's **deployment string**, use something to the binding 30 | shown below. Please see the [deployment string documentation](https://github.com/open-horizon/anax/blob/master/docs/deployment_string.md) for more details. 31 | 32 | ``` bash 33 | "binds": ["$MMS_HELPER_SHARED_VOLUME:/CONTAINER_DIR:ro"] 34 | ``` 35 | 36 | `YOUR_OBJECT_TYPE` - the object type name for MMS_Helper to monitor 37 | 38 | `YOUR_DOCKERHUB_ID` - your DockerHub account name for image "push" commands 39 | Note: you need to `docker login` to this before pushing or publishing 40 | 41 | 3. Build, push and publish this "mms-helper" service: 42 | 43 | ``` bash 44 | $ make build 45 | $ docker login -u ... 46 | $ make push 47 | $ make publish-service 48 | ``` 49 | 50 | 4. Publish a pattern or business policy to deploy this Service. E.g.: 51 | 52 | ``` bash 53 | $ make publish-pattern 54 | ``` 55 | 56 | 5. Register your edge nodes using a pattern or node policy, e.g.: 57 | 58 | ``` bash 59 | $ make register-pattern 60 | ``` 61 | 62 | 6. Start using the `hzn mms object publish` command to publish objects of the specified `YOUR_OBJECT_TYPE`. They will show up up in your `/CONTAINER_DIR` within your container, named using the object IDs you published them with, If you used the pattern above, and set the `OPTIONAL_...` variables, then you can use the command below to send the example file object to your dependendency Service running on every node registered with the example pattern: 63 | 64 | ``` bash 65 | $ make publish-object 66 | ``` 67 | -------------------------------------------------------------------------------- /helper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # A helper script to simplify the collection of a few host-specific items... 4 | # 5 | # ./helper -a 6 | # - returns the appropriate hardware architecture for use with open-horizon 7 | # ./helper -g 8 | # - returns the IP address of the first default gateway for this host 9 | # ./helper -i 10 | # - returns an IP address on the first default interface for this host 11 | # ./helper -n 12 | # - returns a name for this node (typiically `hostname`) 13 | # ./helper -z 14 | # - returns all of the above (really just for development convenience) 15 | # 16 | 17 | DEBUG=0 18 | if [ ${DEBUG} -gt 0 ]; then echo "DEBUG is on."; fi 19 | 20 | 21 | # Return the Horizon architecture string for this platform 22 | show_architecture () { 23 | if [ ${DEBUG} -gt 0 ]; then echo "Architecture."; fi 24 | RAW_ARCH=$(uname -m) 25 | if [[ "$RAW_ARCH" == "x86_64" ]]; then 26 | ARCH=amd64 27 | elif [[ "$RAW_ARCH" == "i386" ]]; then 28 | ARCH=amd64 29 | elif [[ "$RAW_ARCH" == "aarch64" ]]; then 30 | ARCH=arm64 31 | elif [[ "$RAW_ARCH" == "arm"* ]]; then 32 | ARCH=arm 33 | else 34 | # Other. Fail! 35 | ARCH=error 36 | fi 37 | echo "${ARCH}" 38 | } 39 | 40 | # Return the default gateway address for this host 41 | show_gateway () { 42 | if [ ${DEBUG} -gt 0 ]; then echo "Gateway Address."; fi 43 | if [[ "$OSTYPE" == "linux-"* ]]; then 44 | # Linux 45 | GATEWAY=$(ip route | grep default | head -1 | cut -d' ' -f3) 46 | elif [[ "$OSTYPE" == "darwin"* ]]; then 47 | # MacOSX 48 | GATEWAY=$(netstat -nr | grep default | head -1 | awk '{print$2}') 49 | else 50 | # Other. Best guess: 51 | GATEWAY=$(ip route | grep default | head -1 | cut -d' ' -f3) 52 | fi 53 | echo "${GATEWAY}" 54 | } 55 | 56 | # Return the default interface's IP address for this host 57 | show_ip () { 58 | if [ ${DEBUG} -gt 0 ]; then echo "IP Address."; fi 59 | if [[ "$OSTYPE" == "linux-"* ]]; then 60 | # Linux 61 | CIDR=$(ip route | grep default | head -1 | sed 's/ proto dhcp / /' | cut -d' ' -f3 | cut -d'.' -f1-3)'.0/24' 62 | if [ ${DEBUG} -gt 0 ]; then echo "CIDR=${CIDR}"; fi 63 | HOST_IP=$(ip route | grep "${CIDR}" | head -1 | sed 's/ proto [a-z]*//' | cut -d' ' -f7) 64 | elif [[ "$OSTYPE" == "darwin"* ]]; then 65 | # MacOSX 66 | HOST_IP=$(host `hostname` | head -1 | sed 's/.* //') 67 | else 68 | # Other. Best guess: 69 | CIDR=$(ip route | grep default | head -1 | sed 's/ proto dhcp / /' | cut -d' ' -f3 | cut -d'.' -f1-3)'.0/24' 70 | if [ ${DEBUG} -gt 0 ]; then echo "CIDR=${CIDR}"; fi 71 | HOST_IP=$(ip route | grep "${CIDR}" | head -1 | sed 's/ proto [a-z]*//' | cut -d' ' -f7) 72 | fi 73 | echo "${HOST_IP}" 74 | } 75 | 76 | # Return a name for this node 77 | show_name () { 78 | if [ ${DEBUG} -gt 0 ]; then echo "Name."; fi 79 | NAME=`hostname` 80 | echo "${NAME}" 81 | } 82 | 83 | while getopts ":aginz" opt; do 84 | case ${opt} in 85 | a ) 86 | show_architecture; 87 | exit 0; 88 | ;; 89 | g ) 90 | show_gateway; 91 | exit 0; 92 | ;; 93 | i ) 94 | show_ip; 95 | exit 0; 96 | ;; 97 | n ) 98 | show_name; 99 | exit 0; 100 | ;; 101 | z ) 102 | echo -n "Horizon Architecture: "; 103 | show_architecture; 104 | echo -n "Gateway: "; 105 | show_gateway; 106 | echo -n "IP Address: "; 107 | show_ip; 108 | exit 0; 109 | ;; 110 | \? ) echo "Usage: $0 [-a|-g|-i|-z]" 111 | ;; 112 | esac 113 | done 114 | 115 | 116 | -------------------------------------------------------------------------------- /mms_helper.py: -------------------------------------------------------------------------------- 1 | # 2 | # MMS Helper 3 | # 4 | # Written by Glen Darling, October 2020. 5 | # 6 | 7 | import json 8 | import os 9 | import subprocess 10 | import threading 11 | import time 12 | import base64 13 | 14 | # Configuration from the process environment 15 | def get_from_env(v, d): 16 | if v in os.environ and '' != os.environ[v]: 17 | return os.environ[v] 18 | else: 19 | return d 20 | HZN_ESS_AUTH = get_from_env('HZN_ESS_AUTH', '/ess-auth/auth.json') 21 | HZN_ESS_CERT = get_from_env('HZN_ESS_CERT', '/ess-auth/cert.pem') 22 | HZN_ESS_API_ADDRESS = get_from_env('HZN_ESS_API_ADDRESS', '/var/run/horizon/essapi.sock') 23 | MMS_HELPER_VOLUME_MOUNT = get_from_env('MMS_HELPER_VOLUME_MOUNT', '/shared_dir') 24 | MMS_HELPER_OBJECT_TYPE = get_from_env('MMS_HELPER_OBJECT_TYPE', 'unknown') 25 | 26 | # Load the ESS credentials (user/token) 27 | with open(HZN_ESS_AUTH) as creds_file: 28 | creds = json.load(creds_file) 29 | HZN_ESS_USER = creds['id'] 30 | HZN_ESS_TOKEN = creds['token'] 31 | 32 | # Cheap debug 33 | DEBUG = False 34 | def debug(s): 35 | if DEBUG: 36 | print(s) 37 | 38 | # Cheap logging 39 | INFO = False 40 | WARNING = True 41 | ERROR = True 42 | def log(t, s): 43 | if (INFO and t == 'info') or (WARNING and t == 'WARNING') or (ERROR and t == 'ERROR'): 44 | print("%s: %s" % (t, s)) 45 | 46 | def main(): 47 | LOOP_DELAY_SEC = 3 48 | debug('\nMonitoring ESS...') 49 | debug(' user=%s' % HZN_ESS_USER) 50 | debug(' token=%s' % HZN_ESS_TOKEN) 51 | debug(' cacert=%s' % HZN_ESS_CERT) 52 | debug(' socket=%s' % HZN_ESS_API_ADDRESS) 53 | debug(' object_type=%s' % MMS_HELPER_OBJECT_TYPE) 54 | debug(' shared_dir=%s' % MMS_HELPER_VOLUME_MOUNT) 55 | 56 | ESS_OBJECT_LIST_BASE = 'curl -sSL -u %s:%s --cacert %s --unix-socket %s https://localhost/api/v1/objects/%s' 57 | ESS_REDIRECT_BASE = 'curl -sSL -u %s:%s --cacert %s --unix-socket %s https://localhost/api/v1/objects/%s/%s/data -o %s/%s' 58 | ESS_MARK_RECEIVED_BASE = 'curl -sSL -X PUT -u %s:%s --cacert %s --unix-socket %s https://localhost/api/v1/objects/%s/%s/received' 59 | while True: 60 | get_objects = ESS_OBJECT_LIST_BASE % (HZN_ESS_USER, HZN_ESS_TOKEN, HZN_ESS_CERT, HZN_ESS_API_ADDRESS, MMS_HELPER_OBJECT_TYPE) 61 | try: 62 | raw = subprocess.check_output(get_objects, shell=True) 63 | output = raw.decode("utf-8") 64 | debug('\n\nReceived from ESS:\n') 65 | debug(output) 66 | j = json.loads(output) 67 | id = j[-1]['objectID'] 68 | deleted = j[-1]['deleted'] 69 | if not deleted: 70 | tempfile = '.' + id 71 | redirect_command = ESS_REDIRECT_BASE % (HZN_ESS_USER, HZN_ESS_TOKEN, HZN_ESS_CERT, HZN_ESS_API_ADDRESS, MMS_HELPER_OBJECT_TYPE, id, MMS_HELPER_VOLUME_MOUNT, tempfile) 72 | try: 73 | subprocess.run(redirect_command, shell=True, check=True) 74 | debug('ESS object file copy was successful.') 75 | try: 76 | rename_command = '/bin/mv %s/%s %s/%s' % (MMS_HELPER_VOLUME_MOUNT, tempfile, MMS_HELPER_VOLUME_MOUNT, id) 77 | subprocess.run(rename_command, shell=True, check=True) 78 | debug('File rename was successful.') 79 | mark_received_command = ESS_MARK_RECEIVED_BASE % (HZN_ESS_USER, HZN_ESS_TOKEN, HZN_ESS_CERT, HZN_ESS_API_ADDRESS, MMS_HELPER_OBJECT_TYPE, id) 80 | try: 81 | log("info", mark_received_command) 82 | subprocess.run(mark_received_command, shell=True, check=True) 83 | debug('ESS object received command was successful.') 84 | except: 85 | log("ERROR", mark_received_command) 86 | except: 87 | log("ERROR", rename_command) 88 | except: 89 | log("ERROR", redirect_command) 90 | except: 91 | log("info", get_objects) 92 | debug('Sleeping for ' + str(LOOP_DELAY_SEC) + ' seconds...') 93 | time.sleep(LOOP_DELAY_SEC) 94 | 95 | if __name__ == '__main__': 96 | main() 97 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # MMS_Helper a quick and easy way to use the Open-Horizon MMS feature 2 | # 3 | # 1. Begin by installing the Open-Horizon Agent, and configuring your creds: 4 | # $ agent-install.sh 5 | # $ export HZN_ORG_ID=... 6 | # $ export HZN_EXCHANGE_USER_AUTH=... 7 | # 8 | # 2. Edit the Makefile variables below as described: 9 | # YOUR_SERVICE_NAME - the name of your dependent MMS consuming Service 10 | # YOUR_SERVICE_VERSION - the version of your dependent MMS consuming Service 11 | # MMS_HELPER_SHARED_VOLUME - a Docker volume for these conainers to share. 12 | # Note: you need to mount this in your consuming Service, e.g., in your 13 | # Service defiinition's deployment string, use something like this: 14 | # "binds": ["$MMS_HELPER_SHARED_VOLUME:/CONTAINER_DIR:ro"] 15 | # Note also that if you use a host directory here instead of a volume name, 16 | # then you need to ensure the directory is writeable by the contaiiner 17 | # processes (which run under a different user ID). 18 | # YOUR_OBJECT_TYPE - the object type name for MMS_Helper to monitor 19 | # YOUR_DOCKERHUB_ID - your DockerHub account name for image "push" commands 20 | # Note: you need to `docker login` to this before pushing or publishing 21 | # 22 | # 3. Build, push and publish this "mms-helper" service: 23 | # $ make build 24 | # $ docker login -u ... 25 | # $ make push 26 | # $ make publish-service 27 | # 28 | # 4. Publish a pattern or business policy to deploy this Service. E.g.: 29 | # $ make publish-pattern 30 | # 31 | # 5. Register your edge nodes using a pattern or node policy, e.g.: 32 | # $ make register-pattern 33 | # 34 | # 6. Start using the `hzn mms object publish` command to publish objects of 35 | # the specified YOUR_OBJECT_TYPE. They will show up up in your /CONTAINER_DIR 36 | # within your container, named using the object IDs you published them with, 37 | # If you used the pattern above, and set the OPTIONAL variables, then: 38 | # $ make publish-object 39 | # to send the example file object to your dependendency Service running on 40 | # every node registered with the example pattern. 41 | 42 | # Please edit these appropriately (as described above) 43 | YOUR_SERVICE_NAME:=my_example_consumer 44 | YOUR_SERVICE_VERSION:=1.0.0 45 | MMS_HELPER_SHARED_VOLUME:=my_mms_helper_shared_volume 46 | YOUR_OBJECT_TYPE:=my_object_type 47 | YOUR_DOCKERHUB_ID:=ibmosquito 48 | 49 | # Optionally specify an example file to send as an MMS object. If you do so, 50 | # a file named with the path in OPTIONAL_OBJECT_FILE must be present. 51 | OPTIONAL_OBJECT_ID:=my_object_0 52 | OPTIONAL_OBJECT_FILE:=my_object_0 53 | 54 | # The "helper" utility is useful for things like this so I included it. 55 | ARCH:=`./helper -a` 56 | 57 | # Variables for MMS_Helper container/service/pattern (optionally edit these) 58 | # Note that service and container may have differen names and versions. 59 | MMS_HELPER_SERVICE_NAME:=mms-helper 60 | MMS_HELPER_SERVICE_VERSION:=1.0.0 61 | MMS_HELPER_CONTAINER:=$(YOUR_DOCKERHUB_ID)/mms-helper_$(ARCH):1.0.0 62 | # For DockerHub, leave the variable below as it is (empty). 63 | # For secure registries set it using: -r "registry.wherever.com:myid:mypw"` 64 | MMS_HELPER_CONTAINER_CREDS:= 65 | MMS_HELPER_PATTERN_NAME:=mms-helper-pattern 66 | 67 | build: Makefile Dockerfile mms_helper.py 68 | docker build -t $(MMS_HELPER_CONTAINER) . 69 | 70 | dev: 71 | docker run -it -v `pwd`:/outside -v $(MMS_HELPER_SHARED_VOLUME):/shared_dir:rw $(MMS_HELPER_CONTAINER) bin/bash 72 | 73 | push: 74 | docker push $(MMS_HELPER_CONTAINER) 75 | 76 | publish-service: validate-creds 77 | @ARCH=$(ARCH) \ 78 | SERVICE_NAME="$(MMS_HELPER_SERVICE_NAME)" \ 79 | SERVICE_VERSION="$(MMS_HELPER_SERVICE_VERSION)"\ 80 | SERVICE_CONTAINER="$(MMS_HELPER_CONTAINER)" \ 81 | YOUR_SERVICE_NAME="$(YOUR_SERVICE_NAME)" \ 82 | YOUR_SERVICE_VERSION="$(YOUR_SERVICE_VERSION)"\ 83 | YOUR_OBJECT_TYPE="$(YOUR_OBJECT_TYPE)"\ 84 | MMS_HELPER_SHARED_VOLUME="$(MMS_HELPER_SHARED_VOLUME)"\ 85 | hzn exchange service publish -O $(MMS_HELPER_CONTAINER_CREDS) -f service.json 86 | 87 | publish-pattern: 88 | @ARCH=$(ARCH) \ 89 | SERVICE_NAME="$(MMS_HELPER_SERVICE_NAME)" \ 90 | SERVICE_VERSION="$(MMS_HELPER_SERVICE_VERSION)"\ 91 | PATTERN_NAME="$(MMS_HELPER_PATTERN_NAME)" \ 92 | hzn exchange pattern publish -f pattern.json 93 | 94 | register-pattern: 95 | hzn register --pattern "$(MMS_HELPER_PATTERN_NAME)" 96 | 97 | publish-object: 98 | hzn mms object publish --type=$(YOUR_OBJECT_TYPE) --id=$(OPTIONAL_OBJECT_ID) --object=$(OPTIONAL_OBJECT_FILE) --pattern=$(MMS_HELPER_PATTERN_NAME) 99 | 100 | validate-creds: 101 | @if [ -z "${HZN_ORG_ID}" ]; \ 102 | then { echo "***** ERROR: \"HZN_ORG_ID\" is not set!"; exit 1; }; \ 103 | else echo "Using Exchange Org ID: \"${HZN_ORG_ID}\""; \ 104 | fi 105 | @if [ -z "${HZN_EXCHANGE_USER_AUTH}" ]; \ 106 | then { echo "***** ERROR: \"EXCHANGE_USER_AUTH\" is not set!"; exit 1; }; \ 107 | else echo "Using Exchange user creds: \"${EXCHANGE_USER_AUTH}\""; \ 108 | fi 109 | @sleep 1 110 | 111 | clean: 112 | -hzn unregister -f 113 | -hzn exchange service remove -f "${HZN_ORG_ID}/$(MMS_HELPER_SERVICE_NAME)_$(MMS_HELPER_SERVICE_VERSION)_$(ARCH)" 114 | -docker rmi -f "$(MMS_HELPER_CONTAINER)" 115 | 116 | .PHONY: build dev push publish-service publish-pattern publish-object validate-creds clean 117 | --------------------------------------------------------------------------------