This patch addresses Nate's feedback that it's difficult to know what
platform is being operated on.
Previously it wasn't clear where the platform id used for push and pull
comes from. The source of truth is the platform.metadata.json file
created when the platform is first generated using `holos generate
platform k3d`.
This patch removes the platformId field from the platform.config.json
file, renames the platform.config.json file to platform.model.json and
renames the internal symbols to match the domain language of "Platform
Model" instead of the less clear "config"
This patch also changes the API between holos and CUE to use the proto
json imported from the proto file instead of generated from the go code
generated from the proto file. The purpose is to ensure protojson
encoding is used end to end.
Default log handler:
The patch also changes the default log output to print only the message
to stderr. This addresses similar feedback from both Gary and Nate that
the output is skipped over because it feels like internal debug logs.
We still want 100% of output to go through the logger so we can ensure
each line can be made into valid json. Info messages however are meant
for the user and all other attributes can be stripped off by default.
If additional source location is necessary, enable the text or json
output format.
Protobuf JSON:
This patch modifies the API contract between holos and CUE to ensure
data is exchanged exclusively using protojson. This is necessary
because protobuf has a canonical json format which is not compatible
with the go json package struct tags. When Holos handles a protobuf
message, it must marshal and unmarshal it using the protojson package.
Similarly, when importing protobuf messages into CUE, we must use `cue
import` instead of `cue go get` so that the canonical format is used
instead of the invalid go json struct tags.
Finally, when a Go struct like v1alpha1.Form is used to represent data
defined in cue which contains a nested protobuf message, Holos should
use a cue.Value to lookup the nested path, marshal it into json bytes,
then unmarshal it again using protojson.
Previously there was no way to delete a platform. This patch adds a
basic delete subcommand which deletes platforms by their id using the
rpc api.
❯ holos get platform
NAME DESCRIPTION AGE ID
k3d Holos Local k3d 20h 0190c78a-4027-7a7e-82d0-0b9f400f4bc9
k3d2 Holos Local k3d 20h 0190c7b3-382b-7212-81d6-ffcfc4a3fe7e
k3dasdf Holos Local k3d 20h 0190c7b3-728a-7212-b56d-2d2edf389003
k3d9 Holos Local k3d 20h 0190c7b8-4c4e-7cea-9d3d-a6b9434ae438
k3d-8581 Holos Local k3d 20h 0190c7ba-1de9-7cea-bff8-f15b51a56bdd
k3d-13974 Holos Local k3d 20h 0190c7ba-5833-7cea-b863-8e5ffb926810
k3d-20760 Holos Local k3d 19h 0190c7ba-7a12-7cea-a350-d55b4817d8bc
❯ holos delete platform 0190c7ba-1de9-7cea-bff8-f15b51a56bdd 0190c7ba-5833-7cea-b863-8e5ffb926810 0190c7ba-7a12-7cea-a350-d55b4817d8bc
deleted platform k3d-8581
deleted platform k3d-13974
deleted platform k3d-20760
Previously there was no way to get/list platforms. This patch adds a
basic get subcommand with list as an alias to get the platforms
currently defined in the organization.
❯ holos get platform
NAME DESCRIPTION AGE ID
k3d Holos Local k3d 18h 0190c78a-4027-7a7e-82d0-0b9f400f4bc9
k3d2 Holos Local k3d 17h 0190c7b3-382b-7212-81d6-ffcfc4a3fe7e
k3dasdf Holos Local k3d 17h 0190c7b3-728a-7212-b56d-2d2edf389003
k3d9 Holos Local k3d 17h 0190c7b8-4c4e-7cea-9d3d-a6b9434ae438
k3d-8581 Holos Local k3d 17h 0190c7ba-1de9-7cea-bff8-f15b51a56bdd
k3d-13974 Holos Local k3d 17h 0190c7ba-5833-7cea-b863-8e5ffb926810
k3d-20760 Holos Local k3d 17h 0190c7ba-7a12-7cea-a350-d55b4817d8bc
k3d-13916 Holos Local k3d 17h 0190c7ba-8313-7cea-be37-41491c95ae79
k3d-26154 Holos Local k3d 17h 0190c7ba-a117-7cea-8229-ce27da84135e
❯ holos get platform foo
7:16AM ERR could not execute version=0.89.1 code=unknown err="not found"
❯ holos get platform foo k3d
NAME DESCRIPTION AGE ID
k3d Holos Local k3d 18h 0190c78a-4027-7a7e-82d0-0b9f400f4bc9
Previously holos.platform.v1alpha1.PlatformService.CreatePlatform
returns an error for a request to create a platform of the same name as
an existing platform.
holos create platform --name k3d --display-name "Try Holos Locally"
8:00AM ERR could not execute version=0.87.2 code=failed_precondition
err="failed_precondition: platform.go:55: ent: constraint failed:
ERROR: duplicate key value violates unique constraint
\"platform_org_id_name\" (SQLSTATE 23505)" loc=client.go:138
This patch makes the CreatePlatform rpc idempotent using the upsert API.
The already_exists bool field is added to CreatePlatformResponse
response to indicate to the client if the platform already exists or
not.
Result:
holos create platform --display-name "Holos Local" --name k3d10
11:53AM INF create.go:56 created platform k3d10 version=0.87.2
name=k3d10 id=0190c731-1808-7e7d-9ccb-3d17434d0055
org=0190c6d6-4974-7733-9f7b-5d759a3e60e7 exists=false
holos create platform --display-name "Holos Local" --name k3d10
11:53AM INF create.go:56 updated platform k3d10 version=0.87.2
name=k3d10 id=0190c731-1808-7e7d-9ccb-3d17434d0055
org=0190c6d6-4974-7733-9f7b-5d759a3e60e7 exists=true
Previously there wasn't a good way to populate the platform model in the
database after building a new instance of holos server.
With this patch, the process to reset clean is:
```
export HOLOS_SERVER=https://dev.app.holos.run:443
grpcurl -H "x-oidc-id-token: $(holos token)" ${HOLOS_SERVER##*/} holos.user.v1alpha1.SystemService.DropTables
grpcurl -H "x-oidc-id-token: $(holos token)" ${HOLOS_SERVER##*/} holos.system.v1alpha1.SystemService.SeedDatabase
```
Then populate the form and model:
```
holos push platform form .
holos push platform model .
```
The `platform.config.json` file stored in version control is pushed to
the holos server and stored in the database. This makes it nice and
easy to reset entirely, or move to another service url.
Without this patch the
holos.platform.v1alpha1.PlatformService.CreatePlatform doesn't work as
expected. The Platform message is used which incorrectly requires a
client supplied id which is ignored by the server.
This patch allows the creation of a new platform by reusing the update
operation as a mutation that applies to both create and update. Only
modifiable fields are part of the PlatformMutation message.
This patch adds a subcommand to pull the data necessary to construct a
PlatformConfig DTO. The PlatformConfig message contains all of the
fields and values necessary to build a platform and the platform
components. This is an alternative to holos passing multiple tags to
CUE. The PlatformConfig is marshalled and passed once.
The platform config is also stored in the local filesystem in the root
directory of the platform. This enables repeated local building and
rendering without making an rpc call.
The build / render pipeline is expected to cache the PlatformConfig once
at the start of the pipeline using the pull subcommand.
The `holos render platform` command is unimplemented. This patch
partially implements platform rendering by fetching the platform model
from the PlatformService and providing it to CUE using a tag.
CUE returns a `kind: Platform` resource to `holos` which will eventually
process a Buildlan for each platform component listed in the Platform
spec.
For now, however, it's sufficient to have the current platform model
available to CUE.
When the holos server URL switches, we also need to update the client
context to get the correct org id.
Also improve quality of life by printing the url to the form when the
platform form is pushed to the server.
❯ holos push platform form .
11:41AM INF push.go:71 updated platform form version=0.79.0 server=https://app.dev.k2.holos.run:443 platform_id=018f87d1-7ca2-7e37-97ed-a06bcee9b442
11:41AM INF push.go:72 https://app.dev.k2.holos.run:443/ui/platform/018f87d1-7ca2-7e37-97ed-a06bcee9b442 version=0.79.0
This sub-command renders the web app form from CUE code and updates the
form using the `holos.platform.v1alpha1.PlatformService/UpdatePlatform`
rpc method.
Example use case, starting fresh:
```
rm -rf ~/holos
mkdir ~/holos
cd ~/holos
```
Step 1: Login
```sh
holos login
```
```txt
9:53AM INF login.go:40 logged in as jeff@ois.run version=0.79.0 name="Jeff McCune" exp="2024-05-17 21:16:07 -0700 PDT" email=jeff@ois.run
```
Step 2: Register to create server side resources.
```sh
holos register user
```
```
9:52AM INF register.go:68 user version=0.79.0 email=jeff@ois.run user_id=018f826d-85a8-751d-81ee-64d0f2775b3f org_id=018f826d-85a8-751e-98dd-a6cddd9dd8f0
```
Step 3: Generate the bare platform in the local filesystem.
```sh
holos generate platform bare
```
```txt
9:52AM INF generate.go:79 wrote platform.metadata.json version=0.79.0 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos/platform.metadata.json
9:52AM INF generate.go:91 generated platform bare version=0.79.0 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos
```
Step 4: Push the platform form to the `holos server` web app.
```sh
holos push platform form .
```
```txt
9:52AM INF client.go:67 updated platform version=0.79.0 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 duration=73.62995ms
```
At this point the platform form is published and functions as expected
when visiting the platform web interface.
When the user generates a platform, we need to know the platform ID it's
linked to in the holos server. If there is no platform with the same
name, the `holos generate platform` command should error out.
This is necessary because the first thing we want to show is pushing an
updated form to `holos server`. To update the web ui the CLI needs to
know the platform ID to update.
This patch modifies the generate command to obtain a list of platforms
for the org and verify the generated name matches one of the platforms
that already exists.
A future patch could have the `generate platform` command call the
`holos.platform.v1alpha1.PlatformService.CreatePlatform` method if the
platform isn't found.
Results:
```sh
holos generate platform bare
```
```txt
4:15PM INF generate.go:77 wrote platform.metadata.json version=0.77.1 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos/platform.metadata.json
4:15PM INF generate.go:89 generated platform bare version=0.77.1 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos
```
```sh
cat platform.metadata.json
```
```json
{
"id": "018f826d-85a8-751f-96d0-0d2bf70df909",
"name": "bare",
"display_name": "Bare Platform"
}
```