├── .gitignore ├── HOST.md ├── LICENSE ├── NOTES.md ├── README.md ├── config └── .gitignore ├── haproxy └── haproxy.cfg ├── manifest.json ├── resources-docker-compose.yml ├── services-docker-compose.yml ├── sphere-stack.sh ├── templates ├── activation.sh ├── apiservice.sh ├── douitsu.sh ├── modelservice.sh ├── mqttproxy.sh ├── rpcservice.sh ├── spherecouch.sh ├── spherehaproxy.sh ├── spheremysql.sh ├── sphererabbit.sh ├── sphereredis.sh └── stateservice.sh └── test_data.sql /.gitignore: -------------------------------------------------------------------------------- 1 | haproxy/ssl 2 | .sphere-stack 3 | data/ 4 | -------------------------------------------------------------------------------- /HOST.md: -------------------------------------------------------------------------------- 1 | # host 2 | 3 | This describes the setup of a host which runs the sphere stack. 4 | 5 | # system requirements 6 | 7 | This platform should run OK for a few spheres using a `2gb` (2g ram/2 cpu/40g disk) digital ocean server. 8 | 9 | # ufw 10 | 11 | ``` 12 | sudo ufw allow ssh 13 | sudo ufw allow http 14 | sudo ufw allow https 15 | sudo ufw allow 8883/tcp 16 | sudo ufw allow 2376/tcp 17 | sudo ufw enable 18 | ``` 19 | 20 | Note: `2376/tcp` is used by docker-machine to access docker over ssl. 21 | 22 | To see the status. 23 | 24 | ``` 25 | sudo ufw status 26 | ``` 27 | 28 | For more information: 29 | 30 | * [How To Setup a Firewall with UFW on an Ubuntu and Debian Cloud Server](https://www.digitalocean.com/community/tutorials/how-to-setup-a-firewall-with-ufw-on-an-ubuntu-and-debian-cloud-server) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Ninja Blocks Inc. 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. -------------------------------------------------------------------------------- /NOTES.md: -------------------------------------------------------------------------------- 1 | # This we need to automate. 2 | 3 | * Import the initial test_data.sql 4 | * Add users to rabbitmq 5 | * Enable the mqtt plugin in rabbitmq 6 | 7 | # mysql 8 | 9 | * Restore the databases. 10 | 11 | ``` 12 | cat test_data.sql | docker exec -i spherestack_spheremysql_1 mysql -uroot 13 | ``` 14 | 15 | # couchdb 16 | 17 | curl -X PUT http://crusty.local:5984/sphere_modelstore/_design/manifest -d @manifest.json 18 | 19 | http://IPOFDOCKERHOST:5984/_utils/database.html?sphere_modelstore/_all_docs 20 | 21 | # rabbitmq 22 | 23 | http://IPOFDOCKERHOST:15672/#/ 24 | 25 | # developing 26 | 27 | Add these to your `/etc/hosts' file, where IPOFDOCKERHOST is the ip address of the machine hosting your docker containers. 28 | 29 | ``` 30 | IPOFDOCKERHOST doiutsu 31 | IPOFDOCKERHOST apiservice 32 | ``` 33 | 34 | # douitsu 35 | 36 | * Register your first user in douitsu, this will be used to setup the oauth2 applications. 37 | 38 | * Add an application for the sphere API service. 39 | 40 | * Enable some flags for the api service application. 41 | 42 | ``` 43 | update application set is_ninja_official=1 where id = '35573a18-7f12-47c2-89f7-a82d6087a144'; 44 | ``` 45 | 46 | # openssl 47 | 48 | ``` 49 | openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout haproxy/ssl/sphere.key -out haproxy/ssl/sphere.crt 50 | ``` 51 | 52 | When you hit "ENTER", you will be asked a number of questions. 53 | 54 | ``` 55 | Country Name (2 letter code) [AU]:US 56 | State or Province Name (full name) [Some-State]:New York 57 | Locality Name (eg, city) []:New York City 58 | Organization Name (eg, company) [Internet Widgits Pty Ltd]:Your Company 59 | Organizational Unit Name (eg, section) []:Department of Kittens 60 | Common Name (e.g. server FQDN or YOUR name) []:*.your_domain.com 61 | Email Address []:your_email@domain.com 62 | ``` 63 | Combine these files. 64 | 65 | ``` 66 | cat haproxy/ssl/sphere.key haproxy/ssl/sphere.crt >> haproxy/ssl/wildcard.pem 67 | ``` 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sphere-stack 2 | 3 | This setup is used to launch a standalone copy of the sphere platform either on your local machine or on a cloud host. 4 | 5 | # prerequisites 6 | 7 | To start you need a host running ubuntu 16.04 with docker installed 8 | 9 | * [docker](https://www.docker.com/) 10 | * [docker-compose](https://docs.docker.com/compose/) 11 | 12 | # overview 13 | 14 | I have broken the system up into two compose configuration files, being resources and services. 15 | 16 | ## resources 17 | 18 | This are the resource services, consisting of mysql, rabbitmq, couchdb and redis. 19 | 20 | These services keep their data in the following folders on the docker host: 21 | 22 | * `./data/couchdb` 23 | * `./data/mysql` 24 | * `./data/rabbitmq` 25 | 26 | ## services 27 | 28 | These are the services which ninjablocks developed. 29 | 30 | * [douitsu](https://github.com/ninjablocks/douitsu) 31 | * [activation](https://github.com/ninjablocks/sphere-activation-service) 32 | * [apiservice](https://github.com/ninjablocks/sphere-api-service) 33 | * [rpcservice](https://github.com/ninjablocks/sphere-cloud-rpc-service) 34 | * [modelservice](https://github.com/ninjablocks/sphere-cloud-modelstore-service) 35 | * [sphere-go-state-service](https://github.com/ninjablocks/sphere-go-state-service) 36 | * [mqtt-proxy](https://github.com/ninjablocks/mqtt-proxy) 37 | 38 | # configuring 39 | 40 | First, create a default configuration. This step will generate some unique keys. 41 | 42 | ``` 43 | ./sphere-stack.sh init 44 | ``` 45 | 46 | Review the configuration at any time with: 47 | 48 | ``` 49 | ./sphere-stack.sh edit 50 | ``` 51 | 52 | Now create the docker container (the so-called 'resources composition') that will contain the resource services. 53 | 54 | ``` 55 | ./sphere-stack.sh create resources 56 | ``` 57 | 58 | ## databases 59 | 60 | Then if this is the first time you have run it you need to import the SQL database. 61 | 62 | ``` 63 | ./sphere-stack.sh create mysql 64 | ``` 65 | 66 | Then ensure the couchdb database is created and create the secondary index. 67 | 68 | ``` 69 | ./sphere-stack.sh create couch 70 | ``` 71 | 72 | ## openssl 73 | 74 | ``` 75 | ./sphere-stack.sh create keys 76 | ``` 77 | 78 | When you hit "ENTER", you will be asked a number of questions. 79 | 80 | ``` 81 | Country Name (2 letter code) [AU]:US 82 | State or Province Name (full name) [Some-State]:New York 83 | Locality Name (eg, city) []:New York City 84 | Organization Name (eg, company) [Internet Widgits Pty Ltd]:Your Company 85 | Organizational Unit Name (eg, section) []:Department of Kittens 86 | Common Name (e.g. server FQDN or YOUR name) []:*.example.com 87 | Email Address []:your_email@domain.com 88 | ``` 89 | 90 | ## services 91 | 92 | Then start the services. 93 | 94 | ``` 95 | ./sphere-stack.sh start services 96 | ``` 97 | 98 | ## IP address 99 | 100 | To learn the IP address of your docker-machine, run: 101 | 102 | ``` 103 | ./sphere-stack.sh ip 104 | ``` 105 | 106 | ## host file 107 | 108 | Add an entry like the following to your local hosts /etc/hosts file: 109 | 110 | ``` 111 | 192.168.99.100 id.example.com api.example.com mqtt.example.com 112 | ``` 113 | 114 | You can generate the correct entry with: 115 | 116 | ``` 117 | ./sphere-stack.sh hosts-append 118 | ``` 119 | 120 | ## douitsu 121 | 122 | * Register your first user in douitsu (https://id.example.com), this will be used to setup the oauth2 applications. 123 | 124 | * You will probably find things easier if you choose trust to the self-signed certificate using the mechanisms provided by your browser &/or host operating systems. 125 | 126 | * Add an application for the sphere API service. 127 | 128 | * "Something that users will trust" - "Private Ninja Cloud" 129 | * "The full URL to your application homepage." - https://api.example.com 130 | * "Your application’s callback URL; Read our OAuth documentation for more info." - https://api.example.com/auth/ninja/callback 131 | * "This text is displayed to all potential users of your application." - "This is a private Ninja Cloud" 132 | 133 | After saving, take note of the "Client ID" and "Secret" under the "Application Details" title. 134 | 135 | * Update the NINJA_APP_TOKEN and NINJA_APP_KEY variables with the values collected from the last step 136 | 137 | ``` 138 | ./sphere-stack.sh edit 139 | ``` 140 | 141 | * Enable some flags for the REST API service application 142 | 143 | ``` 144 | ./sphere-stack.sh update application-table 145 | ``` 146 | 147 | * Recreate the services composition 148 | 149 | ``` 150 | ./sphere-stack.sh recreate services 151 | ``` 152 | 153 | ## security 154 | 155 | On the VPS you only need to expose ports 80, 443 and 8883, the rest can be accessed using SSH port forwarding (See `HOST.md` for configuring the firewall). 156 | 157 | ``` 158 | ssh -D 3000 USERNAME@HOST 159 | ``` 160 | 161 | Then configure your browser as required to use this socks proxy using something like [switchysharp](https://chrome.google.com/webstore/detail/proxy-switchysharp/dpplabbmogkhghncfbfdeeokoefdjegm?hl=en). 162 | 163 | # Licensing 164 | 165 | sphere-stack is licensed under the MIT License. See LICENSE for the full license text. 166 | 167 | # Revisions 168 | 169 | ## 1.4 170 | * breaking: path of persisted files changed from `/var/lib/sphere-stack` to `./data` 171 | * change docker-compose files to v3 172 | 173 | ## 1.3 174 | * changed default endpoint names from 'apiservice' to 'api' and from 'douitsu' to 'id' 175 | 176 | ## 1.2 177 | * replace all configuration with environment files 178 | * generate all environment files from master configuration using shell templates 179 | * add support for init and edit commands 180 | 181 | ## 1.1 182 | * added 'sphere-stack.sh' to encapsulate scriplets used in instructions 183 | * ensured that resources used by resources-docker-compose.yml are located on persistent storage of the VM 184 | 185 | ## 1.0 186 | * Initial release 187 | -------------------------------------------------------------------------------- /config/.gitignore: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /haproxy/haproxy.cfg: -------------------------------------------------------------------------------- 1 | global 2 | log 127.0.0.1 local0 3 | log 127.0.0.1 local1 notice 4 | chroot /var/lib/haproxy 5 | user haproxy 6 | group haproxy 7 | # daemon 8 | 9 | defaults 10 | log global 11 | mode http 12 | option httplog 13 | option dontlognull 14 | timeout connect 5000ms 15 | timeout client 50000ms 16 | timeout server 50000ms 17 | errorfile 400 /etc/haproxy/errors/400.http 18 | errorfile 403 /etc/haproxy/errors/403.http 19 | errorfile 408 /etc/haproxy/errors/408.http 20 | errorfile 500 /etc/haproxy/errors/500.http 21 | errorfile 502 /etc/haproxy/errors/502.http 22 | errorfile 503 /etc/haproxy/errors/503.http 23 | errorfile 504 /etc/haproxy/errors/504.http 24 | 25 | frontend http-in 26 | bind :80 27 | redirect scheme https code 301 if !{ ssl_fc } 28 | 29 | frontend www-https 30 | bind :443 ssl crt /haproxy-override/ssl/wildcard.pem 31 | reqadd X-Forwarded-Proto:\ https 32 | use_backend douitsu-backend if { ssl_fc_sni_reg id\..* } 33 | use_backend apiservice-backend if { ssl_fc_sni_reg api\..* } 34 | 35 | frontend mqtts 36 | bind :8883 ssl crt /haproxy-override/ssl/wildcard.pem 37 | mode tcp 38 | default_backend mqttproxy-backend 39 | 40 | backend douitsu-backend 41 | server server1 douitsu:3333 maxconn 32 42 | 43 | backend apiservice-backend 44 | server server1 apiservice:5200 maxconn 32 45 | 46 | backend mqttproxy-backend 47 | mode tcp 48 | server server1 mqttproxy:6300 maxconn 32 -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "_id": "_design/manifest", 3 | "language": "javascript", 4 | "views": { 5 | "manifest": { 6 | "map": "function(doc) {\n if (doc.model) {\n emit([doc.user.id, doc.model.type], {\n last_modified: doc.last_modified,\n id: doc.model.id\n });\n emit([doc.user.id, doc.model.type, doc.model.id], null);\n }\n}" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /resources-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | # sphere-stack resources 4 | # 5 | # This is all the microservices which combine to make the sphere cloud resource services. 6 | # 7 | # NOTE: You will want to reconfigure all the passwords in here and the test_sql.sql file. 8 | # 9 | 10 | services: 11 | spheremysql: # douitsu, activation databases 12 | image: mariadb:10 13 | env_file: config/spheremysql 14 | ports: 15 | - "3306:3306" 16 | expose: 17 | - "3306" 18 | environment: 19 | - MYSQL_ALLOW_EMPTY_PASSWORD="true" 20 | - MYSQL_USER="ninja" 21 | - MYSQL_PASSWORD="ninja" 22 | volumes: 23 | - ./data/mysql:/var/lib/mysql 24 | 25 | spherecouch: # document store 26 | env_file: config/spherecouch 27 | image: couchdb:1 28 | ports: 29 | - "5984:5984" 30 | expose: 31 | - "5984" 32 | volumes: 33 | - ./data/couchdb:/usr/local/var/lib/couchdb 34 | 35 | sphererabbit: # message broker 36 | image: ninjablocks/rabbitmq 37 | env_file: config/sphererabbit 38 | volumes: 39 | - ./data/rabbitmq:/var/lib/rabbitmq 40 | ports: 41 | - "1883:1883" 42 | - "5672:5672" 43 | - "15672:15672" 44 | expose: 45 | - "1883" 46 | - "5672" 47 | - "15672" 48 | 49 | sphereredis: # cache 50 | env_file: config/sphereredis 51 | image: redis:3 52 | ports: 53 | - "6379:6379" 54 | expose: 55 | - "6379" 56 | -------------------------------------------------------------------------------- /services-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | # sphere-stack services 4 | # 5 | # This is all the microservices which combine to make the sphere cloud. 6 | # 7 | # NOTE: You will want to reconfigure all the passwords in here and the test_sql.sql file. 8 | # 9 | 10 | services: 11 | douitsu: # identity provider 12 | image: ninjasphere/douitsu:6b1d73e 13 | env_file: config/douitsu 14 | external_links: 15 | - spherestack_sphereredis_1:redis 16 | - spherestack_spheremysql_1:mysql 17 | ports: 18 | - "3333:3333" 19 | expose: 20 | - "3333" 21 | 22 | activation: # sphere activation service 23 | image: ninjasphere/sphere-activation-service:90c74a0 24 | env_file: config/activation 25 | external_links: 26 | - spherestack_sphereredis_1:redis 27 | - spherestack_spheremysql_1:mysql 28 | - spherestack_sphererabbit_1:rabbit 29 | ports: 30 | - "5100:5100" 31 | expose: 32 | - "5100" 33 | 34 | apiservice: # sphere rest api service 35 | image: ninjasphere/sphere-api-service:a13fb9f 36 | env_file: config/apiservice 37 | links: 38 | - activation:activation 39 | - douitsu:douitsu 40 | - modelservice:modelservice 41 | external_links: 42 | - spherestack_sphereredis_1:redis 43 | - spherestack_spheremysql_1:mysql 44 | - spherestack_sphererabbit_1:rabbit 45 | ports: 46 | - "5200:5200" 47 | expose: 48 | - "5200" 49 | 50 | rpcservice: # sphere rpc service 51 | image: ninjasphere/sphere-rpc-service:e4de51c 52 | env_file: config/rpcservice 53 | links: 54 | - modelservice:modelservice 55 | external_links: 56 | - spherestack_sphereredis_1:redis 57 | - spherestack_spheremysql_1:mysql 58 | - spherestack_sphererabbit_1:rabbit 59 | ports: 60 | - "5900:5900" 61 | expose: 62 | - "5900" 63 | 64 | modelservice: # sphere model store service 65 | image: ninjasphere/sphere-modelstore-service:2463a5e 66 | env_file: config/modelservice 67 | external_links: 68 | - spherestack_spherecouch_1:couchdb 69 | ports: 70 | - "5600:5600" 71 | expose: 72 | - "5600" 73 | 74 | stateservice: # sphere state service 75 | image: ninjasphere/sphere-state-service:2a2b68c 76 | env_file: config/stateservice 77 | external_links: 78 | - spherestack_sphereredis_1:redis 79 | - spherestack_sphererabbit_1:rabbit 80 | ports: 81 | - "6100:6100" 82 | expose: 83 | - "6100" 84 | 85 | mqttproxy: # sphere mqtt proxy 86 | image: ninjablocks/mqtt-proxy:e272ac0 87 | env_file: config/mqttproxy 88 | external_links: 89 | - spherestack_spheremysql_1:mysql 90 | - spherestack_sphererabbit_1:rabbit 91 | ports: 92 | - "6300:6300" 93 | expose: 94 | - "6300" 95 | 96 | spherehaproxy: # cache 97 | image: ninjablocks/haproxy:95d19f6 98 | env_file: config/spherehaproxy 99 | links: 100 | - apiservice:apiservice 101 | - douitsu:douitsu 102 | - mqttproxy:mqttproxy 103 | volumes: 104 | - ./haproxy:/haproxy-override 105 | ports: 106 | - "80:80" 107 | - "443:443" 108 | - "8883:8883" 109 | expose: 110 | - "80" 111 | - "443" 112 | - "8883" 113 | -------------------------------------------------------------------------------- /sphere-stack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | VERSION=1.4 4 | 5 | die() { 6 | echo "$*" 1>&2 7 | exit 1 8 | } 9 | 10 | version() { 11 | echo "$VERSION" 12 | } 13 | 14 | ip() { 15 | if test -n "$DOCKER_HOST"; then 16 | local ip=${DOCKER_HOST#tcp://}; 17 | echo ${ip%:*}; 18 | else 19 | echo "127.0.0.1" 20 | fi 21 | } 22 | 23 | domain() { 24 | echo ${NINJA_CLOUD_DOMAIN} 25 | } 26 | 27 | machine() { 28 | if test -n "$DOCKER_HOST"; then 29 | docker-machine ls | cut -c1-20 | grep "\*" | cut -f1 -d' ' 30 | else 31 | echo "" 32 | return 1 33 | fi 34 | } 35 | 36 | create() { 37 | 38 | config() { 39 | mkdir -p config 40 | chmod 0700 config 41 | cd templates 42 | for f in *.sh; do 43 | (. ./$f) > ../config/$(basename $f .sh) || die "died while running template $f" 44 | done 45 | cd .. 46 | } 47 | 48 | services() { 49 | docker-compose -p spherestack -f services-docker-compose.yml up -d 50 | } 51 | 52 | resources() { 53 | mkdir -p ./data || die "failed to create sphere-stack" 54 | docker-compose -p spherestack -f resources-docker-compose.yml up -d 55 | } 56 | 57 | couch() { 58 | docker exec -i spherestack_spherecouch_1 curl -X PUT http://127.0.0.1:5984/sphere_modelstore; 59 | curl -X PUT http://$(ip):5984/sphere_modelstore/_design/manifest -d @manifest.json 60 | } 61 | 62 | mysql() { 63 | cat test_data.sql | docker exec -i spherestack_spheremysql_1 mysql -uroot 64 | } 65 | 66 | keys() { 67 | mkdir -p haproxy/ssl && 68 | openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout haproxy/ssl/sphere.key -out haproxy/ssl/sphere.crt && 69 | cat haproxy/ssl/sphere.key haproxy/ssl/sphere.crt >> haproxy/ssl/wildcard.pem 70 | } 71 | 72 | "$@" 73 | } 74 | 75 | 76 | hosts-append() { 77 | local d=$(domain) || exit $? 78 | echo $(ip) \ 79 | ${NINJA_API_ENDPOINT} \ 80 | ${NINJA_ID_ENDPOINT} \ 81 | mqtt.$d \ 82 | "" 83 | } 84 | 85 | start() { 86 | resource=$1 87 | shift 1 88 | case "$resource" in 89 | resources) 90 | docker-compose -p spherestack -f resources-docker-compose.yml up -d 91 | ;; 92 | services) 93 | docker-compose -p spherestack -f services-docker-compose.yml up -d 94 | ;; 95 | *) 96 | die "unknown resource: $resource" 97 | ;; 98 | esac 99 | } 100 | 101 | recreate() { 102 | resource=$1 103 | shift 1 104 | case "$resource" in 105 | resources) 106 | docker-compose -p spherestack -f resources-docker-compose.yml stop 107 | docker-compose -p spherestack -f resources-docker-compose.yml rm 108 | docker-compose -p spherestack -f resources-docker-compose.yml up -d 109 | ;; 110 | services) 111 | docker-compose -p spherestack -f services-docker-compose.yml stop 112 | docker-compose -p spherestack -f services-docker-compose.yml rm -f 113 | docker-compose -p spherestack -f services-docker-compose.yml up -d 114 | ;; 115 | *) 116 | ;; 117 | esac 118 | } 119 | 120 | stop() { 121 | resource=$1 122 | shift 1 123 | case "$resource" in 124 | resources) 125 | docker-compose -p spherestack -f resources-docker-compose.yml stop 126 | ;; 127 | services) 128 | docker-compose -p spherestack -f services-docker-compose.yml stop 129 | ;; 130 | *) 131 | die "unknown resource: $resource" 132 | ;; 133 | esac 134 | } 135 | 136 | restart() { 137 | resource=$1 138 | shift 1 139 | (stop "$resource" "$@") 140 | start "$resource" "$@" 141 | } 142 | 143 | logs() { 144 | resource=$1 145 | shift 1 146 | case "$resource" in 147 | resources) 148 | docker-compose -p spherestack -f resources-docker-compose.yml logs 149 | ;; 150 | services) 151 | docker-compose -p spherestack -f services-docker-compose.yml logs 152 | ;; 153 | *) 154 | die "unknown resource: $resource" 155 | ;; 156 | esac 157 | } 158 | 159 | pwgen() { 160 | cat /dev/urandom | dd count=1 bs=256 2>/dev/null | openssl base64 | cut -c1-20 | head -1 161 | } 162 | 163 | edit() { 164 | ${EDITOR:-vi} .sphere-stack/master 165 | initenv 166 | create config 167 | } 168 | 169 | update() { 170 | application-table() { 171 | docker exec -i spherestack_spheremysql_1 mysql douitsu -uroot < .sphere-stack/defaults 199 | if ! test -f .sphere-stack/master; then 200 | generate master > .sphere-stack/master 201 | echo "./sphere-stack/master has been initialized" 202 | else 203 | echo "skipping initialization of .sphere-stack/master - existing tokens will be used" 204 | fi 205 | . .sphere-stack/defaults 206 | . .sphere-stack/master 207 | create config 208 | } 209 | 210 | usage() { 211 | cat <