Document installation of app, including in production. Add smf manifest so

we can run this in a Joyent-branded zone too.
This commit is contained in:
Marsell Kukuljevic 2021-04-11 20:51:52 +02:00
parent db8758cc30
commit 51028156c9
3 changed files with 84 additions and 16 deletions

View File

@ -1,25 +1,74 @@
# Installing in Production
Be familiar with the steps in [Installation][] below, since it is needed to
build the Angular app first.
Once the Angular app is built, provision a small base-64-lts 20.4.0 VM,
connected solely to the external network (aka public Internet). From within
the VM, the following steps are needed:
pkgin in gmake
mkdir -p /opt/spearhead/portal
From this repo, copy in bin/, cfg/, smf/, static/ (since this is a symlink,
this means the build in app/dist should be copied into static/ in prod), and \*.
Notably, avoid app/ and node\_modules. In production, adjust the config in
/opt/spearhead/portal/cfg/prod.json. Lastly:
pushd /opt/spearhead/portal
npm install
svccfg import smf/service.xml
svcadm enable portal
popd
The application will now be running.
# Installation # Installation
First install the server-side libraries:
npm install npm install
# Generate server certificates Then install the Angular compiler needed for the client-side app:
From within the config/ directory: npm install -g @angular/cli
pushd app && npm install && popd
## Build the client-side app:
pushd app && npm run build && popd
## Generate server certificates
pushd config
openssl genrsa -out key.pem openssl genrsa -out key.pem
openssl req -new -key key.pem -out csr.pem openssl req -new -key key.pem -out csr.pem
openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem
rm csr.pem rm csr.pem
popd
# Configuration ## Configuration
Ensure the config file in config/ matches your details. Ensure the config file in config/ matches your details. If running in
production, name the config file config/prod.json.
Relevant configuration attributes:
- server.port: the port this server will serve the app from
- server.key: path to the private key for TLS
- server.cert: path to the PKIX certificate for TLS
- urls.local: the domain or IP the SSO will redirect back to (aka this server)
- urls.sso: the URL to the SSO
- urls.cloudapi: the URL to cloudapi
- key.user: name of Triton user who has "Registered Developer" permission set
- key.id: SSH fingerprint of Triton user (same as what node-triton uses)
- key.path: path to private key of Triton user
The SSH key used must be the correct format, e.g. generated with: The SSH key used must be the correct format, e.g. generated with:
ssh-keygen -m PEM -t rsa -C "your@email.address" ssh-keygen -m PEM -t rsa -C "your@email.address"
# Running the server ## Running the server
node bin/server.js config/prod.json node bin/server.js config/prod.json
@ -31,18 +80,18 @@ and instead:
# Endpoints # Endpoints
## GET /* ## GET /\*
This is where all the front-end code goes. All files will be served as-is as This is where all the front-end code goes. All files will be served as-is as
found in that directory (by default a symlink to app/dist). The default is found in that directory (by default a symlink from static/ to app/dist). The
static/index.html. There is no authentication; all files are public. default is static/index.html. There is no authentication; all files are public.
## GET /api/login ## GET /api/login
Call this endpoint to begin the login cycle. It will redirect you to the SSO Call this endpoint to begin the login cycle. It will redirect you to the SSO
login page: an HTTP 302, with a Location header. login page: an HTTP 302, with a Location header.
## GET/POST/PUT/DELETE/HEAD /api/* ## GET/POST/PUT/DELETE/HEAD /api/\*
All calls will be passed through to cloudapi. For these calls to succeed, All calls will be passed through to cloudapi. For these calls to succeed,
they MUST provide an X-Auth-Token header, containing the token returned from they MUST provide an X-Auth-Token header, containing the token returned from
@ -50,12 +99,12 @@ SSO.
# Interaction cycle # Interaction cycle
client --- GET /api/login --------> this server client --- GET /api/login --------> this server
<-- 302 Location #1 ---- <-- 302 Location #1 ----
client --- GET <Location #1> --> SSO server client --- GET <Location #1> --> SSO server
<separate SSO cycle> <separate SSO cycle>
<-- 302 with token query arg <-- 302 with token query arg
From now on call this server as if it were a cloudapi server (using [cloudapi From now on call this server as if it were a cloudapi server (using [cloudapi
paths](https://github.com/joyent/sdc-cloudapi/blob/master/docs/index.md#api-introduction)), paths](https://github.com/joyent/sdc-cloudapi/blob/master/docs/index.md#api-introduction)),
@ -63,8 +112,8 @@ except prefixing any path with "/api". Also always provide the X-Auth-Token.
For example, to retrieve a list of packages: For example, to retrieve a list of packages:
client --- GET /api/my/packages --> this server client --- GET /api/my/packages --> this server
<-- 200 JSON body ------ <-- 200 JSON body ------
The most useful cloudapi endpoints to begin with will be ListPackages, The most useful cloudapi endpoints to begin with will be ListPackages,
GetPackage, ListImages, GetImage, ListMachines, GetMachine, CreateMachine and GetPackage, ListImages, GetImage, ListMachines, GetMachine, CreateMachine and

4
smf/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
cd /opt/spearhead/portal
/opt/local/bin/node bin/server.js cfg/prod.json &

15
smf/service.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type='manifest' name='portal:default'>
<service name='spearhead/portal' type='service' version='1'>
<create_default_instance enabled='false' />
<single_instance />
<method_context>
<method_credential user='root' group='root' />
</method_context>
<exec_method name='start' type='method' exec='/opt/spearhead/portal/smf/run.sh' timeout_seconds='60'/>
<exec_method name='stop' type='method' exec=':kill' timeout_seconds='60'/>
</service>
</service_bundle>