diff --git a/packages/cosmic-swingset/Makefile b/packages/cosmic-swingset/Makefile index 20e633cbae8..90c8889ffbd 100644 --- a/packages/cosmic-swingset/Makefile +++ b/packages/cosmic-swingset/Makefile @@ -135,7 +135,7 @@ scenario3-run: cd t3 && ../bin/ag-solo start docker-pull: - for f in '' -pserver -setup -setup-solo -solo; do \ + for f in '' -setup -solo; do \ docker pull $(REPOSITORY)$$f:latest || exit $$?; \ done @@ -191,21 +191,6 @@ set-local-gci-ingress: ../../bin/ag-solo set-gci-ingress --chainID=$(CHAIN_ID) $$gci $$rpcport); \ done -install-pserver: - python3 -mvenv ve3 - ve3/bin/pip install -U setuptools wheel - ve3/bin/pip install --editable ./provisioning-server - -run-pserver: - ve3/bin/ag-pserver --listen tcp:8001 --controller tcp:localhost:8002 - -install-setup-client: - python3 -mvenv ve3-client - ve3-client/bin/pip install -U setuptools wheel - ve3-client/bin/pip install --editable ./setup-solo -run-setup-client: - ve3-client/bin/ag-setup-solo - ############################################################################### ### Protobuf ### ############################################################################### diff --git a/packages/cosmic-swingset/docker/ag-pserver b/packages/cosmic-swingset/docker/ag-pserver deleted file mode 100755 index 024022e32ab..00000000000 --- a/packages/cosmic-swingset/docker/ag-pserver +++ /dev/null @@ -1,16 +0,0 @@ -#! /bin/sh -PORT=8001 -TTY=-i -test -t 0 && test -t 1 && TTY=-it - -case "$1" in ---pull) - shift - docker pull agoric/cosmic-swingset-pserver - ;; -esac - -exec docker run -p127.0.0.1:$PORT:$PORT \ - --volume=ag-pserver-state:/root/.ag-pserver \ - --rm $TTY \ - agoric/cosmic-swingset-pserver ${1+"$@"} diff --git a/packages/cosmic-swingset/provisioning-server/.dockerignore b/packages/cosmic-swingset/provisioning-server/.dockerignore deleted file mode 100644 index 2e0b6ac5bf0..00000000000 --- a/packages/cosmic-swingset/provisioning-server/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -src/ag_pserver/__pycache__ -src/ag_pserver/ag_pserver.egg-info -Dockerfile diff --git a/packages/cosmic-swingset/provisioning-server/Dockerfile b/packages/cosmic-swingset/provisioning-server/Dockerfile deleted file mode 100644 index f2090da0e38..00000000000 --- a/packages/cosmic-swingset/provisioning-server/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM debian:buster AS build - -RUN apt-get update -y && apt-get install gcc python3 python3-venv python3-dev -y && apt-get clean -y - -WORKDIR /usr/src/app -RUN python3 -mvenv ve3 -RUN ve3/bin/pip install --upgrade pip -RUN ve3/bin/pip install wheel -COPY . provisioning-server/ -RUN ve3/bin/pip install provisioning-server/ - -FROM debian:buster AS install - -WORKDIR /usr/src/app -RUN apt-get update -y && apt-get install python3 -y && apt-get clean -y -COPY --from=build /usr/src/app/ve3/ /usr/src/app/ve3/ - -ENTRYPOINT ["ve3/bin/ag-pserver"] diff --git a/packages/cosmic-swingset/provisioning-server/bin/ag-pserver.py b/packages/cosmic-swingset/provisioning-server/bin/ag-pserver.py deleted file mode 100644 index 6b954a02345..00000000000 --- a/packages/cosmic-swingset/provisioning-server/bin/ag-pserver.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env python - -# see ../setup.py for installation instructions diff --git a/packages/cosmic-swingset/provisioning-server/setup.py b/packages/cosmic-swingset/provisioning-server/setup.py deleted file mode 100644 index 33854ea904c..00000000000 --- a/packages/cosmic-swingset/provisioning-server/setup.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python - -# run: -# python3 -mvenv ../ve3 -# ../ve3/bin/pip install wheel -# ../ve3/bin/pip install --editable . -# ../ve3/bin/ag-pserver --listen tcp:8001 --controller tcp:localhost:8002 - -# the provisioning webpage is in html/index.html , edit it in place - -from setuptools import setup -import os -setup( - name="ag-pserver", - description="provisioning server for Agoric testnet", - license="MIT", - package_dir={"": "src"}, - packages=["ag_pserver"], - package_data={"ag_pserver": ['html/*']}, - install_requires=[ - "twisted[tls]", - "magic-wormhole", - "treq", - ], - entry_points={ - "console_scripts": [ "ag-pserver = ag_pserver.main:main" ], - }, - include_package_data=True, - version="0.2.0", - ) - diff --git a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/__init__.py b/packages/cosmic-swingset/provisioning-server/src/ag_pserver/__init__.py deleted file mode 100644 index 8b137891791..00000000000 --- a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/html/index.html b/packages/cosmic-swingset/provisioning-server/src/ag_pserver/html/index.html deleted file mode 100644 index d74710965d8..00000000000 --- a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/html/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - -Agoric Testnet Provisioning Page - - - -

Welcome to the Agoric Testnet

- -
On this page you can obtain a code to provision your client node.
- -
Type your nickname into this box and press the button to obtain a provisioning code. Then run ag-setup-solo [BASEDIR] and type the code into the prompt.
- -
-
- - - -
-
- -
- -
-
-
Source: - - v+ -
-
- - - diff --git a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/html/response-template.html b/packages/cosmic-swingset/provisioning-server/src/ag_pserver/html/response-template.html deleted file mode 100644 index 0c67e403a9c..00000000000 --- a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/html/response-template.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - -Agoric Testnet Provisioning Page - - - -

Provision Your Client Node

- -
The provisioning code for $$$NICKNAME$$$ - is: $$$CODE$$$
- -
- -
Now run the following command and enter the provisioning code when asked:
- -
-$ ag-setup-solo [BASEDIR]
-
- -
Then just follow the instructions. Thank you for provisioning an Agoric -Testnet Client Node!
- -
- -
-
-
Source: - - v+ -
-
- - - diff --git a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/html/styles.css b/packages/cosmic-swingset/provisioning-server/src/ag_pserver/html/styles.css deleted file mode 100644 index fcf5d40ea9e..00000000000 --- a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/html/styles.css +++ /dev/null @@ -1,3 +0,0 @@ -span.provisioning-code { - color: #f00; -} diff --git a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/main.py b/packages/cosmic-swingset/provisioning-server/src/ag_pserver/main.py deleted file mode 100644 index 8e1483c5c75..00000000000 --- a/packages/cosmic-swingset/provisioning-server/src/ag_pserver/main.py +++ /dev/null @@ -1,502 +0,0 @@ -from twisted.internet.task import react, deferLater -from twisted.web import static, resource, server -from twisted.web.template import Element, XMLFile, renderer, flattenString -from twisted.internet import endpoints, defer, protocol -from twisted.python import usage -import wormhole -import os.path -import os -import json -import random -import re -from tempfile import NamedTemporaryFile - -from twisted.python import log -import sys -log.startLogging(sys.stdout) - -MAILBOX_URL = u"ws://relay.magic-wormhole.io:4000/v1" -#MAILBOX_URL = u"ws://10.0.2.24:4000/v1" -APPID = u"agoric.com/ag-testnet1/provisioning-tool" - -htmldir = os.path.join(os.path.dirname(__file__), "html") - -class SetConfigOptions(usage.Options): - pass - -class AddPubkeysOptions(usage.Options): - optParameters = [ - ["controller", "c", "NONE", "DEPRECATED"], - ] - -class StartOptions(usage.Options): - optParameters = [ - ["mountpoint", "m", "/", "controller's top level web page"], - ["listen", "l", "tcp:8001", "client-visible HTTP listening port"], - ["controller", "c", "NONE", "DEPRECATED"], - ] - -class Options(usage.Options): - subCommands = [ - ['set-cosmos-config', None, SetConfigOptions, "Pipe output of 'ag-setup-cosmos show-config' to this command"], - ['set-cosmos-genesis', None, SetConfigOptions, "Pipe output of 'ag-setup-cosmos show-genesis' to this commmand"], - ['add-pubkeys', None, AddPubkeysOptions, 'Add public keys from saved database'], - ['start', None, StartOptions, 'Start the HTTP server'], - ] - optParameters = [ - ["home", None, os.path.join(os.environ["HOME"], '.ag-pserver'), "provisioning-server's state directory"], - ['initial-token', 'T', 'NONE', "DEPRECATED"], - ] - -class SendInputAndWaitProtocol(protocol.ProcessProtocol): - def __init__(self, d, input): - self.deferred = d - self.input = input - self.output = b'' - self.error = b'' - - def connectionMade(self): - self.transport.write(self.input) - self.transport.closeStdin() - - def outReceived(self, data): - self.output += data - print(data.decode('latin-1')) - - def errReceived(self, data): - self.error += data - print(data.decode('latin-1'), file=sys.stderr) - - def processEnded(self, reason): - self.deferred.callback((reason.value.exitCode, self.output, self.error)) - -class StackedResource(resource.Resource): - def __init__(self, stack): - super().__init__() - self.stack = [super(), *stack] - - def getChildWithDefault(self, *args): - for s in self.stack: - res = s.getChildWithDefault(*args) - if not isinstance(res, resource.NoResource): - return res - return res - -def wwwroot(home): - return os.path.join(home, 'wwwroot') - -def cosmosConfigFile(home): - return os.path.join(wwwroot(home), 'current', 'chain.json') - -def cosmosGenesisFile(home): - return os.path.join(wwwroot(home), 'current', 'genesis.json') - -def pubkeyDatabase(home): - return os.path.join(home, 'pubkeys.jsona') - -class ConfigElement(Element): - loader = XMLFile(os.path.join(htmldir, "index.html")) - - @staticmethod - def gatherArgs(opts): - meta = {} - with open(cosmosConfigFile(opts['home'])) as f: - config = f.read() - gr = '/usr/src/app/lib/git-revision.txt' - if os.path.exists(gr): - with open(gr) as f: - meta['package_git'] = f.read().strip() - else: - with os.popen('git rev-parse --short HEAD') as f: - sha = f.read().strip() - with os.popen('git diff --quiet || echo -dirty') as f: - meta['package_git'] = sha + f.read().strip() - - pj = '/usr/src/app/package.json' - pjson = {} - if os.path.exists(pj): - with open(pj) as f: - pjson = json.load(f) - else: - pjpath = None - # Walk upwards from the current directory. - pj = os.path.abspath('package.json') - while pj != pjpath: - pjpath = pj - if os.path.exists(pjpath): - with open(pjpath) as f: - pjson = json.load(f) - break - pj = os.path.join(os.path.dirname(pjpath), '../package.json') - pj = os.path.abspath(pj) - - meta['package_version'] = pjson.get('version', 'unknown') - meta['package_name'] = pjson.get('name', 'cosmic-swingset') - repo = pjson.get('repository', 'https://github.com/Agoric/cosmic-swingset') - cleanRev = meta['package_git'].replace('-dirty', '') - link = repo + '/commit/' + cleanRev - meta['package_repo'] = link - - return [config, meta] - - def __init__(self, config, meta): - self._config = config - self._meta = meta - - @renderer - def config(self, request, tag): - tag.fillSlots(cosmos_config=self._config) - return tag - - @renderer - def meta(self, request, tag): - tag.fillSlots(**self._meta) - return tag - -class ResponseElement(ConfigElement): - loader = XMLFile(os.path.join(htmldir, "response-template.html")) - - def __init__(self, code, nickname, *args): - super().__init__(*args) - self._code = code - self._nickname = nickname - - @renderer - def code(self, request, tag): - return self._code - - @renderer - def nickname(self, request, tag): - return self._nickname - -class Provisioner(resource.Resource): - def __init__(self, reactor, o): - self.reactor = reactor - self.opts = o - - @defer.inlineCallbacks - def build_page(self): - with open(cosmosConfigFile(self.opts['home'])) as f: - config = f.read() - - args = ConfigElement.gatherArgs(self.opts) - html = yield flattenString(None, ConfigElement(*args)) - return html - - def render_GET(self, req): - d = self.build_page() - def built(response): - req.write(response) - req.finish() - d.addCallback(built) - d.addErrback(log.err) - return server.NOT_DONE_YET - - -@defer.inlineCallbacks -def enablePubkey(reactor, opts, config, nickname, pubkey): - mobj = { - "type": "pleaseProvision", - "nickname": nickname, - "pubkey": pubkey, - } - # print("mobj:", mobj) - def ret(server_message): - return [mobj, server_message, config] - - args = [ - 'tx', 'swingset', 'provision-one', '--keyring-backend=test', nickname, pubkey, - '--from=ag-solo', '--yes', '--broadcast-mode=block', # Don't return until committed. - '--gas=auto', '--gas-adjustment=1.4', - ] - code, output = yield agCosmosHelper(reactor, opts, config, args, 10) - if code != 0: - return ret({"ok": False, "error": 'transfer returned ' + str(code)}) - - ingressIndex = 1 - # this message is sent back to setup-solo/src/ag_setup_solo/main.py - server_message = { - "ok": True, - "gci": config['gci'], - "rpcAddrs": config['rpcAddrs'], - "chainName": config['chainName'], - "ingressIndex": ingressIndex, - } - print("send server_message", server_message) - return ret(server_message) - - -class RequestCode(resource.Resource): - def __init__(self, reactor, o): - self.reactor = reactor - self.opts = o - - @defer.inlineCallbacks - def got_message(self, client_message, nickname): - cm = json.loads(client_message.decode("utf-8")) - with open(cosmosConfigFile(self.opts['home'])) as f: - config = json.loads(f.read()) - - msgs = yield enablePubkey(self.reactor, self.opts, config, nickname, cm['pubkey']) - return msgs - - def send_provisioning_response(self, msgs, w): - [mobj, server_message, config] = msgs - sm = json.dumps(server_message).encode("utf-8") - print("send provisioning response", server_message) - w.send_message(sm) - d = w.close() - def complete(_): - print("provisioning complete") - pkobj = { - 'chainName': config['chainName'], - 'pubkey': mobj['pubkey'], - 'nickname': mobj['nickname'][:32], - } - print("save public key to database", pkobj) - pkobj_str = json.dumps(pkobj) - with open(pubkeyDatabase(self.opts['home']), 'a') as db: - db.write(pkobj_str + ',\n') - d.addCallbacks(complete, - lambda f: print("provisioning error", f)) - - @defer.inlineCallbacks - def process_wormhole(self, nickname): - w = wormhole.create(APPID, MAILBOX_URL, self.reactor) - w.allocate_code() - code = yield w.get_code() - - d = w.get_message() - d.addCallback(self.got_message, nickname.decode('utf-8')) - d.addCallback(self.send_provisioning_response, w) - return code - - @defer.inlineCallbacks - def build_provisioning_response(self, nickname): - code = yield self.process_wormhole(nickname) - args = ConfigElement.gatherArgs(self.opts) - html = yield flattenString(None, ResponseElement(code, nickname, *args)) - return html - - def render_POST(self, req): - nickname = req.args[b"nickname"][0] - print(nickname) - d = self.build_provisioning_response(nickname) - def built(response): - req.write(response) - req.finish() - d.addCallback(built) - d.addErrback(log.err) - return server.NOT_DONE_YET - - def render_GET(self, req): - nickname = req.args[b"nickname"][0] - d = self.process_wormhole(nickname) - def built(code): - req.setHeader('Content-Type', 'text/plain; charset=UTF-8') - req.write((code + '\n').encode('utf-8')) - req.finish() - d.addCallback(built) - d.addErrback(log.err) - return server.NOT_DONE_YET - -class GenesisJSON(resource.Resource): - def __init__(self, o): - self.opts = o - - def render_GET(self, req): - with open(cosmosGenesisFile(self.opts['home'])) as f: - config = f.read() - req.setHeader('Content-Type', 'application/json') - return config.encode('utf-8') - -class ConfigJSON(resource.Resource): - def __init__(self, o): - self.opts = o - - def render_GET(self, req): - with open(cosmosConfigFile(self.opts['home'])) as f: - config = f.read() - req.setHeader('Content-Type', 'application/json') - return config.encode('utf-8') - -def run_server(reactor, o): - print("dir is", __file__) - provroot = static.File(htmldir) - provisioner = Provisioner(reactor, o) - provroot.putChild(b"", provisioner) - provroot.putChild(b"index.html", provisioner) - provroot.putChild(b"request-code", RequestCode(reactor, o)) - - # Prefix the mountpoints. - revpaths = o['mountpoint'].split('/') - revpaths.reverse() - for dir in revpaths: - # print('mount root under ' + dir) - if dir != '': - r = resource.Resource() - r.putChild(dir.encode('utf-8'), provroot) - provroot = r - - # Override the paths. - root = StackedResource([static.File(wwwroot(o['home'])), provroot]) - if o['mountpoint'] == '/': - root.putChild(b"", provisioner) - - # Display the JSON config. - root.putChild(b"network-config", ConfigJSON(o)) - root.putChild(b"genesis.json", GenesisJSON(o)) - - site = server.Site(root) - s = endpoints.serverFromString(reactor, o["listen"]) - s.listen(site) - print("server running") - return defer.Deferred() - -@defer.inlineCallbacks -def agCosmosHelper(reactor, opts, config, args, retries = 1): - code = None - while code != 0 and retries > 0: - if code is not None: - # Wait 3 seconds between sends. - yield deferLater(reactor, 3, lambda: None) - retries -= 1 - rpcAddr = random.choice(config['rpcAddrs']) - print('running', rpcAddr, args) - d = defer.Deferred() - processProtocol = SendInputAndWaitProtocol(d, b'') - program = 'ag-cosmos-helper' - reactor.spawnProcess(processProtocol, '/usr/local/bin/' + program, args=[ - program, *args, - '--chain-id', config['chainName'], '-ojson', - '--node', 'tcp://' + rpcAddr, - '--home', os.path.join(opts['home'], 'ag-cosmos-helper-statedir'), - ]) - code, output, stderr = yield d - if code == 0: - oj = json.loads(output.decode('utf-8')) - code = oj.get('code', code) - output = oj - elif stderr[0:8] == b'ERROR: {': - try: - oj = json.loads(stderr[7:].decode('utf-8')) - code = oj.get('code', code) - output = oj - except: - pass - elif stderr[0:14] == b'gas estimate: ': - lines = stderr.split(b'\n') - oj = json.loads(lines[1].decode('utf-8')) - if oj.get('type') is None: - # Reformat the message into what --generate-only produces. - output = { - 'type': 'cosmos-sdk/StdTx', - 'value': { - 'msg': oj['msgs'], - 'fee': oj['fee'], - 'signatures': None, - 'memo': '', - }} - else: - output = oj - code = 0 - - return code, output - -@defer.inlineCallbacks -def doEnablePubkeys(reactor, opts, config, pkobjs): - txes = [] - needIngress = [] - - for pkobj in pkobjs: - pubkey = pkobj['pubkey'] - nickname = pkobj['nickname'] - print('generating transaction for', pubkey) - # Estimate the gas, with a little bit of padding. - args = ['tx', 'swingset', 'provision-one', '--keyring-backend=test', nickname, pubkey, - '--from=ag-solo', '--gas=auto', '--gas-adjustment=1.4'] - code, output = yield agCosmosHelper(reactor, opts, config, args, 1) - if code == 0: - txes.append(output) - - if len(txes) > 0: - tx0 = txes[0] - msgs = tx0['value']['msg'] - # Add up all the gases. - gas = int(tx0['value']['fee']['gas']) - for tx in txes[1:]: - val = tx['value'] - gas += int(val['fee']['gas']) - for msg in val['msg']: - msgs.append(msg) - tx0['value']['fee']['gas'] = str(gas) - # Create a temporary file that is automatically deleted. - with NamedTemporaryFile() as temp: - # Save the amalgamated transaction. - temp.write(json.dumps(tx0).encode('utf-8')) - temp.flush() - - # Now the temp.name contents are available - args = [ - 'tx', 'sign', temp.name, '--keyring-backend=test', '--from', config['bootstrapAddress'], - '--yes', '--append=false', - ] - - # Use the temp file in the sign request. - code, output = yield agCosmosHelper(reactor, opts, config, args, 10) - if code != 0: - raise Exception('Cannot sign transaction') - with NamedTemporaryFile() as temp: - # Save the signed transaction. - temp.write(json.dumps(output).encode('utf-8')) - temp.flush() - - # Now the temp.name contents are available - args = [ - 'tx', 'broadcast', temp.name, - '--broadcast-mode=block', - ] - - code, output = yield agCosmosHelper(reactor, opts, config, args, 10) - if code != 0: - raise Exception('Cannot broadcast transaction') - -def main(): - o = Options() - o.parseOptions() - if o.subCommand is not None and o.subCommand.startswith('set-cosmos-'): - try: - os.mkdir(o['home']) - except FileExistsError: - pass - if o.subCommand == 'set-cosmos-config': - fname = cosmosConfigFile(o['home']) - elif o.subCommand == 'set-cosmos-genesis': - fname = cosmosGenesisFile(o['home']) - print('Reading %s from stdin; hit Ctrl-D to finish' % fname) - cfgJson = sys.stdin.read() - # Check that the JSON input is properly-formatted. - json.loads(cfgJson) - # Write out the JSON. - with open(fname, 'w') as f: - f.write(cfgJson) - elif o.subCommand == 'add-pubkeys': - # Now that we have our files, add all the accounts. - with open(cosmosConfigFile(o['home']), 'r') as f: - config = json.loads(f.read()) - try: - # This file is comma-terminated lines of JSON objects. - with open(pubkeyDatabase(o['home'])) as f: - # Strip the trailing newlines and comma. - pkobjs_str = f.read().rstrip().rstrip(',') - # Interpret as an array. - pkobjs = json.loads('[' + pkobjs_str + ']') - except FileNotFoundError: - return - pkobjs.reverse() - react(doEnablePubkeys, ({**o, **o.subOptions}, config, pkobjs)) - elif o.subCommand == 'start': - react(run_server, ({**o, **o.subOptions},)) - else: - print("Need either 'set-cosmos-config' or 'start'") - sys.exit(1) diff --git a/packages/deployment/Dockerfile b/packages/deployment/Dockerfile index 62310673b85..0ebb7f48002 100644 --- a/packages/deployment/Dockerfile +++ b/packages/deployment/Dockerfile @@ -28,8 +28,7 @@ RUN ln -sf $PWD/setup/ag-setup-cosmos /usr/local/bin/ COPY package*.json setup/ RUN cd setup && npm install --production -# Add the provisioning server, so we can deploy it via Ansible. -COPY --from=agoric/cosmic-swingset-pserver /usr/src/app/ve3/ /usr/src/app/ve3/ +# Add the ag-solo, so we can deploy it via Ansible. COPY --from=agoric/cosmic-swingset-solo /usr/src/app/lib/ag-solo/ /usr/src/app/lib/ag-solo/ COPY . setup/ diff --git a/packages/deployment/Makefile b/packages/deployment/Makefile index 03c65c99b98..316b4ad873c 100644 --- a/packages/deployment/Makefile +++ b/packages/deployment/Makefile @@ -11,7 +11,7 @@ docker-show-fat: docker build --file=Dockerfile.show-fat ../.. docker-build: docker-build-base docker-build-sdk docker-build-solo \ - docker-build-pserver docker-build-setup docker-build-vagrant + docker-build-setup docker-build-vagrant docker-build-sdk: docker build -t $(REPOSITORY_SDK):latest --file=Dockerfile.sdk ../.. @@ -25,9 +25,6 @@ docker-build-base: echo "$$hash$$dirty" > $(SS)lib/git-revision.txt docker build -t $(REPOSITORY):latest $(SS) -docker-build-pserver: - docker build -t $(REPOSITORY)-pserver:latest $(SS)provisioning-server - docker-build-solo: docker build -t $(REPOSITORY)-solo:latest $(SS)lib/ag-solo @@ -35,7 +32,7 @@ docker-build-vagrant: docker build -t agoric/vagrant-debian:latest --file=../../vagrant/Dockerfile ../../vagrant docker-push: docker-push-base docker-push-solo docker-push-setup \ - docker-push-pserver docker-push-ibc-alpha docker-push-vagrant + docker-push-ibc-alpha docker-push-vagrant # ./docker is an emptyish directory. docker-build-ibc-alpha: @@ -54,11 +51,6 @@ docker-push-base: $(DONT_PUSH_LATEST) docker push $(REPOSITORY_SDK):latest docker push $(REPOSITORY_SDK):$(TAG) -docker-push-pserver: - docker tag $(REPOSITORY)-pserver:latest $(REPOSITORY)-pserver:$(TAG) - $(DONT_PUSH_LATEST) docker push $(REPOSITORY)-pserver:latest - docker push $(REPOSITORY)-pserver:$(TAG) - docker-push-solo: docker tag $(REPOSITORY)-solo:latest $(REPOSITORY)-solo:$(TAG) $(DONT_PUSH_LATEST) docker push $(REPOSITORY)-solo:latest diff --git a/packages/deployment/ansible/dweb-copy.yml b/packages/deployment/ansible/dweb-copy.yml new file mode 100644 index 00000000000..80d0f18ea5c --- /dev/null +++ b/packages/deployment/ansible/dweb-copy.yml @@ -0,0 +1,11 @@ +--- + +- hosts: "{{ service }}" + user: root + strategy: free + vars: + - service: dweb + - NETWORK_NAME: "{{ lookup('file', SETUP_HOME + '/network.txt') }}" + roles: + - init + - dweb-copy diff --git a/packages/deployment/ansible/fetch-controller.yml b/packages/deployment/ansible/fetch-controller.yml deleted file mode 100644 index 3a4dec00235..00000000000 --- a/packages/deployment/ansible/fetch-controller.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- - -- hosts: ag-pserver - user: root - #any_errors_fatal: true - gather_facts: yes - strategy: free - vars: - - service: ag-pserver - - data: "{{ SETUP_HOME }}/{{ service }}/data" - roles: - - fetch-controller diff --git a/packages/deployment/ansible/install-controller.yml b/packages/deployment/ansible/install-controller.yml deleted file mode 100644 index 024857d92d8..00000000000 --- a/packages/deployment/ansible/install-controller.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- - -- hosts: "{{ service }}" - user: root - #any_errors_fatal: true - gather_facts: yes - strategy: free - vars: - - service: ag-pserver - - data: "{{ SETUP_HOME }}/{{ service }}/data" - - GCI: "{{ lookup('file', SETUP_HOME + '/' + service + '/gci.txt') }}" - - RPC_ADDRS: "{{ lookup('file', SETUP_HOME + '/' + service + '/rpcaddrs.txt') }}" - - CHAIN_NAME: "{{ lookup('file', SETUP_HOME + '/ag-chain-cosmos/chain-name.txt') }}" - - NETWORK_NAME: "{{ lookup('file', SETUP_HOME + '/network.txt') }}" - roles: - - stat-tls-keys - - install-controller diff --git a/packages/deployment/ansible/prepare-controller.yml b/packages/deployment/ansible/prepare-controller.yml deleted file mode 100644 index af970b864bf..00000000000 --- a/packages/deployment/ansible/prepare-controller.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- - -- hosts: ag-pserver - user: root - #any_errors_fatal: true - gather_facts: yes - strategy: free - vars: - - service: ag-pserver - - data: "{{ SETUP_HOME }}/{{ service }}/data" - - APPDIR: "{{lookup('pipe', 'pwd')}}/../.." - - HELPER_BINARY: "{{lookup('env', 'GOPATH') or '/usr/local'}}/bin/ag-cosmos-helper" - - CHAIN_NAME: "{{ lookup('file', SETUP_HOME + '/ag-chain-cosmos/chain-name.txt') }}" - roles: - - copy - - init - - init-controller - - fetch-controller diff --git a/packages/deployment/ansible/roles/dweb-copy/tasks/main.yml b/packages/deployment/ansible/roles/dweb-copy/tasks/main.yml new file mode 100644 index 00000000000..7ed515be7d6 --- /dev/null +++ b/packages/deployment/ansible/roles/dweb-copy/tasks/main.yml @@ -0,0 +1,55 @@ +--- + +- name: Ensure public exists + become_user: "{{ service }}" + become: yes + file: + path: "/home/{{ service }}/public" + state: directory + mode: '0755' + +- name: Copy network-config + become_user: "{{ service }}" + become: yes + copy: + src: "{{ SETUP_HOME }}/{{ service }}/data/cosmos-chain.json" + dest: "/home/{{ service }}/public/network-config" + mode: '0644' + +- name: Copy genesis.json + become_user: "{{ service }}" + become: yes + copy: + src: "{{ SETUP_HOME }}/ag-chain-cosmos/data/genesis.json" + dest: "/home/{{ service }}/public/genesis.json" + mode: '0644' + +- name: "Stat CRT" + delegate_to: localhost + stat: + path="{{ SETUP_HOME }}/{{ NETWORK_NAME }}.crt" + register: stat_crt + +- name: "Stat KEY" + delegate_to: localhost + stat: + path="{{ SETUP_HOME }}/{{ NETWORK_NAME }}.key" + register: stat_key + +- name: "Copy {{ NETWORK_NAME }}.crt" + become_user: "{{ service }}" + become: yes + copy: + src: "{{ SETUP_HOME }}/{{ NETWORK_NAME }}.crt" + dest: "/home/{{ service }}/{{ NETWORK_NAME }}.crt" + mode: '0644' + when: stat_crt.stat.exists + +- name: "Copy {{ NETWORK_NAME }}.key" + become_user: "{{ service }}" + become: yes + copy: + src: "{{ SETUP_HOME }}/{{ NETWORK_NAME }}.key" + dest: "/home/{{ service }}/{{ NETWORK_NAME }}.key" + mode: "0600" + when: stat_key.stat.exists diff --git a/packages/deployment/ansible/roles/fetch-controller/tasks/main.yml b/packages/deployment/ansible/roles/fetch-controller/tasks/main.yml deleted file mode 100644 index 8c0d0eb3d1e..00000000000 --- a/packages/deployment/ansible/roles/fetch-controller/tasks/main.yml +++ /dev/null @@ -1,5 +0,0 @@ -- name: "Fetch {{ data | default(service + '/data') }}/*/boot-address.txt" - fetch: - dest: "{{ data | default(service + '/data') }}/{{ inventory_hostname }}/boot-address.txt" - flat: yes - src: "/home/{{ service }}/.{{ service }}/ag-cosmos-helper-address" diff --git a/packages/deployment/ansible/roles/init-controller/tasks/main.yml b/packages/deployment/ansible/roles/init-controller/tasks/main.yml deleted file mode 100644 index 7a1aed218e2..00000000000 --- a/packages/deployment/ansible/roles/init-controller/tasks/main.yml +++ /dev/null @@ -1,35 +0,0 @@ -- name: "Ensure /home/{{ service }}/.ag-pserver/wwwroot/{{ CHAIN_NAME }} exists" - become: yes - become_user: "{{ service }}" - file: - path: "/home/{{ service }}/.ag-pserver/wwwroot/{{ CHAIN_NAME }}" - state: directory - -- name: "Create provisioning mnemonic" - delegate_to: localhost - shell: - cmd: "ag-cosmos-helper keys mnemonic 2>&1 | tee provisioning-mnemonic.txt" - chdir: "{{ SETUP_HOME }}" - register: mnemonic - -- name: "Delete {{ service }} ag-solo key" - become: yes - become_user: "{{ service }}" - shell: - cmd: "ag-cosmos-helper --home=/home/{{ service }}/.ag-pserver/ag-cosmos-helper-statedir --keyring-backend=test keys delete ag-solo --yes" - removes: "/home/{{ service }}/.ag-pserver/ag-cosmos-helper-statedir" - ignore_errors: yes - -- name: "Create {{ service }} ag-solo key" - become: yes - become_user: "{{ service }}" - shell: - cmd: "ag-cosmos-helper --home=/home/{{ service }}/.ag-pserver/ag-cosmos-helper-statedir --keyring-backend=test keys add --recover ag-solo" - stdin: "{{ mnemonic.stdout }}" - -- name: "Create ag-cosmos-helper-address" - become: yes - become_user: "{{ service }}" - shell: - cmd: "ag-cosmos-helper --home=/home/{{ service }}/.ag-pserver/ag-cosmos-helper-statedir \ - --keyring-backend=test keys show -a ag-solo > /home/{{ service }}/.ag-pserver/ag-cosmos-helper-address" diff --git a/packages/deployment/ansible/roles/install-controller/tasks/main.yml b/packages/deployment/ansible/roles/install-controller/tasks/main.yml deleted file mode 100644 index b655506e5c3..00000000000 --- a/packages/deployment/ansible/roles/install-controller/tasks/main.yml +++ /dev/null @@ -1,47 +0,0 @@ -- name: "Ensure /home/{{ service }}/.{{ service }} exists" - become_user: "{{ service }}" - become: true - file: - path: "/home/{{ service }}/.{{ service }}" - state: directory - mode: 0755 - -- name: "Install {{ data | default(service + '/data') }}/../../ag-chain-cosmos/data/genesis.json" - become_user: "{{ service }}" - become: true - copy: - src: "{{ data | default(service + '/data') }}/../../ag-chain-cosmos/data/genesis.json" - dest: "/home/{{ service }}/.{{ service }}/wwwroot/{{ CHAIN_NAME }}/genesis.json" - owner: "{{ service }}" - group: "{{ service }}" - mode: 0644 - -- name: "Install {{ data | default(service + '/data') }}/cosmos-chain.json" - become_user: "{{ service }}" - become: true - copy: - src: "{{ data | default(service + '/data') }}/cosmos-chain.json" - dest: "/home/{{ service }}/.{{ service }}/wwwroot/{{ CHAIN_NAME }}/chain.json" - owner: "{{ service }}" - group: "{{ service }}" - mode: 0644 - -- name: "Set wwwroot/current to {{ CHAIN_NAME }}" - become_user: "{{ service }}" - become: true - file: - state: link - path: "/home/{{ service }}/.{{ service }}/wwwroot/current" - src: "{{ CHAIN_NAME }}" - -- name: "Add {{ NETWORK_NAME }} keys" - synchronize: - src: "{{ SETUP_HOME }}/{{ NETWORK_NAME }}.{{ item }}" - dest: "/home/{{ service }}/.{{ service }}/{{NETWORK_NAME}}.{{item}}" - mode: push - with_items: - - crt - - key - when: - - tlscrt.stat.exists - - tlskey.stat.exists diff --git a/packages/deployment/main.js b/packages/deployment/main.js index 52c9b501bd6..0487e5dc4df 100644 --- a/packages/deployment/main.js +++ b/packages/deployment/main.js @@ -36,7 +36,7 @@ import { const PROVISION_DIR = 'provision'; const PROVISIONER_NODE = 'node0'; // FIXME: Allow configuration. const COSMOS_DIR = 'ag-chain-cosmos'; -const CONTROLLER_DIR = 'ag-pserver'; +const DWEB_DIR = 'dweb'; const SECONDS_BETWEEN_BLOCKS = 5; // This is needed for hyphenated group names not to trigger Ansible. @@ -49,9 +49,7 @@ const guardFile = async (file, maker) => { return 0; } const parent = dirname(file); - if (!(await exists(parent))) { - await mkdir(parent); - } + await mkdir(parent, { recursive: true }); let made = false; const ret = await maker(async contents => { await createFile(file, contents); @@ -363,37 +361,22 @@ show-config display the client connection parameters const networkName = await trimReadFile('network.txt'); const chainVersion = await trimReadFile('chain-version.txt'); const chainName = `${networkName}-${chainVersion}`; - const pserverPassword = (await exists('pserver-password.txt')) - ? await trimReadFile('pserver-password.txt') - : ''; const currentChainName = await trimReadFile( `${COSMOS_DIR}/chain-name.txt`, ).catch(_ => undefined); if (subOpts.bump || currentChainName !== chainName) { // We don't have matching parameters, so restart the chain. - // Stop all the services. - await reMain(['play', 'stop', '-eservice=ag-pserver']); - await reMain([ - 'play', - 'stop', - '-eservice=ag-controller', - '-euser=ag-pserver', - ]); + // Stop the chain services. await reMain(['play', 'stop', '-eservice=ag-chain-cosmos']); - // Blow away controller/cosmos state. - await needDoRun(['rm', '-rf', CONTROLLER_DIR, COSMOS_DIR]); + // Blow away cosmos state. + await needDoRun(['rm', '-rf', COSMOS_DIR]); } await guardFile(`${COSMOS_DIR}/chain-name.txt`, async makeFile => { await makeFile(chainName); }); - // Initialize the controller. - await guardFile(`${CONTROLLER_DIR}/prepare.stamp`, () => - needReMain(['play', 'prepare-controller']), - ); - // Bootstrap the chain nodes. await guardFile(`${COSMOS_DIR}/prepare.stamp`, () => needReMain(['play', 'prepare-cosmos']), @@ -473,91 +456,61 @@ show-config display the client connection parameters 'Your Agoric Cosmos chain is now running!', ), ); + await needReMain(['dweb']); + break; + } + + case 'dweb': { + await inited(); + const networkName = await trimReadFile('network.txt'); const cfg = await needBacktick(`${shellEscape(progname)} show-config`); process.stdout.write(`${chalk.yellow(cfg)}\n`); - await guardFile( - `${CONTROLLER_DIR}/data/cosmos-chain.json`, - async makeFile => { - await makeFile(cfg); - }, - ); - - await guardFile(`${CONTROLLER_DIR}/gci.txt`, async makeFile => { - const gci = await needBacktick(`${shellEscape(progname)} show-gci`); - await makeFile(gci); - }); - await guardFile(`${CONTROLLER_DIR}/rpcaddrs.txt`, async makeFile => { - const rpcAddrs = await needBacktick( - `${shellEscape(progname)} show-rpcaddrs`, - ); - await makeFile(rpcAddrs.replace(/,/g, ' ')); + await guardFile(`${DWEB_DIR}/data/cosmos-chain.json`, async makeFile => { + await makeFile(cfg); }); - await guardFile(`${CONTROLLER_DIR}/install.stamp`, () => - needReMain(['play', 'install-controller']), - ); - // Install any pubkeys from a former instantiation. - await guardFile(`${CONTROLLER_DIR}/pubkeys.stamp`, () => - needReMain([ - 'ssh', - 'ag-pserver', - 'sudo', - '-u', - 'ag-pserver', - '/usr/src/app/ve3/bin/ag-pserver', - 'add-pubkeys', - '-c', - 'http://localhost:8000/private/repl', - ]), + const rpcAddrs = await needBacktick( + `${shellEscape(progname)} show-rpcaddrs`, ); + const match = rpcAddrs.match(/^([^,]+):\d+(,|$)/); - let pserverFlags = ''; - const installFlags = []; - const pub = `${networkName}.crt`; + let execline = `npx http-server ./public`; + let pWebHost; + const cert = `${networkName}.crt`; const key = `${networkName}.key`; - if ((await exists(pub)) && (await exists(key))) { - pserverFlags = ` ${shellEscape( - `--listen=ssl:443:privateKey=.ag-pserver/${key}:certKey=.ag-pserver/${pub}`, - )}`; - installFlags.push( - `-eserviceLines=AmbientCapabilities=CAP_NET_BIND_SERVICE`, - ); + if ((await exists(cert)) && (await exists(key))) { + execline += ` --port=443 --ssl`; + execline += ` --cert=${shellEscape(cert)}`; + execline += ` --key=${shellEscape(key)}`; + pWebHost = `https://${match[1]}`; + } else { + execline += ` --port=80`; + pWebHost = `http://${match[1]}`; } - const mountpoint = - pserverPassword === '' - ? '' - : ` -m ${shellEscape(`/provision-${pserverPassword}`)}`; - const execline = `/usr/src/app/ve3/bin/ag-pserver start${pserverFlags}${mountpoint} -c http://localhost:8000/private/repl`; - await guardFile(`${CONTROLLER_DIR}/service.stamp`, () => + // Copy the needed files to the web server. + await needReMain(['play', 'dweb-copy']); + + await guardFile(`${DWEB_DIR}/service.stamp`, () => needReMain([ 'play', 'install', - '-eservice=ag-pserver', + '-eservice=dweb', `-eexecline=${shellEscape(execline)}`, - ...installFlags, + `-eserviceLines=AmbientCapabilities=CAP_NET_BIND_SERVICE`, ]), ); - await guardFile(`${CONTROLLER_DIR}/start.stamp`, () => - needReMain(['play', 'start', '-eservice=ag-pserver']), + await guardFile(`${DWEB_DIR}/start.stamp`, () => + needReMain(['play', 'start', '-eservice=dweb']), ); - const rpcAddrs = await needBacktick( - `${shellEscape(progname)} show-rpcaddrs`, - ); - const match = rpcAddrs.match(/^([^,]+):\d+(,|$)/); - const pserverHost = pserverFlags - ? `https://${match[1]}` - : `http://${match[1]}:8001`; initHint(); console.error( `Use the following to provision: -${chalk.yellow.bold( - `ag-setup-solo --netconfig='${pserverHost}/network-config'`, -)} +${chalk.yellow.bold(`ag-setup-solo --netconfig='${pWebHost}/network-config'`)} `, ); if (await exists('/vagrant')) { @@ -829,7 +782,7 @@ ${chalk.yellow.bold( } // We no longer are provisioned or have Cosmos. - await needDoRun(['rm', '-rf', PROVISION_DIR, CONTROLLER_DIR, COSMOS_DIR]); + await needDoRun(['rm', '-rf', COSMOS_DIR, PROVISION_DIR, DWEB_DIR]); break; } @@ -885,18 +838,18 @@ ${name}: for (let instance = 0; instance < ips.length; instance += 1) { const ip = ips[instance]; const node = `node${offset + instance}`; - const moniker = `Agoric${offset + instance}`; const units = node === PROVISIONER_NODE ? `\ units: - - ag-pserver.service - ag-chain-cosmos.service ` : ''; const host = `\ ${node}: - moniker: ${moniker} + moniker: Agoric${offset + instance} + website: https://testnet.agoric.com + identity: https://keybase.io/team/agoric.testnet.validators ansible_host: ${ip} ansible_ssh_user: root ansible_ssh_private_key_file: '${SSH_PRIVATE_KEY_FILE}' @@ -906,11 +859,10 @@ ${units}`; addAll(host); - // TODO: Don't make these hardcoded assumptions. - // For now, we add all the nodes to ag-chain-cosmos, and the first node to ag-pserver. + // We add all the nodes to ag-chain-cosmos. addChainCosmos(host); if (node === PROVISIONER_NODE) { - makeGroup('ag-pserver', 4)(host); + makeGroup('dweb', 4)(host); } } }