Compare commits

..

68 Commits

Author SHA1 Message Date
Jeff McCune
bac7aec0ba (#167) Restructure the bare platform
This patch restructures the bare platform in preparation for a
`Platform` kind of output from CUE in addition to the existing
`BuildPlan` kind.

This patch establishes a pattern where our own CUE defined code goes
into the two CUE module paths:

1. `internal/platforms/cue.mod/gen/github.com/holos-run/holos/api/v1alpha1`
2. `internal/platforms/cue.mod/pkg/github.com/holos-run/holos/api/v1alpha1`
3. `internal/platforms/cue.mod/usr/github.com/holos-run/holos/api/v1alpha1`

The first path is automatically generated from Go structs.  The second
path is where we override and provide additional cue level integration.

The third path is reserved for the end user to further refine and
constrain our definitions.
2024-05-07 16:53:00 -07:00
Jeff McCune
42f916af41 (#164) Use quay.io/holos/oauth2-proxy:v7.6.0-1-g77a03ae2
Custom build to set samesite=none on the csrf cookie.
2024-05-06 16:18:32 -07:00
Jeff McCune
47a5e237e0 (#162) Lint go, typescript, and proto3 files
This patch adds lint coverage for proto3 and typescript to keep our code
reasonably clean.  The go linter was already enabled.
2024-05-06 14:17:08 -07:00
Jeff McCune
1279e2351a (#162) Move Platform back to holos.v1alpha1
No need to have a separate package for the PlatformService and related
protobuf messages.
2024-05-06 13:47:37 -07:00
Jeff McCune
adb8177026 Merge pull request #166 from holos-run/jeff/165-deploy-holos
(#165) Deploy Holos to Dev
2024-05-06 11:23:48 -07:00
Jeff McCune
4e8fa5abda (#165) Bump dev deployment to 0.73.1 2024-05-06 11:22:24 -07:00
Jeff McCune
6894f45b6c (#165) Deploy Holos to Dev
This patch deploys holos to the dev environment on the k2 cluster.  It's
accessible at https://app.dev.k2.holos.run/ behind the auth proxy by
default.
2024-05-06 11:10:29 -07:00
Jeff McCune
89d25be837 (#161) Wrap main router outlet in <main></main> 2024-05-06 09:16:15 -07:00
Jeff McCune
5b33e48552 (#161) Reasonably advanced form modeling the reference platform
This form goes a good way toward capturing what we need to configure the
entire reference platform.  Elements and sections are responsive to
which cloud providers are selected, which achieves my goal of modeling a
reasonably advanced form using only JSON data produced by CUE.

To write the form via the API:

    cue export ./forms/platform/ --out json \
      | jq '{platform_id: "'${platformId}'", fields: .spec.fields}' \
      | grpcurl -H "x-oidc-id-token: $(holos token)" -d @ ${host}:443 \
      holos.platform.v1alpha1.PlatformService.PutForm
2024-05-04 20:16:09 -07:00
Jeff McCune
79e8ab639a (#161) Fix the FormGroup & Refactor API
The way we were organizing fields into section broke Formly validation.
This patch fixes the problem by using the recommended approach of
[Nested Forms][1].

This patch also refactors the PlatformService API to clean it up.
GetForm / PutForm are separated from the Platform methods.  Similarly
GetModel / PutModel are separated out and are specific to get and put
the model data.

NOTE: I'm not sure we should have separated out the platform service
into it's own protobuf package.  Seems maybe unnecessary.

❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"018f36fb-e3ff-7f7f-a5d1-7ca2bf499e94"}' jeff.app.dev.k2.holos.run:443 holos.platform.v1alpha1.PlatformService.GetModel
{
  "model": {
    "org": {
      "contactEmail": "platform@openinfrastructure.co",
      "displayName": "Open Infrastructure Services LLC",
      "domain": "ois.run",
      "name": "ois"
    },
    "privacy": {
      "country": "earth",
      "regions": [
        "us-east-2",
        "us-west-2"
      ]
    },
    "terms": {
      "didAgree": true
    }
  }
}

[1]: https://formly.dev/docs/examples/other/nested-formly-forms
2024-05-04 10:14:37 -07:00
Jeff McCune
a0cc673736 (#150) Wire up select and multi select boxes
This patch wires up a Select and a Multi Select box.  This patch also
establishes a decision as it relates to Formly TypeScript / gRPC Proto3
/ CUE definitions of the form data structure.  The decision is to use
gRPC as a transport for any JSON to avoid friction trying to fit Formly
types into Proto3 messages.

Note when using google.protobuf.Value messages with bufbuild/connect-es,
we need to round trip them one last time through JSON to get the
original JSON on the other side.  This is because connect-es preserves
the type discriminators in the case and value fields of the message.

Refer to: [Accessing oneof
groups](https://github.com/bufbuild/protobuf-es/blob/main/docs/runtime_api.md#accessing-oneof-groups)

NOTE: On the wire, carry any JSON as field configs for expedience.  I
attempted to reflect FormlyFieldConfig in protobuf, but it was too time
consuming.  The loosely defined Formly json data API creates significant
friction when joined with a well defined protobuf API.  Therefore, we do
not specify anything about the Forms API, convey any valid JSON, and
leave it up to CUE and Formly on the sending and receiving side of the
API.

We use CUE to define our own holos form elements as a subset of the loose
Formly definitions.  We further hope Formly will move toward a better JSON
data API, but it's unlikely.  Consider replacing Formly entirely and
building on top of the strongly typed Angular Dyanmic Forms API.

Refer to: https://github.com/ngx-formly/ngx-formly/blob/v6.3.0/src/core/src/lib/models/fieldconfig.ts#L15
Consider: https://angular.io/guide/dynamic-form

Usage:

Generate the form from CUE

    cue export ./forms/platform/ --out json | jq -cM | pbcopy

Store the form JSON in the config_values column of the platforms table.

View the form, and submit some data. Then get the data back out for use rendering the platform:

    grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"'${platformId}'"}' $holos holos.v1alpha1.PlatformService.GetConfig

```json
{
  "platform": {
    "spec": {
      "config": {
        "user": {
          "sections": {
            "org": {
              "fields": {
                "contactEmail": "jeff@openinfrastructure.co",
                "displayName": "Open Infrastructure Services LLC",
                "domain": "ois.run",
                "name": "ois"
              }
            },
            "privacy": {
              "fields": {
                "country": "earth",
                "regions": [
                  "us-east-2",
                  "us-west-2"
                ]
              }
            },
            "terms": {
              "fields": {
                "didAgree": true
              }
            }
          }
        }
      }
    }
  }
}
```
2024-05-03 10:42:03 -07:00
Jeff McCune
d06ecfadc8 (#150) Refactor PlatformService.GetConfig for use with CUE
Problem:
The GetConfig response value isn't directly usable with CUE without some
gymnastics.

Solution:
Refactor the protobuf definition and response output to make the user
defined and supplied config values provided by the API directly usable
in the CUE code that defines the platform.

Result:

The top level platform config is directly usable in the
`internal/platforms/bare` directory:

    grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"'${platformID}'"}' $host \
      holos.v1alpha1.PlatformService.GetConfig \
      > platform.holos.json

Vet the user supplied data:

    cue vet ./ -d '#PlatformConfig' platform.holos.json

Build the holos component.  The ConfigMap consumes the user supplied
data:

    cue export --out yaml -t cluster=k2 ./components/configmap platform.holos.json \
      | yq .spec.components

Note the data provided by the input form is embedded into the
ConfigMap managed by Holos:

```yaml
KubernetesObjectsList:
  - metadata:
      name: platform-configmap
    apiObjectMap:
      ConfigMap:
        platform: |
          metadata:
            name: platform
            namespace: default
            labels:
              app.holos.run/managed: "true"
          data:
            platform: |
              kind: Platform
              spec:
                config:
                  user:
                    sections:
                      org:
                        fields:
                          contactEmail: jeff@openinfrastructure.co
                          displayName: Open Infrastructure Services LLC
                          domain: ois.run
                          name: ois
              apiVersion: app.holos.run/v1alpha1
              metadata:
                name: bare
                labels: {}
                annotations: {}
              holos:
                flags:
                  cluster: k2
          kind: ConfigMap
          apiVersion: v1
    Skip: false
```
2024-05-02 06:39:33 -07:00
Jeff McCune
64a117b0c3 (#150) Add PlatformService.GetConfig and refactor ConfigValues proto
Problem:
The use of google.protobuf.Any was making it awkward to work with the
data provided by the user.  The structure of the form data is defined by
the platform engineer, so the intent of Any was to wrap the data in a
way we can pass over the network and persist in the database.

The escaped JSON encoding was problematic and error prone to decode on
the other end.

Solution:
Define the Platform values as a two level map with string keys, but with
protobuf message fields "sections" and "fields" respectively.  Use
google.protobuf.Value from the struct package to encode the actual
value.

Result:
In TypeScript, google.protobuf.Value encodes and decodes easily to a
JSON value.  On the go side, connect correctly handles the value as
well.

No more ugly error prone escaping:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"'${platformId}'"}' $host holos.v1alpha1.PlatformService.GetConfig
{
  "sections": {
    "org": {
      "fields": {
        "contactEmail": "jeff@openinfrastructure.co",
        "displayName": "Open Infrastructure Services LLC",
        "domain": "ois.run",
        "name": "ois"
      }
    }
  }
}
```

This return value is intended to be directly usable in the CUE code, so
we may further nest the values into a platform.spec key.
2024-05-01 21:30:30 -07:00
Jeff McCune
cf006be9cf (#150) Add SystemService DropTables and SeedDatabase
Makes it easier to reset the database and give Gary and Nate access to
the same organization I'm in so they can provide feedback.
2024-05-01 14:30:13 -07:00
Jeff McCune
45ad3d8e63 (#150) Fix 500 error when config values aren't provided
AddPlatform was failing with a 500 error trying to decode a nil byte
slice when adding a platform without providing any values.
2024-05-01 11:31:25 -07:00
Jeff McCune
441c968c4f (#150) Look up user by iss sub, not email.
Also log when orgs are created.
2024-05-01 10:02:08 -07:00
Jeff McCune
99f2763fdf (#150) Store Platform Config Form and Values as JSON
This patch changes the backend to store the platform config form
definition and the config values supplied by the form as JSON in the
database.

The gRPC API does not change with this patch, but may need to depending
on how this works and how easy it is to evolve the data model and add
features.
2024-05-01 09:11:53 -07:00
Jeff McCune
1312395a11 (#150) Fix platforms page links
The links were hard to click.  This makes the links a much larger click
target following the example at https://material.angular.io/components/list/overview#navigation-lists
2024-05-01 08:51:29 -07:00
Jeff McCune
615f147bcb (#150) Add PutPlatformConfig to store the config values
This patch is a work in progress wiring up the form to put the values to
the holos server using grpc.

In an effort to simplify the platform configuration, the structure is a
two level map with the top level being configuration sections and the
second level being the fields associated with the config section.

To support multiple kinds of values and field controls, the values are
serialized to JSON for rpc over the network and for storage in the
database.  When they values are used, either by the UI or by the `holos
render` command, they're to be unmarshalled and in-lined into the
Platform Config data structure.

Pick back up ensuring the Platform rpc handler correctly encodes and
decodes the structure to the database.

Consider changing the config_form and config_values fields to JSON field
types in the database.  It will likely make working with this a lot
easier.

With this patch we're ready to wire up the holos render command to fetch
the platform configuration and create the end to end demo.

Here's essentially what the render command will fetch and lay down as a
json file for CUE:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"018f2c4e-ecde-7bcb-8b89-27a99e6cc7a1"}' jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.GetPlatform | jq .platform.config.values
{
  "sections": {
    "org": {
      "values": {
        "contactEmail": "\"platform@openinfrastructure.co\"",
        "displayName": "\"Open Infrastructure Services  LLC\"",
        "domain": "\"ois.run\"",
        "name": "\"ois\""
      }
    }
  }
}
```
2024-04-30 20:21:15 -07:00
Jeff McCune
d0ad3bfc69 (#150) Add Platform Detail to edit platform config
This patch adds a /platform/:id route path to a PlatformDetail
component.  The platform detail component calls the GetPlatform method
given the platform ID and renders the platform config form on the detail
tab.

The submit button is not yet wired up.

The API for adding platforms changes, allowing raw json bytes using the
RawConfig.  The raw bytes are not presented on the read path though,
calling GetPlatforms provides the platform and the config form inline in
the response.

Use the `raw_config` field instead of `config` when creating the form
data.

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d @ jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.AddPlatform <<EOF
{
  "platform": {
    "org_id": "018f27cd-e5ac-7f98-bfe1-2dbab208a48c",
    "name": "bare2",
    "raw_config": {
      "form": "$(cue export ./forms/platform/ --out json | jq -cM | base64 -w0)"
    }
  }
}
EOF
```
2024-04-30 14:02:49 -07:00
Jeff McCune
fe58a33747 (#150) Add holos.v1alpha1.PlatformService.GetForm
The GetForm method is intended for the Angular frontend to get
[FormlyFieldConfig][1] data for each section of the Platform config.

[1]: https://formly.dev/docs/api/core/#formlyfieldconfig

Steps to exercise for later testing:

Add the form definition to the database:

```
grpcurl -H "x-oidc-id-token: $(holos token)" -d @ jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.AddPlatform <<EOF
{
  "platform": {
    "org_id": "018f27cd-e5ac-7f98-bfe1-2dbab208a48c",
    "name": "bare${RANDOM}",
    "config": {
      "form": "$(cue export ./forms/platform/ --out json | jq -cM | base64 -w0)"
    }
  }
}
EOF
```

Get the form definition back out:

```

❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"018f2bc1-6590-7670-958a-9f3bc02b658f"}' jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.GetForm
{
  "apiVersion": "forms.holos.run/v1alpha1",
  "kind": "PlatformForm",
  "metadata": {
    "name": "bare"
  },
  "spec": {
    "sections": [
      {
        "name": "org",
        "displayName": "Organization",
        "description": "Organization config values are used to derive more specific configuration values throughout the platform.",
        "fieldConfigs": [
          {
            "key": "name",
            "type": "input",
            "props": {
              "label": "Name",
              "placeholder": "example",
              "description": "DNS label, e.g. 'example'",
              "required": true
            }
          },
          {
            "key": "domain",
            "type": "input",
            "props": {
              "label": "Domain",
              "placeholder": "example.com",
              "description": "DNS domain, e.g. 'example.com'",
              "required": true
            }
          },
          {
            "key": "displayName",
            "type": "input",
            "props": {
              "label": "Display Name",
              "placeholder": "Example Organization",
              "description": "Display name, e.g. 'Example Organization'",
              "required": true
            }
          },
          {
            "key": "contactEmail",
            "type": "input",
            "props": {
              "label": "Contact Email",
              "placeholder": "platform-team@example.com",
              "description": "Technical contact email address",
              "required": true
            }
          }
        ]
      }
    ]
  }
}
```

References

```
❯ cue export ./forms/platform/ --out yaml | yq
apiVersion: forms.holos.run/v1alpha1
kind: PlatformForm
metadata:
  name: bare
spec:
  sections:
    - name: org
      displayName: Organization
      description: Organization config values are used to derive more specific configuration values throughout the platform.
      fieldConfigs:
        - key: name
          type: input
          props:
            label: Name
            placeholder: example
            description: DNS label, e.g. 'example'
            required: true
        - key: domain
          type: input
          props:
            label: Domain
            placeholder: example.com
            description: DNS domain, e.g. 'example.com'
            required: true
        - key: displayName
          type: input
          props:
            label: Display Name
            placeholder: Example Organization
            description: Display name, e.g. 'Example Organization'
            required: true
        - key: contactEmail
          type: input
          props:
            label: Contact Email
            placeholder: platform-team@example.com
            description: Technical contact email address
            required: true
```
2024-04-29 14:24:16 -07:00
Jeff McCune
26e537e768 (#150) Add platform config form, values, cue
This patch adds 4 fields to the Platform table:

 1. Config Form represents the JSON FormlyFieldConfig for the UI.
 2. Config CUE represents the CUE file containing a definition the
    Config Values must unify with.
 3. Config Definition is the CUE definition variable name used to unify
    the values with the cue code.  Should be #PlatformSpec in most
    cases.
 4. Config Values represents the JSON values provided by the UI.

The use case is the platform engineer defines the #PlatformSpec in cue,
and provides the form field config.  The platform engineer then provides
1-3 above when adding or updating a Platform.

The UI then presents the form to the end user and provides values for 4
when the user submits the form.

This patch also refactors the AddPlatform method to accept a Platform
message.  To do so we make the id field optional since it is server
assigned.

The patch also adds a database constraint to ensure platform names are
unique within the scope of an organization.

Results:

Note how the CUE representation of the Platform Form is exported to JSON
then converted to a base64 encoded string, which is the protobuf JSON
representation of a bytes[] value.

```
grpcurl -H "x-oidc-id-token: $(holos token)" -d @ jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.AddPlatform <<EOF
{
  "platform": {
    "id": "0d3dc0c0-bbc8-41f8-8c6e-75f0476509d6",
    "org_id": "018f27cd-e5ac-7f98-bfe1-2dbab208a48c",
    "name": "bare",
    "config": {
      "form": "$(cd internal/platforms/bare && cue export ./forms/platform/ --out json | jq -cM | base64 -w0)"
    }
  }
}
EOF
```

Note the requested platform ID is ignored.

```
{
  "platforms": [
    {
      "id": "018f2af9-f7ba-772a-9db6-f985ece8fed1",
      "timestamps": {
        "createdAt": "2024-04-29T17:49:36.058379Z",
        "updatedAt": "2024-04-29T17:49:36.058379Z"
      },
      "name": "bare",
      "creator": {
        "id": "018f27cd-e591-7f98-a9d2-416167282d37"
      },
      "config": {
        "form": "eyJhcGlWZXJzaW9uIjoiZm9ybXMuaG9sb3MucnVuL3YxYWxwaGExIiwia2luZCI6IlBsYXRmb3JtRm9ybSIsIm1ldGFkYXRhIjp7Im5hbWUiOiJiYXJlIn0sInNwZWMiOnsic2VjdGlvbnMiOlt7Im5hbWUiOiJvcmciLCJkaXNwbGF5TmFtZSI6Ik9yZ2FuaXphdGlvbiIsImRlc2NyaXB0aW9uIjoiT3JnYW5pemF0aW9uIGNvbmZpZyB2YWx1ZXMgYXJlIHVzZWQgdG8gZGVyaXZlIG1vcmUgc3BlY2lmaWMgY29uZmlndXJhdGlvbiB2YWx1ZXMgdGhyb3VnaG91dCB0aGUgcGxhdGZvcm0uIiwiZmllbGRDb25maWdzIjpbeyJrZXkiOiJuYW1lIiwidHlwZSI6ImlucHV0IiwicHJvcHMiOnsibGFiZWwiOiJOYW1lIiwicGxhY2Vob2xkZXIiOiJleGFtcGxlIiwiZGVzY3JpcHRpb24iOiJETlMgbGFiZWwsIGUuZy4gJ2V4YW1wbGUnIiwicmVxdWlyZWQiOnRydWV9fSx7ImtleSI6ImRvbWFpbiIsInR5cGUiOiJpbnB1dCIsInByb3BzIjp7ImxhYmVsIjoiRG9tYWluIiwicGxhY2Vob2xkZXIiOiJleGFtcGxlLmNvbSIsImRlc2NyaXB0aW9uIjoiRE5TIGRvbWFpbiwgZS5nLiAnZXhhbXBsZS5jb20nIiwicmVxdWlyZWQiOnRydWV9fSx7ImtleSI6ImRpc3BsYXlOYW1lIiwidHlwZSI6ImlucHV0IiwicHJvcHMiOnsibGFiZWwiOiJEaXNwbGF5IE5hbWUiLCJwbGFjZWhvbGRlciI6IkV4YW1wbGUgT3JnYW5pemF0aW9uIiwiZGVzY3JpcHRpb24iOiJEaXNwbGF5IG5hbWUsIGUuZy4gJ0V4YW1wbGUgT3JnYW5pemF0aW9uJyIsInJlcXVpcmVkIjp0cnVlfX0seyJrZXkiOiJjb250YWN0RW1haWwiLCJ0eXBlIjoiaW5wdXQiLCJwcm9wcyI6eyJsYWJlbCI6IkNvbnRhY3QgRW1haWwiLCJwbGFjZWhvbGRlciI6InBsYXRmb3JtLXRlYW1AZXhhbXBsZS5jb20iLCJkZXNjcmlwdGlvbiI6IlRlY2huaWNhbCBjb250YWN0IGVtYWlsIGFkZHJlc3MiLCJyZXF1aXJlZCI6dHJ1ZX19XX1dfX0K"
      }
    }
  ]
}
```
2024-04-29 10:53:23 -07:00
Jeff McCune
ad70a6c4fe (#150) Add holos.v1alpha1.PlatformService.AddPlatform
This patch adds a basic AddPlatform method that adds a platform with a
name and a display name.

Next steps are to add fields for the Platform Config Form definition and
the Platform Config values submitted from the form.
2024-04-29 09:35:49 -07:00
Jeff McCune
22a04da6bb (#150) Add holos.v1alpha1.PlatformService.GetPlatforms
Next step: AddPlatform

Also consider extracting the queries to get the requested org_id to a
helper function.  This will likely eventually move to an interceptor
because every request is org scoped and needs authorization checks
against the org.

```
grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"org_id":"018f27cd-e5ac-7f98-bfe1-2dbab208a48c"}' jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.GetPlatforms
```
2024-04-28 20:21:32 -07:00
Jeff McCune
dc97fe0ff0 (#150) Define a PlatformForm for platform design
Problem:
Platform engineers need the ability to define custom input fields for
their own platform level configuration values.  The holos web UI needs
to present the platform config values in a clean way.  The values
entered on the form need to make their way into the top level
Platform.spec field for use across all components and clusters in the
platform.

Solution:
Define a Platform Form in a forms cue package.  The output of this
definition is intended to be sent to the holos server to provide to the
web UI.

Result:
Platform engineers can define their platform config input values in
their infrastructure repository.  For example, the bare platform form
inputs are defined at `platforms/bare/forms/platform/platform-form.cue`.

This cue file produces [FormlyFieldConfig][1] output.

```console
cue export ./forms/platform/ --out yaml
```

```yaml
apiVersion: forms.holos.run/v1alpha1
kind: PlatformForm
metadata:
  name: bare
spec:
  sections:
    - name: org
      displayName: Organization
      description: Organization config values are used to derive more specific configuration values throughout the platform.
      fieldConfigs:
        - key: name
          type: input
          props:
            label: Name
            placeholder: example
            description: DNS label, e.g. 'example'
            required: true
        - key: domain
          type: input
          props:
            label: Domain
            placeholder: example.com
            description: DNS domain, e.g. 'example.com'
            required: true
        - key: displayName
          type: input
          props:
            label: Display Name
            placeholder: Example Organization
            description: Display name, e.g. 'Example Organization'
            required: true
        - key: contactEmail
          type: input
          props:
            label: Contact Email
            placeholder: platform-team@example.com
            description: Technical contact email address
            required: true
```

Next Steps:
Add a holos subcommand to produce the output and store it in the
backend.  Wire the front end to fetch the form config from the backend.

[1]: https://formly.dev/docs/api/core#formlyfieldconfig
2024-04-28 11:25:06 -07:00
Jeff McCune
9ca97c6e01 Merge pull request #148 from holos-run/jeff/147-cue-oom
(#147) Add holos render --print-instances flag
2024-04-26 16:31:14 -07:00
Jeff McCune
924653e240 (#150) Bare Platform
This patch adds a bare platform that does nothing but render a configmap
containing the platform config structure itself.

The definition of the platform structure is firming up.  The platform
designer, which may be a holos customer, is responsible for defining the
structure of the `platform.spec` output field.

Us holos developers have a reserved namespace to add configuration
fields and data in the `platform.holos` output file.

Beyond these two fields, the platform config structure has TypeMeta and
ObjectMeta fields similar to a kubernetes api object to support
versioning the platform config data, naming the platform, annotating the
platform, and labeling the platform.

The path forward from here is to:

 1. Eventually move the stable definitions into a CUE module that gets
    imported into the user's package.
 2. As a platform designer, add the organization field to the
    #PlatformSpec definition as a CUE definition.
 3. As a platform designer, add the organization field Form data
    structure as a JSON file.
 4. Add an API to upload the #PlatformSpec cue file and the
    #PlatformSpec form json file to the saas backend.
 5. Wire up Angular to pull the form json from the API and render the
    form.
 6. Wire up Angular to write the form data to a gRPC service method.
 7. Wire up the `holos cli` to read the form data from a gRPC service
    method.
 8. Tie it all together where the holos cli renders the configmap.
2024-04-26 16:14:30 -07:00
Jeff McCune
59d48f8599 (#146) Platform Config Mock Up
This patch adds a mock up of the platform config.  The goal is to use
this to connect to an anemic example platform built from `holos init`.
2024-04-26 11:29:58 -07:00
Jeff McCune
90f8eab816 (#144) Tidy go.mod and package.json 2024-04-25 19:14:20 -07:00
Jeff McCune
9ae45e260d (#147) Add holos render --print-instances flag
To enumerate all of the instances that could be run in separate
processes with xargs instead of run in the for loop in the Builder Run
method.
2024-04-25 13:59:10 -07:00
Jeff McCune
aee15f95e2 Merge pull request #145 from holos-run/jeff/144-organization-selector
(#144) Profile Button
2024-04-25 09:55:55 -07:00
Jeff McCune
1c540ac375 (#144) Profile Button and Organization Selector
This patch adds an organization "selector" that's really just a place
holder.  The active organization is the last element in the list
returned by the GetCallerOrganizations method for now.

The purpose is to make sure we have the structure in place for more than
one organizations without needing to implement full support for the
feature at this early stage.

The Angular frontend is expected to call the activeOrg() method of the
OrganizationService.  In the future this could store the state of which
organization the user has selected.  The purpose is to return an org id
to send as a request parameter for other requests.

Note this patch also implements refresh behavior.  The list of orgs is
fetched once on application load.  If there is no user, or the user has
zero orgs, the user is created and an organization is added with them as
an owner.  This is accompished using observable pipes.

The pipe is tied to a refresh behavior.  Clicking the org button
triggers the refresh behavior, which executes the pipe again and
notifies all subscribers.

This works quite well and should be idiomatic angular / rxjs.  Clicking
the button automatically updates the UI after making the necessary API
calls.
2024-04-25 09:55:13 -07:00
Jeff McCune
5b0e883ac9 (#144) Get or Create the orgranization
This patch adds the OrganizationService to the Angular front end and
displays a simple list of the organizations the user is a member of in
the profile card.

There isn't a service yet to return the currently selected
organization, but that could be a simple method to return the most
recent entry in the list until we put something more complicated in
place like local storage of what the user has selected.

It may make sense to put a database constraint on the number of
organizations until we implement the feature later, it's too early to do
so now, I just want to make sure it's possible to add later.
2024-04-25 07:02:17 -07:00
Jeff McCune
9a2519af71 (#144) Make the linter happy 2024-04-24 13:41:45 -07:00
Jeff McCune
9b9ff601c0 (#144) Call GetCallerClaims once instead of multiple times
Problem:
When loading the page the GetCallerClaims rpc method is called multiple
times unnecessarily.

Solution:
Use [shareReplay][1] to replay the last observable event for all
subscribers, including subscribers coming late to the party.

Result:
Network inspector in chrome indicates GetCallerClaims is called once and
only once.

[1]: https://rxjs.dev/api/operators/shareReplay
2024-04-24 12:44:44 -07:00
Jeff McCune
2f798296dc (#144) Profile Button
This patch adds a ProfileButton component which makes a ConnectRPC gRPC
call to the `holos.v1alpha1.UserService.GetCallerClaims` method and
renders the profile button based on the claims.

Note, in the network inspector there are two API calls to
`holos.v1alpha1.UserService.GetCallerClaims` which is unfortunate.  A
follow up patch might be good to fix this.
2024-04-24 12:23:54 -07:00
Jeff McCune
2b2ff63cad (#144) Connect /ui to ng serve for hot reload
Problem:
It's slow to build the angular app, compile it into the go executable,
copy it to the pod, then restart the server.

Solution:
Configure the mesh to route /ui to `ng serve` running on my local
host.

Result:
Navigating to https://jeff.app.dev.k2.holos.run/ui gets responses from
the ng development server.

Use:

    ng serve --host 0.0.0.0
2024-04-23 20:30:02 -07:00
Jeff McCune
3b135c09f3 (#144) Make a ConnectRPC call to the GetUserClaims method
This patch wires up an Angular RxJS Observable to the result of a gRPC
call to the `holos.v1alpha1.UserService.GetCallerClaims` method.

The implementation is a combination of [this connect example][1] and the
official [angular data][2] guide.

[1]: https://github.com/connectrpc/examples-es/tree/main/angular
[2]: https://angular.io/start/start-data#configuring-the-shippingcomponent-to-use-cartservice
2024-04-23 17:18:35 -07:00
Jeff McCune
28813eba5b (#126) v0.69.0 2024-04-23 10:24:58 -07:00
Jeff McCune
02ff765f54 Merge pull request #143 from holos-run/jeff/126-registration
(#126) Minimal API to register users and organizations
2024-04-23 09:00:07 -07:00
Jeff McCune
fe8a806132 (#126) Refactor to GetCallerX / CreateCallerX
This patch simplifies the user and organization registration and query
for the UI.  The pattern clients are expected to follow is to create if
the get fails.  For example, the following pseudo-go-code is the
expected calling convention:

    var entity *ent.User
    entity, err := Get()
    if err != nil {
      if ent.MaskNotFound(err) == nil {
        entity = Create()
      } else {
        return err
      }
    }
    return entity

This patch adds the following service methods.  For initial
registration, all input data comes from the id token claims of the
authenticated user.

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 list | xargs -n1 grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 list
holos.v1alpha1.OrganizationService.CreateCallerOrganization
holos.v1alpha1.OrganizationService.GetCallerOrganizations
holos.v1alpha1.UserService.CreateCallerUser
holos.v1alpha1.UserService.GetCallerClaims
holos.v1alpha1.UserService.GetCallerUser
```
2024-04-23 08:43:23 -07:00
Jeff McCune
6626d58301 (#126) Add OrganizationService
Next step after this is to simplify the calling convention to a get
followed by a create if the get fails.
2024-04-23 05:28:07 -07:00
Jeff McCune
cb0911e890 (#126) Add holos.v1alpha1.UserService.GetUser
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 holos.v1alpha1.UserService.GetUser
{
  "user": {
    "id": "018f07f4-4f9c-7b69-9d9e-07bf7bb4fe33",
    "email": "jeff@openinfrastructure.co",
    "name": "Jeff McCune",
    "timestamps": {
      "createdAt": "2024-04-22T22:36:42.780492Z",
      "updatedAt": "2024-04-22T22:36:42.780492Z"
    }
  }
}
2024-04-22 16:49:25 -07:00
Jeff McCune
3745a68dc5 (#126) Add unique index on user iss sub fields
The server will frequently look up the user record given the iss and sub
claims from the id token, index them and make sure the combination of
the two is unique.
2024-04-22 16:14:40 -07:00
Jeff McCune
fd64830476 (#126) Rename HolosService to UserService
Organize services by the resource they manage.
2024-04-22 16:05:32 -07:00
Jeff McCune
1ee0fa9c1f (#126) User Registration via API
With this patch user registration works with grpcurl.  Nothing in the
web UI yet.

```
grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 holos.v1alpha1.HolosService.RegisterUser
```

Cannot register twice:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 holos.v1alpha1.HolosService.RegisterUser
ERROR:
  Code: FailedPrecondition
  Message: user.go:26: ent: constraint failed: ERROR: duplicate key value violates unique constraint "users_email_key" (SQLSTATE 23505)
```

GetUserClaims works though:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 holos.v1alpha1.HolosService.GetUserClaims
{
  "iss": "https://login.ois.run",
  "sub": "261773693724656988",
  "email": "jeff@openinfrastructure.co",
  "emailVerified": true,
  "name": "Jeff McCune"
}
```
2024-04-22 15:38:07 -07:00
Jeff McCune
8fab325b0a (#126) Add gRPC reflection
So grpcurl works as expected:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 list
holos.v1alpha1.HolosService
```
2024-04-22 15:02:08 -07:00
Jeff McCune
858ffad913 (#126) Add holos token command for grpcurl 2024-04-22 14:54:09 -07:00
Jeff McCune
62735b99e7 (#126) Update Tiltfile to use holos.run for dev
This patch updates the Tiltfile to use the holos.run domain which is
integrated with the default Gateway.
2024-04-22 13:42:18 -07:00
Jeff McCune
29ab9c6300 (#141) Install provisioner helper.rb from entrypoint
And add a script to reset the choria provisioner credentials and config.
2024-04-22 13:20:38 -07:00
Jeff McCune
debc01c7de (#141) Fix Incorrect Provisioning Token foo given
The `make-provisioner-jwt` incorrectly used the choria broker password
as the provisioning token.  In the reference [setup.sh][1] both the
token and the `broker_provisioning_password` are set to `s3cret` so I
confused the two, but they are actually different values.

This patch ensures the provisioning token configured in
`provisioner.yaml` matches the token embedded into the provisioning.jwt
file using `choria jwt provisioning` via the `make-provisioner-jwt`
script.

[1]: 6dbc8fd105/example/setup/templates/provisioner/provisioner.yaml (L6)
2024-04-22 12:31:10 -07:00
Jeff McCune
c07f35ecd6 (#141) Fix holos controller invalid websocket connection error
Problem:
When the ingress default Gateway AuthorizationPolicy/authpolicy-custom
rule is in place the choria machine room holos controller fails to
connect to the provisioner broker with the following error:

```
❯ holos controller run --config=agent.cfg
WARN[0000] Starting controller version 0.68.1 with config file /home/jeff/workspace/holos-run/holos/hack/choria/agent/agent.cfg  leader=false
WARN[0000] Switching to provisioning configuration due to build defaults and missing /home/jeff/workspace/holos-run/holos/hack/choria/agent/agent.cfg
WARN[0000] Setting anonymous TLS mode during provisioning  component=server connection=coffee.home identity=coffee.home
WARN[0000] Initial connection to the Broker failed on try 1: invalid websocket connection  component=server connection=coffee.home identity=coffee.home
WARN[0000] Initial connection to the Broker failed on try 2: invalid websocket connection  component=server connection=coffee.home identity=coffee.home
WARN[0002] Initial connection to the Broker failed on try 3: invalid websocket connection  component=server connection=coffee.home identity=coffee.home
```

This problem is caused because the provisioning token url is set to
`wss://jeff.provision.dev.k2.holos.run:443` which has the port number
specified.

Solution:
Follow the upstream istio guidance of [Writing Host Match Policies][1]
to match host headers with or without the port specified.

Result:
The controller is able to connect to the provisioner broker:

[1]: https://istio.io/latest/docs/ops/best-practices/security/#writing-host-match-policies
2024-04-22 12:31:10 -07:00
Jeff McCune
c8f528700c (#141) Fix error: do not know how to handle choria_provisioning purpose token
Solution:
remove the plugin.security.choria.ca setting
2024-04-22 12:30:16 -07:00
Jeff McCune
896248c237 (#141) Try and connect holos controller to the provisioner
Running into error:

time="2024-04-20T03:23:19Z" level=warning msg="Denying connection: verified error: do not know how to handle choria_provisioning purpose token, unverified error: <nil>" component=authentication remote="10.244.1.51:56338" stage=check
time="2024-04-20T03:23:19Z" level=error msg="192.168.2.21/10.244.1.51:56338 - wid:367 - authentication error" component=network_broker
2024-04-22 12:29:56 -07:00
Jeff McCune
74a181db21 (#133) Add missing Choria Provisioner deployment 2024-04-19 15:14:31 -07:00
Jeff McCune
ba10113342 (#133) Fix tls error when connecting to provisioner websocket
This problem fixes an error where the istio ingress gateway proxy failed
to verify the TLS certificate presented by the choria broker upstream
server.

    kubectl logs choria-broker-0

    level=error msg="websocket: TLS handshake error from 10.244.1.190:36142: remote error: tls: unknown certificate\n"

Istio ingress logs:

    kubectl -n istio-ingress logs -l app=istio-ingressgateway -f | grep --line-buffered '^{' | jq .

    "upstream_transport_failure_reason": "TLS_error:|268435581:SSL_routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED:TLS_error_end:TLS_error_end"

Client curl output:

    curl https://jeff.provision.dev.k2.holos.run

    upstream connect error or disconnect/reset before headers. retried and the latest reset reason: remote connection failure, transport failure reason: TLS_error:|268435581:SSL routines:OPENSSL_i
nternal:CERTIFICATE_VERIFY_FAILED:TLS_error_end:TLS_error_end

Explanation of error:

Istio defaults to expecting a tls certificate matching the downstream
host/authority which isn't how we've configured Choria.

Refer to [ClientTLSSettings][1]

> A list of alternate names to verify the subject identity in the
> certificate. If specified, the proxy will verify that the server
> certificate’s subject alt name matches one of the specified values. If
> specified, this list overrides the value of subject_alt_names from the
> ServiceEntry. If unspecified, automatic validation of upstream presented
> certificate for new upstream connections will be done based on the
> downstream HTTP host/authority header, provided
> VERIFY_CERTIFICATE_AT_CLIENT and ENABLE_AUTO_SNI environmental variables
> are set to true.

[1]: https://istio.io/latest/docs/reference/config/networking/destination-rule/#ClientTLSSettings
2024-04-19 13:13:09 -07:00
Jeff McCune
eb0207c92e (#133) Choria Provisioner
This patch is a work in progress to configure the provisioner to connect
to the broker.  Services and deployments are prefixed with choria for
clarity.
2024-04-19 13:13:08 -07:00
Jeff McCune
0fbcee8119 (#133) Extend the life of the Platform Issuer CA
The platform issuer root CA was set to expire after 90 days, the default
value.  This is too short.

Extend the life of the root CA beyond 100 years.
2024-04-19 11:29:17 -07:00
Jeff McCune
ce8bc798f6 (#133) Exclude nats and provision hosts from the auth proxy
Problem:
The identity aware auth proxy attached to the default gateway is
blocking access to NATS and the Choria Provisioner cluster.

Solution:
Add configuration that causes the project hosts to get added to the
exclusion list of the AuthorizationPolicy/authproxy-custom rule.

Result:
Requests bypass the auth proxy and go straight to the backend.  The
rules look like:

    kubectl get authorizationpolicy authproxy-custom -o yaml

```yaml
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: authproxy-custom
  namespace: istio-ingress
  labels:
    app.kubernetes.io/name: authproxy-custom
    app.kubernetes.io/part-of: istio-ingressgateway
spec:
  action: CUSTOM
  provider:
    name: ingressauth
  rules:
  - to:
    - operation:
        notHosts:
        - login.ois.run
        - vault.core.ois.run
        - provision.holos.run
        - nats.holos.run
        - provision.dev.holos.run
        - nats.dev.holos.run
        - jeff.provision.dev.holos.run
        - jeff.nats.dev.holos.run
        - gary.provision.dev.holos.run
        - gary.nats.dev.holos.run
        - nate.provision.dev.holos.run
        - nate.nats.dev.holos.run
        - provision.k2.holos.run
        - nats.k2.holos.run
        - provision.dev.k2.holos.run
        - nats.dev.k2.holos.run
        - jeff.provision.dev.k2.holos.run
        - jeff.nats.dev.k2.holos.run
        - gary.provision.dev.k2.holos.run
        - gary.nats.dev.k2.holos.run
        - nate.provision.dev.k2.holos.run
        - nate.nats.dev.k2.holos.run
    when:
    - key: request.headers[x-oidc-id-token]
      notValues:
      - '*'
  selector:
    matchLabels:
      istio: ingressgateway
```
2024-04-19 06:32:11 -07:00
Jeff McCune
996195d651 (#137) Fix ArgoCD PKCE login small comment 2024-04-18 14:39:13 -07:00
Jeff McCune
f00b29d3a3 (#137) Fix ArgoCD PKCE login
This patch configures ArgoCD to log in via PKCE.

Note the changes are primarily in platform.site.cue and ensuring the
emailDomain is set properly.  Note too the redirect URL needs to be
`/pkce/verify` when PKCE is enabled.  Finally, if the setting is
reconfigured make sure to clear cookies otherwise the incorrect
`/auth/callback` path may be used.
2024-04-18 14:37:06 -07:00
Jeff McCune
a6756ecf11 (#132) Update go deps to fix Machine Room 2024-04-18 13:35:58 -07:00
Jeff McCune
ef7ec30037 (#132) Use machine-room main branch
Our patch to use Args got merged.
2024-04-18 11:38:51 -07:00
Jeff McCune
1642787825 (#101) Fix port names in servers must be unique: duplicate name https
Problem:
Port names in the default Gateway.spec.servers.port field must be unique
across all servers associated with the workload.

Solution:
Append the fully qualified domain name with dots replaced with hyphens.

Result:
Port name is unique.
2024-04-18 11:21:05 -07:00
Jeff McCune
f83781480f (#101) Do not add Gateway.spec.servers for other clusters
Problem:
The default gateway in one cluster gets server entries for all hosts in
the problem.  This makes the list unnecessarily large with entries for
clusters that should not be handled on the current cluster.

For example, the k2 cluster has gateway entries to route hosts for k1,
k3, k4, k5, etc...

Solution:
Add a field to the CertInfo definition representing which clusters the
host is valid on.

Result:
Hosts which are valid on all clusters, e.g. login.ois.run, have all
project clusters added to the clusters field of the CertInfo.  Hosts
which are valid on a single cluster have the coresponding single entry
added.

When building resources, holos components should check if `#ClusterName`
is a valid field of the CertInfo.clusters field.  If so, the host is
valid for the current cluster.  If not, the host should be omitted from
the current cluster.
2024-04-18 11:10:16 -07:00
Jeff McCune
9b70205855 (#101) Use letsencrypt production instead of staging
Certificates issue OK from staging, switching to production.
2024-04-18 10:36:28 -07:00
Jeff McCune
0e4bf3c144 (#101) Manage certs on all clusters
We're going to do a big re-issue so might as well do it once so we don't
have to re-issue again to add more clusters to existing projects.
2024-04-18 10:16:55 -07:00
Jeff McCune
1241c74b41 (#101) Do not add the project name as a project host
Doing so forces unnecessary hosts for some projects.  For example,
iam.ois.run is useless for the iam project, the primary project host is
login to build login.ois.run.

Some projects may not need any hosts as well.

Better to let the user specify `project: foo: hosts: foo: _` if they
want it.
2024-04-18 09:59:21 -07:00
229 changed files with 26646 additions and 1556 deletions

View File

@@ -87,6 +87,8 @@ test: ## Run tests.
.PHONY: lint
lint: ## Run linters.
buf lint
cd internal/frontend/holos && ng lint
golangci-lint run
.PHONY: coverage

View File

@@ -99,6 +99,7 @@ docker_build_with_restart(
'--listen-port={}'.format(listen_port),
'--oidc-issuer=https://login.ois.run',
'--oidc-audience=262096764402729854@holos_platform',
'--log-level=debug',
'--metrics-port={}'.format(metrics_port),
],
dockerfile='./hack/tilt/Dockerfile',
@@ -190,7 +191,7 @@ k8s_resource(
],
resource_deps=[compile_id],
links=[
link('https://{}.holos.dev.k2.ois.run/app/'.format(developer), "Holos Web UI")
link('https://{}.app.dev.k2.holos.run/ui/'.format(developer), "Holos Web UI")
],
)
@@ -200,11 +201,6 @@ k8s_resource(
new_name=auth_id,
objects=[
'{}:virtualservice'.format(holos_server),
'{}-allow-groups:authorizationpolicy'.format(holos_server),
'{}-allow-nothing:authorizationpolicy'.format(holos_server),
'{}-allow-well-known-paths:authorizationpolicy'.format(holos_server),
'{}-auth:authorizationpolicy'.format(holos_server),
'{}:requestauthentication'.format(holos_server),
],
)

View File

@@ -9,8 +9,9 @@ import (
type BuildPlan struct {
TypeMeta `json:",inline" yaml:",inline"`
// Metadata represents the holos component name
Metadata ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Spec BuildPlanSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
Metadata ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Spec BuildPlanSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
Platform map[string]any `json:"platform,omitempty" yaml:"platform,omitempty"`
}
type BuildPlanSpec struct {
@@ -38,3 +39,14 @@ func (bp *BuildPlan) Validate() error {
}
return nil
}
func (bp *BuildPlan) ResultCapacity() (count int) {
if bp == nil {
return 0
}
count = len(bp.Spec.Components.HelmChartList) +
len(bp.Spec.Components.KubernetesObjectsList) +
len(bp.Spec.Components.KustomizeBuildList) +
len(bp.Spec.Components.Resources)
return count
}

9
api/v1alpha1/platform.go Normal file
View File

@@ -0,0 +1,9 @@
package v1alpha1
// Platform represents a platform to manage. A Platform resource tells holos
// which components to build. The primary use case is to specify the cluster
// names, cluster types, and holos components to build.
type Platform struct {
TypeMeta `json:",inline" yaml:",inline"`
Metadata ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
}

View File

@@ -19,6 +19,14 @@ type Result struct {
accumulatedOutput string
}
// Continue returns true if Skip is true indicating the result is to be skipped over.
func (r *Result) Continue() bool {
if r == nil {
return false
}
return r.Skip
}
func (r *Result) Name() string {
return r.Metadata.Name
}
@@ -32,6 +40,11 @@ func (r *Result) KustomizationFilename(writeTo string, cluster string) string {
return filepath.Join(writeTo, "clusters", cluster, "holos", "components", r.Metadata.Name+"-kustomization.gen.yaml")
}
// KustomizationContent returns the kustomization file contents to write.
func (r *Result) KustomizationContent() string {
return r.KsContent
}
// AccumulatedOutput returns the accumulated rendered output.
func (r *Result) AccumulatedOutput() string {
return r.accumulatedOutput

View File

@@ -8,3 +8,13 @@ type TypeMeta struct {
func (tm *TypeMeta) GetKind() string {
return tm.Kind
}
func (tm *TypeMeta) GetAPIVersion() string {
return tm.Kind
}
// Discriminator is an interface to discriminate the kind api object.
type Discriminator interface {
GetKind() string
GetAPIVersion() string
}

View File

@@ -11,14 +11,10 @@ plugins:
out: service/gen
opt: paths=source_relative
- plugin: es
out: internal/frontend/holos/gen
out: internal/frontend/holos/src/app/gen
opt:
- target=ts
- plugin: connect-es
out: internal/frontend/holos/gen
opt:
- target=ts
- plugin: connect-query
out: internal/frontend/holos/gen
out: internal/frontend/holos/src/app/gen
opt:
- target=ts

View File

@@ -2,7 +2,10 @@ package holos
import ap "security.istio.io/authorizationpolicy/v1"
// #AuthPolicyRules represents AuthorizationPolicy rules for hosts that need specialized treatment. Entries in this struct are exclused from the blank ingressauth AuthorizationPolicy governing the ingressgateway and included in a spcialized policy
// #AuthPolicyRules represents AuthorizationPolicy rules for hosts that need
// specialized treatment. Entries in this struct are excluded from
// AuthorizationPolicy/authproxy-custom in the istio-ingress namespace. Entries
// are added to their own AuthorizationPolicy.
#AuthPolicyRules: {
// AuthProxySpec represents the identity provider configuration
AuthProxySpec: #AuthProxySpec & #Platform.authproxy
@@ -14,6 +17,9 @@ import ap "security.istio.io/authorizationpolicy/v1"
name: Name
// slug is the resource name prefix
slug: string
// NoAuthorizationPolicy disables an AuthorizationPolicy for the host
NoAuthorizationPolicy: true | *false
// Refer to https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule
spec: ap.#AuthorizationPolicySpec & {
action: "CUSTOM"
@@ -25,11 +31,13 @@ import ap "security.istio.io/authorizationpolicy/v1"
objects: #APIObjects & {
for Host in hosts {
apiObjects: {
AuthorizationPolicy: "\(Host.slug)-custom": {
metadata: namespace: "istio-ingress"
metadata: name: "\(Host.slug)-custom"
spec: Host.spec
if Host.NoAuthorizationPolicy == false {
apiObjects: {
AuthorizationPolicy: "\(Host.slug)-custom": {
metadata: namespace: "istio-ingress"
metadata: name: "\(Host.slug)-custom"
spec: Host.spec
}
}
}
}

View File

@@ -18,6 +18,7 @@ import "encoding/yaml"
Issuer?: [Name=_]: #Issuer & {metadata: name: Name}
Gateway?: [Name=_]: #Gateway & {metadata: name: Name}
ConfigMap?: [Name=_]: #ConfigMap & {metadata: name: Name}
ServiceAccount?: [Name=_]: #ServiceAccount & {metadata: name: Name}
Deployment?: [_]: #Deployment
StatefulSet?: [_]: #StatefulSet

View File

@@ -1,13 +1,13 @@
package holos
let Namespace = "jeff-holos"
let Broker = "broker"
let Broker = "choria-broker"
spec: components: KubernetesObjectsList: [
#KubernetesObjects & {
_dependsOn: "prod-platform-issuer": _
metadata: name: "\(Namespace)-broker"
metadata: name: "\(Namespace)-\(Broker)"
apiObjectMap: OBJECTS.apiObjectMap
},
]
@@ -31,9 +31,6 @@ let OBJECTS = #APIObjects & {
Broker,
"\(Broker).\(Namespace).svc",
"\(Broker).\(Namespace).svc.cluster.local",
"provision-\(Broker)",
"provision-\(Broker).\(Namespace).svc",
"provision-\(Broker).\(Namespace).svc.cluster.local",
"*.\(Broker)",
"*.\(Broker).\(Namespace).svc",
"*.\(Broker).\(Namespace).svc.cluster.local",

View File

@@ -0,0 +1,45 @@
package holos
let Namespace = "jeff-holos"
let Provisioner = "choria-provisioner"
spec: components: KubernetesObjectsList: [
#KubernetesObjects & {
_dependsOn: "prod-platform-issuer": _
metadata: name: "\(Namespace)-\(Provisioner)"
apiObjectMap: OBJECTS.apiObjectMap
},
]
let SelectorLabels = {
"app.kubernetes.io/instance": Provisioner
"app.kubernetes.io/name": Provisioner
}
let OBJECTS = #APIObjects & {
apiObjects: {
Certificate: "\(Provisioner)-tls": #Certificate & {
metadata: {
name: "\(Provisioner)-tls"
namespace: Namespace
labels: SelectorLabels
}
spec: {
commonName: "\(Provisioner).\(Namespace).svc.cluster.local"
dnsNames: [
Provisioner,
"\(Provisioner).\(Namespace).svc",
"\(Provisioner).\(Namespace).svc.cluster.local",
"*.\(Provisioner)",
"*.\(Provisioner).\(Namespace).svc",
"*.\(Provisioner).\(Namespace).svc.cluster.local",
]
issuerRef: kind: "ClusterIssuer"
issuerRef: name: "platform-issuer"
secretName: metadata.name
usages: ["signing", "key encipherment", "server auth", "client auth"]
}
}
}
}

View File

@@ -1,20 +1,20 @@
package holos
let Namespace = "jeff-holos"
let Broker = "broker"
let Broker = "choria-broker"
spec: components: KubernetesObjectsList: [
#KubernetesObjects & {
_dependsOn: "prod-secrets-stores": _
metadata: name: "\(Namespace)-broker"
metadata: name: "\(Namespace)-\(Broker)"
apiObjectMap: OBJECTS.apiObjectMap
},
]
let SelectorLabels = {
"app.kubernetes.io/instance": Broker
"app.kubernetes.io/name": Broker
"app.kubernetes.io/part-of": "choria"
"app.kubernetes.io/name": Broker
}
let Metadata = {
@@ -29,8 +29,8 @@ let OBJECTS = #APIObjects & {
metadata: name: "\(Broker)-tls"
metadata: namespace: Namespace
}
ExternalSecret: "choria-\(Broker)": #ExternalSecret & {
metadata: name: "choria-\(Broker)"
ExternalSecret: "\(Broker)": #ExternalSecret & {
metadata: name: Broker
metadata: namespace: Namespace
}
StatefulSet: "\(Broker)": {
@@ -92,7 +92,7 @@ let OBJECTS = #APIObjects & {
volumes: [
{
name: Broker
secret: secretName: "choria-\(Broker)"
secret: secretName: Broker
},
{
name: "\(Broker)-tls"
@@ -137,11 +137,20 @@ let OBJECTS = #APIObjects & {
}
}
DestinationRule: "\(Broker)-wss": #DestinationRule & {
metadata: Metadata
_decriptions: "Configures Istio to connect to Choria using a cert issued by the Platform Issuer"
metadata: Metadata
spec: host: "\(Broker).\(Namespace).svc.cluster.local"
spec: trafficPolicy: tls: {
credentialName: "istio-ingress-mtls-cert"
mode: "MUTUAL"
// subjectAltNames is important, otherwise istio will fail to verify the
// choria broker upstream server. make sure this matches a value
// present in the choria broker's cert.
//
// kubectl get secret choria-broker-tls -o json | jq --exit-status
// '.data | map_values(@base64d)' | jq .\"tls.crt\" -r | openssl x509
// -text -noout -in -
subjectAltNames: [spec.host]
}
}
VirtualService: "\(Broker)-wss": #VirtualService & {

View File

@@ -1,220 +0,0 @@
# build output from https://github.com/holos-run/holos-infra/blob/main/experiments/components/holos-saas/broker/build
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/instance: broker
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: broker
app.kubernetes.io/version: 0.1.0
helm.sh/chart: broker-0.1.0
name: broker
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/instance: broker
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: broker
app.kubernetes.io/version: 0.1.0
helm.sh/chart: broker-0.1.0
name: broker
spec:
clusterIP: None
ports:
- appProtocol: tcp
name: tcp-nats
port: 4222
protocol: TCP
targetPort: tcp-nats
- appProtocol: tcp
name: tcp-cluster
port: 5222
protocol: TCP
targetPort: tcp-cluster
- appProtocol: https
name: https-wss
port: 443
protocol: TCP
targetPort: https-wss
selector:
app.kubernetes.io/instance: broker
app.kubernetes.io/name: broker
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/instance: broker
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: broker
app.kubernetes.io/version: 0.1.0
helm.sh/chart: broker-0.1.0
name: broker-lb
spec:
externalTrafficPolicy: Local
loadBalancerIP: 1.2.3.4
ports:
- appProtocol: tcp
name: tcp-nats
port: 4222
protocol: TCP
targetPort: tcp-nats
- appProtocol: https
name: https-wss
port: 443
protocol: TCP
targetPort: https-wss
selector:
app.kubernetes.io/instance: broker
app.kubernetes.io/name: broker
type: LoadBalancer
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app.kubernetes.io/instance: broker
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: broker
app.kubernetes.io/version: 0.1.0
helm.sh/chart: broker-0.1.0
name: broker
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/instance: broker
app.kubernetes.io/name: broker
serviceName: broker
template:
metadata:
labels:
app.kubernetes.io/instance: broker
app.kubernetes.io/name: broker
spec:
containers:
- command:
- choria
- broker
- run
- --config
- /etc/choria/broker.conf
image: registry.choria.io/choria/choria:latest
imagePullPolicy: Always
livenessProbe:
httpGet:
path: /healthz
port: http-stats
name: broker
ports:
- containerPort: 4222
name: tcp-nats
protocol: TCP
- containerPort: 4333
name: https-wss
protocol: TCP
- containerPort: 5222
name: tcp-cluster
protocol: TCP
- containerPort: 8222
name: http-stats
protocol: TCP
readinessProbe:
httpGet:
path: /healthz
port: http-stats
resources: {}
securityContext: {}
volumeMounts:
- mountPath: /etc/choria
name: broker
- mountPath: /etc/choria-tls
name: broker-tls
securityContext: {}
serviceAccountName: broker
volumes:
- name: broker
secret:
secretName: broker
- name: broker-tls
secret:
secretName: broker-tls
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: broker-tls
namespace: holos-dev
spec:
commonName: broker.holos-dev.svc.cluster.local
dnsNames:
- broker
- broker.holos-dev.svc
- broker.holos-dev.svc.cluster.local
- provision-broker
- provision-broker.holos-dev.svc
- provision-broker.holos-dev.svc.cluster.local
- '*.broker'
- '*.broker.holos-dev.svc'
- '*.broker.holos-dev.svc.cluster.local'
issuerRef:
kind: ClusterIssuer
name: cluster-issuer
secretName: broker-tls
usages:
- signing
- key encipherment
- server auth
- client auth
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: broker
spec:
dataFrom:
- extract:
key: kv//kube-namespace/holos-dev/broker
refreshInterval: 1h
secretStoreRef:
kind: SecretStore
name: core-vault
target:
creationPolicy: Owner
name: broker
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: broker-wss
namespace: holos-dev
spec:
host: broker.holos-dev.svc.cluster.local
trafficPolicy:
tls:
credentialName: istio-ingress-mtls-cert
mode: MUTUAL
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: broker-wss
namespace: holos-dev
spec:
gateways:
- istio-ingress/wildcard-pub-gw
hosts:
- provision.pub.k2.holos.run
http:
- route:
- destination:
host: broker.holos-dev.svc.cluster.local
port:
number: 443
tls:
mode: SIMPLE

View File

@@ -0,0 +1,18 @@
FROM registry.choria.io/choria/provisioner:latest
RUN curl -Lo nsc.zip https://github.com/nats-io/nsc/releases/download/v2.8.6/nsc-linux-amd64.zip &&\
unzip nsc.zip && \
mv nsc /usr/local/bin/nsc && \
chmod 755 /usr/local/bin/nsc && \
rm -f nsc.zip
# TODO: Add jwt executable
# TODO: Add helper executable
USER choria
ENV USER=choria
ENTRYPOINT ["/usr/sbin/choria-provisioner"]
# These two files are expected to be in the provisioner secret.
CMD ["--config=/etc/provisioner/provisioner.yaml", "--choria-config=/etc/provisioner/choria.cfg"]

View File

@@ -0,0 +1,82 @@
package holos
let Namespace = "jeff-holos"
let Provisioner = "choria-provisioner"
spec: components: KubernetesObjectsList: [
#KubernetesObjects & {
_dependsOn: "prod-secrets-stores": _
metadata: name: "\(Namespace)-\(Provisioner)"
apiObjectMap: OBJECTS.apiObjectMap
},
]
let SelectorLabels = {
"app.kubernetes.io/instance": Provisioner
"app.kubernetes.io/name": Provisioner
}
let Metadata = {
name: Provisioner
namespace: Namespace
labels: SelectorLabels
}
let OBJECTS = #APIObjects & {
apiObjects: {
ExternalSecret: "\(Provisioner)-tls": #ExternalSecret & {
metadata: name: "\(Provisioner)-tls"
metadata: namespace: Namespace
}
ExternalSecret: "\(Provisioner)": #ExternalSecret & {
metadata: name: Provisioner
metadata: namespace: Namespace
}
ServiceAccount: "\(Provisioner)": #ServiceAccount & {
metadata: Metadata
}
Deployment: "\(Provisioner)": {
metadata: Metadata
spec: {
selector: matchLabels: SelectorLabels
template: metadata: labels: SelectorLabels
template: spec: {
containers: [
{
name: Provisioner
command: ["bash", "/etc/provisioner/entrypoint"]
// skopeo inspect docker://registry.choria.io/choria/provisioner | jq .RepoTags
image: "registry.choria.io/choria/provisioner:0.15.1"
imagePullPolicy: "IfNotPresent"
resources: {}
securityContext: {}
volumeMounts: [
{
mountPath: "/etc/provisioner"
name: Provisioner
},
{
mountPath: "/etc/provisioner-tls"
name: "\(Provisioner)-tls"
},
]
},
]
securityContext: {}
serviceAccountName: Provisioner
volumes: [
{
name: Provisioner
secret: secretName: name
},
{
name: "\(Provisioner)-tls"
secret: secretName: name
},
]
}
}
}
}
}

View File

@@ -71,14 +71,15 @@ let IstioInject = [{op: "add", path: "/spec/template/metadata/labels/sidecar.ist
}
}
// Probably shouldn't use the authproxy struct and should instead define an identity provider struct.
let AuthProxySpec = #AuthProxySpec & #Platform.authproxy
let OAuthClient = #Platform.oauthClients.argocd.spec
let OIDCConfig = {
name: "Holos Platform"
issuer: AuthProxySpec.issuer
clientID: #Platform.argocd.clientID
requestedIDTokenClaims: groups: essential: true
requestedScopes: ["openid", "profile", "email", "groups", "urn:zitadel:iam:org:domain:primary:\(AuthProxySpec.orgDomain)"]
name: "Holos Platform"
issuer: OAuthClient.issuer
clientID: OAuthClient.clientID
requestedScopes: OAuthClient.scopesList
// Set redirect uri to https://argocd.example.com/pkce/verify
enablePKCEAuthentication: true
requestedIDTokenClaims: groups: essential: true
}

View File

@@ -18,6 +18,10 @@ _IngressAuthProxy: {
Domains: (#Platform.org.domain): _
Domains: "\(#ClusterName).\(#Platform.org.domain)": _
// TODO: This should be generated from ProjectHosts
Domains: "holos.run": _
Domains: "\(#ClusterName).holos.run": _
let Metadata = {
name: string
namespace: Namespace
@@ -85,7 +89,8 @@ _IngressAuthProxy: {
spec: {
securityContext: seccompProfile: type: "RuntimeDefault"
containers: [{
image: "quay.io/oauth2-proxy/oauth2-proxy:v7.6.0"
// image: "quay.io/oauth3-proxy/oauth2-proxy:v7.6.0"
image: "quay.io/holos/oauth2-proxy:v7.6.0-1-g77a03ae2"
imagePullPolicy: "IfNotPresent"
name: "oauth2-proxy"
volumeMounts: [{
@@ -271,11 +276,14 @@ _IngressAuthProxy: {
rules: [
{
to: [{
// Refer to https://istio.io/latest/docs/ops/best-practices/security/#writing-host-match-policies
operation: notHosts: [
// Never send requests for the login service through the authorizer, would block login.
AuthProxySpec.issuerHost,
"\(AuthProxySpec.issuerHost):*",
// Exclude hosts with specialized rules from the catch-all.
for x in _AuthPolicyRules.hosts {x.name},
for x in _AuthPolicyRules.hosts {"\(x.name):*"},
]
}]
when: [
@@ -298,7 +306,7 @@ _IngressAuthProxy: {
_AuthPolicyRules: #AuthPolicyRules & {
hosts: {
let Vault = "vault.core.ois.run"
(Vault): {
"\(Vault)": {
slug: "vault"
// Rules for when to route requests through the auth proxy
spec: rules: [
@@ -321,3 +329,20 @@ _AuthPolicyRules: #AuthPolicyRules & {
}
}
}
// Exclude project hosts from the auth proxy if configured to do so. The
// intended effect is to exclude the host from the blanket `authproxy-custom`
// AuthorizationPolicy rule _without_ adding a specialized AuthorizationPolicy
// for the same host. This has the effect of completely excluding the host from
// authorization policy.
for Project in _Projects {
let ProjectHosts = (#ProjectHosts & {project: Project}).Hosts
for FQDN, Host in ProjectHosts {
if Host.NoAuthorizationPolicy {
if Host.clusters[#ClusterName] != _|_ {
_AuthPolicyRules: hosts: "\(Host.fqdn)": NoAuthorizationPolicy: true
}
}
}
}

View File

@@ -4,15 +4,23 @@ package holos
let ZitadelProjectID = 257713952794870157
let AllClusters = {
// platform level services typically run in the core cluster pair.
core1: _
core2: _
// for development, probably wouldn't run these services in the workload clusters.
k1: _
k2: _
k3: _
k4: _
k5: _
}
_Projects: #Projects & {
// The platform project is required and where platform services reside. ArgoCD, Grafana, Prometheus, etc...
platform: {
resourceId: ZitadelProjectID
// platform level services typically run in the core cluster pair.
clusters: core1: _
clusters: core2: _
// for development, probably wouldn't run these services in the workload clusters.
clusters: k2: _
clusters: AllClusters
// Services hosted in the platform project
hosts: argocd: _
hosts: grafana: _
@@ -22,13 +30,7 @@ _Projects: #Projects & {
holos: {
resourceId: ZitadelProjectID
domain: "holos.run"
clusters: core1: _
clusters: core2: _
clusters: k1: _
clusters: k2: _
clusters: k3: _
clusters: k4: _
clusters: k5: _
clusters: AllClusters
environments: {
prod: stage: "prod"
@@ -41,9 +43,9 @@ _Projects: #Projects & {
// app is the holos web app and grpc api.
hosts: app: _
// provision is the choria broker provisioning system.
hosts: provision: _
hosts: provision: NoAuthorizationPolicy: true
// nats is the nats service holos controller machine room agents connect after provisioning.
hosts: nats: _
hosts: nats: NoAuthorizationPolicy: true
}
iam: {

View File

@@ -29,6 +29,7 @@ let OBJECTS = #APIObjects & {
metadata: name: PlatformIssuer
metadata: namespace: Namespace
spec: {
duration: "999999h"
isCA: true
commonName: PlatformIssuer
secretName: PlatformIssuer

View File

@@ -0,0 +1,73 @@
package holos
let Namespace = "dev-holos"
let Holos = "holos"
// spec represents the output provided to holos
spec: components: KubernetesObjectsList: [
#KubernetesObjects & {
metadata: name: "dev-holos-app"
apiObjectMap: OBJECTS.apiObjectMap
},
]
// OBJECTS represents the kubernetes api objects to manage.
let OBJECTS = #APIObjects & {
apiObjects: Deployment: holos: {
metadata: {
name: Holos
namespace: Namespace
labels: app: Holos
}
spec: {
selector: matchLabels: app: Holos
template: metadata: labels: {
app: Holos
"sidecar.istio.io/inject": "true"
}
strategy: rollingUpdate: maxSurge: 1
strategy: rollingUpdate: maxUnavailable: 0
template: {
spec: {
serviceAccountName: Holos
securityContext: seccompProfile: type: "RuntimeDefault"
containers: [
{
name: Holos
image: "271053619184.dkr.ecr.us-east-2.amazonaws.com/holos-run/holos-server/holos:0.73.1"
imagePullPolicy: "Always"
env: [
{
name: "TZ"
value: "America/Los_Angeles"
},
{
name: "DATABASE_URL"
valueFrom: secretKeyRef: {
key: "uri"
name: "holos-pguser-holos"
}
},
]
ports: [
{
containerPort: 3000
name: "http"
protocol: "TCP"
},
]
securityContext: capabilities: drop: ["ALL"]
securityContext: allowPrivilegeEscalation: false
securityContext: runAsNonRoot: true
resources: limits: {
cpu: "0.25"
memory: "256Mi"
}
resources: requests: resources.limits
},
]
}
}
}
}
}

View File

@@ -0,0 +1,129 @@
package holos
let Namespace = "dev-holos"
let Holos = "holos"
// spec represents the output provided to holos
spec: components: KubernetesObjectsList: [
#KubernetesObjects & {
metadata: name: "dev-holos-infra"
apiObjectMap: OBJECTS.apiObjectMap
},
]
let Metadata = {
name: Holos
namespace: Namespace
labels: app: Holos
}
// OBJECTS represents the kubernetes api objects to manage.
let OBJECTS = #APIObjects & {
// Postgres
// Deployment
// VirtualService
apiObjects: ServiceAccount: holos: {
metadata: Metadata
imagePullSecrets: [{name: "kube-system-ecr-image-pull-creds"}]
}
apiObjects: PostgresCluster: holos: {
apiVersion: "postgres-operator.crunchydata.com/v1beta1"
metadata: Metadata
spec: {
image: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.1-0"
instances: [{
affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: [{
podAffinityTerm: {
labelSelector: matchLabels: "postgres-operator.crunchydata.com/cluster": "holos"
topologyKey: "kubernetes.io/hostname"
}
weight: 1
}]
dataVolumeClaimSpec: {
accessModes: ["ReadWriteOnce"]
resources: requests: storage: "1Gi"
}
name: "db"
replicas: 1
}]
port: 5432
postgresVersion: 16
users: [{
databases: ["holos"]
name: "holos"
options: "SUPERUSER"
}]
backups: pgbackrest: {
global: {
"archive-async": "y"
"archive-push-queue-max": "100MiB"
"spool-path": "/pgdata/backups"
}
image: "registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.47-2"
repos: [{
name: "repo1"
volume: volumeClaimSpec: {
accessModes: ["ReadWriteOnce"]
resources: requests: storage: "1Gi"
}
}]
}
}
}
apiObjects: Service: holos: {
apiVersion: "v1"
metadata: Metadata
spec: {
type: "ClusterIP"
selector: app: "holos"
ports: [{
appProtocol: "http2"
name: "http"
port: 3000
protocol: "TCP"
targetPort: 3000
}, {
appProtocol: "http"
name: "metrics"
port: 9090
protocol: "TCP"
targetPort: 9090
}]
}
}
apiObjects: VirtualService: holos: {
apiVersion: "networking.istio.io/v1beta1"
metadata: Metadata
spec: {
gateways: ["istio-ingress/default"]
hosts: [
"app.dev.holos.run",
"app.dev.\(#ClusterName).holos.run",
]
http: [{
match: [{
uri: prefix: "/ui"
}]
name: "ui"
route: [{
destination: {
host: "holos"
port: number: 3000
}
}]
}, {
name: "api"
route: [{
destination: {
host: "holos"
port: number: 3000
}
}]
}]
}
}
}

View File

@@ -4,15 +4,18 @@ package holos
#Project: {
name: string
// All projects have at least a prod environment and stage.
// All projects have at least a prod and dev environment and stage.
// Omit the prod stage segment from hostnames. foo.holos.run not foo.prod.holos.run
stages: prod: stageSegments: []
environments: prod: stage: "prod"
// Omit the prod env segment from hostnames. foo.holos.run not prod.foo.holos.run
environments: prod: envSegments: []
stages: dev: _
environments: dev: stage: "dev"
// Omit the dev env segment from hostnames. foo.dev.holos.run not dev.foo.dev.holos.run
environments: dev: envSegments: []
// Ensure at least the project name is a short hostname. Additional may be added.
hosts: (name): _
// environments share the stage segments of their stage.
environments: [_]: {

View File

@@ -16,9 +16,10 @@ import "strings"
for Host in project.hosts {
// Global hostname, e.g. app.holos.run
let CertInfo = (#MakeCertInfo & {
host: Host
env: Env
domain: project.domain
host: Host
env: Env
domain: project.domain
clusterMap: project.clusters
}).CertInfo
"\(CertInfo.fqdn)": CertInfo
@@ -26,10 +27,11 @@ import "strings"
// Cluster hostname, e.g. app.east1.holos.run, app.west1.holos.run
for Cluster in project.clusters {
let CertInfo = (#MakeCertInfo & {
host: Host
env: Env
domain: project.domain
cluster: Cluster.name
host: Host
env: Env
domain: project.domain
cluster: Cluster.name
clusterMap: project.clusters
}).CertInfo
"\(CertInfo.fqdn)": CertInfo
@@ -42,10 +44,11 @@ import "strings"
// #MakeCertInfo provides dns info for a certificate
// Refer to: https://github.com/holos-run/holos/issues/66#issuecomment-2027562626
#MakeCertInfo: {
host: #Host
env: #Environment
domain: string
cluster: string
host: #Host
env: #Environment
domain: string
cluster: string
clusterMap: #ClusterMap
let Stage = #StageInfo & {name: env.stage, project: env.project}
let Env = env
@@ -91,6 +94,18 @@ import "strings"
slug: Env.slug
namespace: Env.namespace
}
if cluster != _|_ {
// Host is valid on a single cluster.
clusters: "\(cluster)": _
}
if cluster == _|_ {
// Host is valid on all project clusters.
clusters: clusterMap
}
NoAuthorizationPolicy: host.NoAuthorizationPolicy
}
}
@@ -108,8 +123,19 @@ import "strings"
stage: #StageOrEnvRef
env: #StageOrEnvRef
// clusters represents the cluster names the fqdn is valid on.
clusters: #ClusterMap
// hosts are always valid on the provisioner cluster
clusters: provisioner: _
// NoAuthorizationPolicy excludes the host from the auth proxy integrated with
// the default ingress Gateway.
NoAuthorizationPolicy: true | *false
}
#ClusterMap: [Name=string]: #Cluster & {name: Name}
#StageOrEnvRef: {
name: string
slug: string

View File

@@ -24,7 +24,7 @@ package holos
dnsNames: [for x in _dnsNames {x}]
issuerRef: {
kind: "ClusterIssuer"
name: "letsencrypt-staging"
name: "letsencrypt"
}
}
}

View File

@@ -3,6 +3,7 @@ package holos
import (
h "github.com/holos-run/holos/api/v1alpha1"
"encoding/yaml"
"strings"
)
// let SourceLoc = "project-template.cue"
@@ -26,25 +27,32 @@ import (
project: #Project
let Project = project
// ProjectHosts represents all of the hosts associated with a project indexed
// by FQDN with #CertInfo values. Slice and dice this struct as needed to
// work with hosts in the platform.
ProjectHosts: (#ProjectHosts & {project: Project}).Hosts
// GatewayServers maps Gateway spec.servers #GatewayServer values indexed by stage then name.
GatewayServers: {
for FQDN, Host in ProjectHosts {
"\(FQDN)": #GatewayServer & {
_CertInfo: Host
hosts: [
"\(Host.env.namespace)/\(FQDN)",
// Allow the authproxy VirtualService to match the project.authProxyPrefix path.
"\(Host.stage.namespace)/\(FQDN)",
]
port: {
name: "https"
number: 443
protocol: "HTTPS"
// If the host is valid on the cluster being rendered
if Host.clusters[#ClusterName] != _|_ {
"\(FQDN)": #GatewayServer & {
_CertInfo: Host
hosts: [
"\(Host.env.namespace)/\(FQDN)",
// Allow the authproxy VirtualService to match the project.authProxyPrefix path.
"\(Host.stage.namespace)/\(FQDN)",
]
port: {
// NOTE: port names in servers must be unique: duplicate name https
name: "https-" + strings.Replace(FQDN, ".", "-", -1)
number: 443
protocol: "HTTPS"
}
tls: credentialName: Host.canonical
tls: mode: "SIMPLE"
}
tls: credentialName: Host.canonical
tls: mode: "SIMPLE"
}
}
}

View File

@@ -68,8 +68,13 @@ _Projects: #Projects
// #Cluster defines a cluster
#Cluster: name: string
// #Host defines a short hostname
#Host: name: string
#Host: {
// #Host defines a short hostname
name: string
// NoAuthorizationPolicy excludes the host from the auth proxy integrated with
// the default ingress Gateway.
NoAuthorizationPolicy: true | *false
}
#Environment: {
// name uniquely identifies the environment within the scope of the project.

77
go.mod
View File

@@ -5,11 +5,12 @@ go 1.21.5
require (
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.33.0-20240401165935-b983156c5e99.1
connectrpc.com/connect v1.16.0
connectrpc.com/grpcreflect v1.2.0
connectrpc.com/validate v0.1.0
cuelang.org/go v0.8.0
entgo.io/ent v0.13.1
github.com/bufbuild/buf v1.30.1
github.com/choria-io/machine-room v0.0.0-20231204170637-dbd92497cddc
github.com/choria-io/machine-room v0.0.0-20240417064836-c604da2f005e
github.com/coreos/go-oidc/v3 v3.10.0
github.com/fullstorydev/grpcurl v1.9.1
github.com/go-jose/go-jose/v3 v3.0.3
@@ -26,8 +27,8 @@ require (
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
golang.org/x/net v0.22.0
golang.org/x/tools v0.19.0
golang.org/x/net v0.24.0
golang.org/x/tools v0.20.0
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002
honnef.co/go/tools v0.4.7
k8s.io/api v0.29.2
@@ -66,20 +67,20 @@ require (
github.com/bufbuild/protoyaml-go v0.1.8 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/choria-io/fisk v0.6.1 // indirect
github.com/choria-io/go-choria v0.27.1-0.20231204170245-efda165efc54 // indirect
github.com/choria-io/fisk v0.6.2 // indirect
github.com/choria-io/go-choria v0.28.1-0.20240416190746-b3bf9c7d5a45 // indirect
github.com/choria-io/go-updater v0.1.0 // indirect
github.com/choria-io/stream-replicator v0.8.3-0.20230503130504-86152f798aec // indirect
github.com/choria-io/tokens v0.0.3 // indirect
github.com/cloudevents/sdk-go/v2 v2.14.0 // indirect
github.com/choria-io/tokens v0.0.4-0.20240316144214-a929d9325d48 // indirect
github.com/cloudevents/sdk-go/v2 v2.15.2 // indirect
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa // indirect
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/cli v26.0.0+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
@@ -93,7 +94,7 @@ require (
github.com/envoyproxy/go-control-plane v0.12.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
github.com/expr-lang/expr v1.15.6 // indirect
github.com/expr-lang/expr v1.16.4 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/fgprof v0.9.4 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
@@ -120,7 +121,7 @@ require (
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-containerregistry v0.19.1 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20240327155427-868f304927ed // indirect
github.com/google/pprof v0.0.0-20240416155748-26353dc0451f // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/google/wire v0.5.0 // indirect
@@ -131,7 +132,7 @@ require (
github.com/gosuri/uilive v0.0.4 // indirect
github.com/gosuri/uiprogress v0.0.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/guptarohit/asciigraph v0.5.6 // indirect
github.com/guptarohit/asciigraph v0.7.1 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl/v2 v2.13.0 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
@@ -149,11 +150,11 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/looplab/fsm v1.0.1 // indirect
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect
github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
@@ -172,41 +173,41 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/jsm.go v0.1.1-0.20231204140718-1ad3bcd9702c // indirect
github.com/nats-io/jwt/v2 v2.5.3 // indirect
github.com/nats-io/nats-server/v2 v2.10.6 // indirect
github.com/nats-io/nats.go v1.31.0 // indirect
github.com/nats-io/nkeys v0.4.6 // indirect
github.com/nats-io/jsm.go v0.1.1 // indirect
github.com/nats-io/jwt/v2 v2.5.5 // indirect
github.com/nats-io/nats-server/v2 v2.10.14 // indirect
github.com/nats-io/nats.go v1.34.1 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/oleiade/reflections v1.0.1 // indirect
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
github.com/onsi/gomega v1.31.1 // indirect
github.com/open-policy-agent/opa v0.59.0 // indirect
github.com/onsi/ginkgo/v2 v2.17.1 // indirect
github.com/onsi/gomega v1.32.0 // indirect
github.com/open-policy-agent/opa v0.63.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/profile v1.7.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/prometheus/client_model v0.6.0 // indirect
github.com/prometheus/common v0.50.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.52.3 // indirect
github.com/prometheus/procfs v0.13.0 // indirect
github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/robfig/cron v1.2.0 // indirect
github.com/rs/cors v1.10.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/samber/lo v1.39.0 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
github.com/shirou/gopsutil/v3 v3.23.11 // indirect
github.com/shirou/gopsutil/v3 v3.24.3 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
@@ -222,7 +223,7 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xlab/tablewriter v0.0.0-20160610135559-80b567a11ad5 // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/zclconf/go-cty v1.8.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.25.0 // indirect
@@ -233,14 +234,14 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a // indirect
golang.org/x/mod v0.16.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/term v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
@@ -262,5 +263,3 @@ require (
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)
replace github.com/choria-io/machine-room v0.0.0 => github.com/jeffmccune/machine-room v0.0.990

156
go.sum
View File

@@ -40,6 +40,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
connectrpc.com/connect v1.16.0 h1:rdtfQjZ0OyFkWPTegBNcH7cwquGAN1WzyJy80oFNibg=
connectrpc.com/connect v1.16.0/go.mod h1:XpZAduBQUySsb4/KO5JffORVkDI4B6/EYPi7N8xpNZw=
connectrpc.com/grpcreflect v1.2.0 h1:Q6og1S7HinmtbEuBvARLNwYmTbhEGRpHDhqrPNlmK+U=
connectrpc.com/grpcreflect v1.2.0/go.mod h1:nwSOKmE8nU5u/CidgHtPYk1PFI3U9ignz7iDMxOYkSY=
connectrpc.com/otelconnect v0.7.0 h1:ZH55ZZtcJOTKWWLy3qmL4Pam4RzRWBJFOqTPyAqCXkY=
connectrpc.com/otelconnect v0.7.0/go.mod h1:Bt2ivBymHZHqxvo4HkJ0EwHuUzQN6k2l0oH+mp/8nwc=
connectrpc.com/validate v0.1.0 h1:r55jirxMK7HO/xZwVHj3w2XkVFarsUM77ZDy367NtH4=
@@ -113,22 +115,22 @@ github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMr
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/choria-io/fisk v0.6.1 h1:umFzmj2Ecttk89AFoxnqCph0exAmChqhJklvE+Id18o=
github.com/choria-io/fisk v0.6.1/go.mod h1:m6kd61ycRGwkyb0SDdgmcQXW9fQJuqeH4DKEjRxJewg=
github.com/choria-io/go-choria v0.27.1-0.20231204170245-efda165efc54 h1:JeKdv9cF/VRvpCiHYn9ywiRO8EAJOxa4ucRxK7ZyPL8=
github.com/choria-io/go-choria v0.27.1-0.20231204170245-efda165efc54/go.mod h1:FRKqAlnTdujcyhNCdGBSaTGtlHuTX6akgjTxP9SDXMI=
github.com/choria-io/fisk v0.6.2 h1:Vfvpcv8SD53FHW5cT4u7LStpz/wThwRPQHU7mzv1kMI=
github.com/choria-io/fisk v0.6.2/go.mod h1:PajiUZTAotE5zO18eU6UexuPLLv565WOma4dB0ObxRM=
github.com/choria-io/go-choria v0.28.1-0.20240416190746-b3bf9c7d5a45 h1:B76eu8PMXr3mAhQl8y7NSsb1/4KCKX4bEDTsKWh7/CQ=
github.com/choria-io/go-choria v0.28.1-0.20240416190746-b3bf9c7d5a45/go.mod h1:XLEKGqo1Xmvj69DrSdI0neDGveWJDDQTeHdZgf1zxsI=
github.com/choria-io/go-updater v0.1.0 h1:+Pt2ifsDh478T/ldA8fnDwavvH3RTQNn1mkrabVZ5eg=
github.com/choria-io/go-updater v0.1.0/go.mod h1:8qj3lwYUC6c0zqsvaKP4pNu8GMHbIr5WGrd5YUWByWw=
github.com/choria-io/machine-room v0.0.0-20231204170637-dbd92497cddc h1:S/I4co2ITCHzZO81EV4xpIP+sGWQvxkFnrhXCehNR+0=
github.com/choria-io/machine-room v0.0.0-20231204170637-dbd92497cddc/go.mod h1:sL9flpPiPucmV8Xb+HQ3VD2lgBZnLGAJbJALcGYcxjc=
github.com/choria-io/machine-room v0.0.0-20240417064836-c604da2f005e h1:Kt9CeGRjW/mKQTams+aCUvIAucw3VzEZbKFJvM3pFeE=
github.com/choria-io/machine-room v0.0.0-20240417064836-c604da2f005e/go.mod h1:3zCpMS5R2/xOd6Wsep2o0vvAy0eJnfU/ngEptEuJArs=
github.com/choria-io/stream-replicator v0.8.3-0.20230503130504-86152f798aec h1:jGTkaDf2kDAlho4Oi6r2x51kzjXpxqhECFTHzTZ/a3w=
github.com/choria-io/stream-replicator v0.8.3-0.20230503130504-86152f798aec/go.mod h1:QVvT5tjYSYmvqx585herBk0aK13DS1j/wJVDDWuLFww=
github.com/choria-io/tokens v0.0.3 h1:kD+TNzS+ok8hYOs8MUOOTrkpG/gsQwpfIVPhcH7zrXs=
github.com/choria-io/tokens v0.0.3/go.mod h1:P/2ukQBNVkM4EjGw/PAvUrPQY8A/CU9I3NALGTC07yM=
github.com/choria-io/tokens v0.0.4-0.20240316144214-a929d9325d48 h1:KyL4w+dxAOfqi4Wds6Fh0632sxBw0YvRqL9fqMziGBI=
github.com/choria-io/tokens v0.0.4-0.20240316144214-a929d9325d48/go.mod h1:dEyJo/309e8n141nzx1u82QuXVt6mt42V1Jn9CkJJPs=
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
@@ -139,8 +141,8 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudevents/sdk-go/v2 v2.14.0 h1:Nrob4FwVgi5L4tV9lhjzZcjYqFVyJzsA56CwPaPfv6s=
github.com/cloudevents/sdk-go/v2 v2.14.0/go.mod h1:xDmKfzNjM8gBvjaF8ijFjM1VYOVUEeUfapHMUX1T5To=
github.com/cloudevents/sdk-go/v2 v2.15.2 h1:54+I5xQEnI73RBhWHxbI1XJcqOFOVJN85vb41+8mHUc=
github.com/cloudevents/sdk-go/v2 v2.15.2/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk=
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
@@ -163,8 +165,9 @@ github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg=
github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
@@ -202,8 +205,8 @@ github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/expr-lang/expr v1.15.6 h1:dQFgzj5DBu3wnUz8+PGLZdPMpefAvxaCFTNM3iSjkGA=
github.com/expr-lang/expr v1.15.6/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ=
github.com/expr-lang/expr v1.16.4 h1:1Mq5RHw5T5jxXMUvyb+eT546mJREm1yFyNHkybYQ81c=
github.com/expr-lang/expr v1.16.4/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
@@ -213,8 +216,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fullstorydev/grpcurl v1.9.1 h1:YxX1aCcCc4SDBQfj9uoWcTLe8t4NWrZe1y+mk83BQgo=
@@ -346,8 +349,8 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20240327155427-868f304927ed h1:n8QtJTrwsv3P7dNxPaMeNkMcxvUpqocsHLr8iDLGlQI=
github.com/google/pprof v0.0.0-20240327155427-868f304927ed/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/pprof v0.0.0-20240416155748-26353dc0451f h1:WpZiq8iqvGjJ3m3wzAVKL6+0vz7VkE79iSy9GII00II=
github.com/google/pprof v0.0.0-20240416155748-26353dc0451f/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
@@ -373,8 +376,8 @@ github.com/gosuri/uiprogress v0.0.1 h1:0kpv/XY/qTmFWl/SkaJykZXrBBzwwadmW8fRb7RJS
github.com/gosuri/uiprogress v0.0.1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
github.com/guptarohit/asciigraph v0.5.6 h1:0tra3HEhfdj1sP/9IedrCpfSiXYTtHdCgBhBL09Yx6E=
github.com/guptarohit/asciigraph v0.5.6/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag=
github.com/guptarohit/asciigraph v0.7.1 h1:K+JWbRc04XEfv8BSZgNuvhCmpbvX4+9NYd/UxXVnAuk=
github.com/guptarohit/asciigraph v0.7.1/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
@@ -427,8 +430,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -449,8 +452,8 @@ github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ
github.com/looplab/fsm v1.0.1 h1:OEW0ORrIx095N/6lgoGkFkotqH6s7vaFPsgjLAaF5QU=
github.com/looplab/fsm v1.0.1/go.mod h1:PmD3fFvQEIsjMEfvZdrCDZ6y8VwKTwWNjlpEr6IKPO4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0=
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 h1:1KuuSOy4ZNgW0KA2oYIngXVFhQcXxhLqCVK7cBcldkk=
github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -501,16 +504,16 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nats-io/jsm.go v0.1.1-0.20231204140718-1ad3bcd9702c h1:/4QPECV3zPK1/eRQEU7SfYDACU1yPRYuwaf5p+ThJUI=
github.com/nats-io/jsm.go v0.1.1-0.20231204140718-1ad3bcd9702c/go.mod h1:4HtrppnSb8m+1bX9bH/IhqmYDluP8tXRVVEznXo+kIg=
github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo=
github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4=
github.com/nats-io/nats-server/v2 v2.10.6 h1:40U3ngyAKyC1tNT4Kw7PjuvivY74NTYD3qyIHxZUHKQ=
github.com/nats-io/nats-server/v2 v2.10.6/go.mod h1:IrTXS8o4Roa3G2kW8L5mEtSdmSrFjKhYb/m2g0gQ/vc=
github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
github.com/nats-io/jsm.go v0.1.1 h1:6vjllz276SdC+3Fb3XI71p9B6toxkCruuB1K6unQEr0=
github.com/nats-io/jsm.go v0.1.1/go.mod h1:cFz5wR1pW0zLFotntS4HA7V8Wm+sf8zpF+iQJHbsS6M=
github.com/nats-io/jwt/v2 v2.5.5 h1:ROfXb50elFq5c9+1ztaUbdlrArNFl2+fQWP6B8HGEq4=
github.com/nats-io/jwt/v2 v2.5.5/go.mod h1:ZdWS1nZa6WMZfFwwgpEaqBV8EPGVgOTDHN/wTbz0Y5A=
github.com/nats-io/nats-server/v2 v2.10.14 h1:98gPJFOAO2vLdM0gogh8GAiHghwErrSLhugIqzRC+tk=
github.com/nats-io/nats-server/v2 v2.10.14/go.mod h1:a0TwOVBJZz6Hwv7JH2E4ONdpyFk9do0C18TEwxnHdRk=
github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4=
github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
@@ -519,12 +522,12 @@ github.com/oleiade/reflections v1.0.1 h1:D1XO3LVEYroYskEsoSiGItp9RUxG6jWnCVvrqH0
github.com/oleiade/reflections v1.0.1/go.mod h1:rdFxbxq4QXVZWj0F+e9jqjDkc7dbp97vkRixKo2JR60=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
github.com/open-policy-agent/opa v0.59.0 h1:1WFU/KUhJAr3qatm0Lf8Ea5jp10ZmlE2M07oaLiHypg=
github.com/open-policy-agent/opa v0.59.0/go.mod h1:rdJSkEc4oQ+0074/3Fsgno5bkPsYxTjU5aLNmMujIvI=
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
github.com/open-policy-agent/opa v0.63.0 h1:ztNNste1v8kH0/vJMJNquE45lRvqwrM5mY9Ctr9xIXw=
github.com/open-policy-agent/opa v0.63.0/go.mod h1:9VQPqEfoB2N//AToTxzZ1pVTVPUoF2Mhd64szzjWPpU=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
@@ -539,20 +542,21 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ=
github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.52.3 h1:5f8uj6ZwHSscOGNdIQg6OiZv/ybiK2CO2q2drVZAQSA=
github.com/prometheus/common v0.52.3/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 h1:sadMIsgmHpEOGbUs6VtHBXRR1OHevnj7hLx9ZcdNGW4=
github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
@@ -560,8 +564,8 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqn
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -577,19 +581,19 @@ github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6Ng
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ=
github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -653,8 +657,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -700,8 +704,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -712,8 +716,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a h1:Jw5wfR+h9mnIYH+OtGT2im5wV1YGGDora5vTv/aa5bE=
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
@@ -739,8 +743,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -774,8 +778,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -796,8 +800,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -846,18 +850,18 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -922,8 +926,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -1,5 +1,17 @@
Initialize machine room provisioning credentials
When you want the holos controller to provision while operating in the current
working directory, run:
1. `init-choria-provisioner-creds` to populate secrets in the Holos
Provisioner Cluster (not to be confused with the Choria Provisioner).
2. `make-provisioning-jwt` to issue a `provisioning.jwt` file for `holos
controller` to use.
3. `holos controller --config=agent.cfg` to read `provisioning.jwt` and write
the provisioned config file and credentials to the current directory.
Expect the controller to provision.
Setup Notes:
The holos server flag `--provisioner-seed` must match the issuer.seed value.

View File

@@ -6,6 +6,9 @@ export PROVISIONER_TOKEN="$(LC_ALL=C tr -dc "[:alpha:]" </dev/random | tr '[:upp
set -xeuo pipefail
# Make sure gomplate is available
gomplate --version
PARENT="$(cd $(dirname "$0") && pwd)"
TOPLEVEL="$(cd "${PARENT}" && git rev-parse --show-toplevel)"
: "${NAMESPACE:=jeff-holos}"
@@ -33,7 +36,7 @@ echo -n "${PROVISIONER_TOKEN}" > ./provisioner/token
# Provisioner signer
choria jwt keys ./provisioner/signer.seed ./provisioner/signer.public
choria jwt client ./provisioner/signer.jwt provisioner_signer ./issuer/issuer.seed \
--public-key "$(<provisioner/signer.public)" --server-provisioner --validity $((999*365))d --issuer
--public-key "$(<provisioner/signer.public)" --server-provisioner --validity $((100*365))d --issuer
# Provisioner Secret
mkdir -p provisioner/secret
@@ -57,5 +60,5 @@ choria jwt keys ./agents/signer.seed ./agents/signer.public
# Now save the secrets
holos create secret --append-hash=false --namespace $NAMESPACE choria-issuer --from-file=issuer
holos create secret --append-hash=false --namespace $NAMESPACE choria-broker --from-file=broker
holos create secret --append-hash=false --namespace $NAMESPACE choria-provisioner --from-file=provisioner
holos create secret --append-hash=false --namespace $NAMESPACE choria-provisioner --from-file=provisioner/secret
holos create secret --append-hash=false --namespace $NAMESPACE choria-agents --from-file=agents

View File

@@ -0,0 +1,50 @@
#! /bin/bash
#
# Make a provisioner.jwt and put it in the current directory.
#
# Use the provisioner.jwt with `holos controller --config=controller.cfg` which
# will read the jwt from the same directory as the config file.
#
# Refer to Arri's
# [setup.sh](https://github.com/ripienaar/machine-room-mvp/blob/main/example/setup/setup.sh#L41)
# And our own nites at https://github.com/holos-run/holos/issues/142
PARENT="$(cd $(dirname "$0") && pwd)"
OUTDIR="$(pwd)"
: "${NAMESPACE:=jeff-holos}"
tmpdir="$(mktemp -d)"
finish() {
[[ -d "$tmpdir" ]] && rm -rvf "$tmpdir"
}
trap finish EXIT
cd "$tmpdir"
set -xeuo pipefail
# e.g. jeff.provision.dev.k2.holos.run
#
kubectl -n $NAMESPACE get virtualservice choria-broker-wss -o json > vs.json
jq --exit-status -r '.spec.hosts[0]' vs.json > host
# Get the issuer.seed
holos -n $NAMESPACE get secret choria-issuer --to-file issuer.seed
# Get the provisioner token to embed in the provisioning.jwt file.
holos -n $NAMESPACE get secret choria-provisioner --to-file token
# The --token flag value must be the same value set in the token field of provisioner.yaml
# Refer to https://github.com/ripienaar/machine-room-mvp/blob/main/example/setup/setup.sh#L41
# Refer to https://github.com/ripienaar/machine-room-mvp/blob/main/example/setup/templates/provisioner/provisioner.yaml#L6
choria jwt prov provisioning.jwt "issuer.seed" \
--token "$(<token)" \
--urls wss://$(<host):443 \
--default \
--protocol-v2 \
--insecure \
--update \
--validity 30d \
--extensions '{}'
cp provisioning.jwt "${OUTDIR}/"

View File

@@ -0,0 +1,23 @@
#! /bin/bash
#
# This script resets the choria config for a Namespace
PARENT="$(cd $(dirname "$0") && pwd)"
: "${NAMESPACE:=jeff-holos}"
export NAMESPACE
set -xeuo pipefail
KUBECONFIG=$HOME/.holos/kubeconfig.provisioner kubectl delete secret -n jeff-holos choria-agents choria-broker choria-provisioner choria-issuer
"${PARENT}/init-choria-provisioner-creds"
stamp="$(date)"
kubectl -n $NAMESPACE annotate externalsecret choria-broker secret.holos.run/refresh="$stamp" --overwrite
kubectl -n $NAMESPACE annotate externalsecret choria-provisioner secret.holos.run/refresh="$stamp" --overwrite
kubectl -n $NAMESPACE wait --for='jsonpath={.status.conditions[?(@.type=="Ready")].status}=True' externalsecret choria-provisioner choria-broker
kubectl -n $NAMESPACE rollout restart statefulset choria-broker
kubectl -n $NAMESPACE rollout restart deployment choria-provisioner

View File

@@ -6,11 +6,13 @@ plugin.choria.network.client_port = 4222
plugin.choria.network.peer_port = 5222
plugin.choria.network.system.user = system
plugin.choria.network.system.password = system
plugin.choria.network.peers = nats://broker-0.broker:5222,nats://broker-1.broker:5222,nats://broker-2.broker:5222
plugin.choria.network.peers = nats://choria-broker-0.choria-broker:5222,nats://choria-broker-1.choria-broker:5222,nats://choria-broker-2.choria-broker:5222
plugin.choria.use_srv = false
plugin.choria.network.websocket_port = 4333
plugin.security.provider = choria
# NOTE: plugin.security.choria.ca must not be set or provisioning will fail
# with a unhandled choria_provisioning purpose token error
plugin.security.choria.certificate = /etc/choria-tls/tls.crt
plugin.security.choria.key = /etc/choria-tls/tls.key
plugin.security.choria.token_file = /etc/choria/broker.jwt

View File

@@ -4,4 +4,4 @@ plugin.security.choria.seed_file = /etc/provisioner/signer.seed
identity = provisioner_signer
plugin.choria.middleware_hosts = broker-0.broker:4222,broker-1.broker:4222,broker-2.broker:4222
plugin.choria.middleware_hosts = choria-broker-0.choria-broker:4222,choria-broker-1.choria-broker:4222,choria-broker-2.choria-broker:4222

View File

@@ -0,0 +1,9 @@
#! /bin/bash
#
set -xeuo pipefail
mkdir -p /home/choria/bin
install -m 0755 /etc/provisioner/helper.rb /home/choria/bin/helper.rb
exec /usr/sbin/choria-provisioner --config=/etc/provisioner/provisioner.yaml --choria-config=/etc/provisioner/choria.cfg

View File

@@ -0,0 +1,134 @@
#!/usr/bin/ruby
require "json"
require "yaml"
require "base64"
require "net/http"
require "openssl"
def parse_input
input = STDIN.read
begin
File.open("/tmp/request.json", "w") {|f| f.write(input)}
rescue Exception
end
request = JSON.parse(input)
request["inventory"] = JSON.parse(request["inventory"])
request
end
def validate!(request, reply)
if request["identity"] && request["identity"].length == 0
reply["msg"] = "No identity received in request"
reply["defer"] = true
return false
end
unless request["ed25519_pubkey"]
reply["msg"] = "No ed15519 public key received"
reply["defer"] = true
return false
end
unless request["ed25519_pubkey"]
reply["msg"] = "No ed15519 directory received"
reply["defer"] = true
return false
end
if request["ed25519_pubkey"]["directory"].length == 0
reply["msg"] = "No ed15519 directory received"
reply["defer"] = true
return false
end
true
end
def publish_reply(reply)
begin
File.open("/tmp/reply.json", "w") {|f| f.write(reply.to_json)}
rescue Exception
end
puts reply.to_json
end
def publish_reply!(reply)
publish_reply(reply)
exit
end
def set_config!(request, reply)
# stub data the helper will fetch from the saas
customers = {
"one" => {
:brokers => "nats://managed.example.net:9222", # whoever is the leader for this site
:site => "customer_one",
:source => {
:host => "nats://cust_one:s3cret@saas-nats.choria.local",
}
}
}
customer = request["jwt"]["extensions"]["customer"]
brokers = customers[customer][:brokers]
source = customers[customer][:source]
reply["configuration"].merge!(
"identity" => request["identity"],
"loglevel" => "warn",
"plugin.choria.server.provision" => "false",
"plugin.choria.middleware_hosts" => brokers,
"plugin.security.issuer.names" => "choria",
"plugin.security.issuer.choria.public" => "{{ .Env.ISSUER }}",
"plugin.security.provider" => "choria",
"plugin.security.choria.token_file" => File.join(request["ed25519_pubkey"]["directory"], "server.jwt"),
"plugin.security.choria.seed_file" => File.join(request["ed25519_pubkey"]["directory"], "server.seed"),
"machine_room.role" => "leader",
"machine_room.site" => customers[customer][:site],
"machine_room.source.host" => source[:host],
)
reply["server_claims"].merge!(
"exp" => 5*60*60*24*365,
"pub_subjects" => [">"],
"permissions" => {
"streams" => true,
"submission" => true,
"service_host" => true,
}
)
end
reply = {
"defer" => false,
"msg" => "",
"certificate" => "",
"ca" => "",
"configuration" => {},
"server_claims" => {}
}
begin
request = parse_input
reply["msg"] = "Validating"
unless validate!(request, reply)
publish_reply!(reply)
end
set_config!(request, reply)
reply["msg"] = "Done"
publish_reply!(reply)
rescue SystemExit
rescue Exception
reply["msg"] = "Unexpected failure during provisioning: %s: %s" % [$!.class, $!.to_s]
reply["defer"] = true
publish_reply!(reply)
end

View File

@@ -2,7 +2,8 @@ workers: 4
interval: 1m
logfile: /dev/stdout
loglevel: info
helper: /app/.venv/bin/helper
# The entrypoint script installs this helper script.
helper: /home/choria/bin/helper.rb
token: "{{ .Env.PROVISIONER_TOKEN }}"
choria_insecure: false
site: holos

View File

@@ -0,0 +1 @@
{{ .Env.PROVISIONER_TOKEN -}}

16
hack/setup/bare Executable file
View File

@@ -0,0 +1,16 @@
#! /bin/bash
set -euo pipefail
TOPLEVEL="$(cd $(dirname "$0") && git rev-parse --show-toplevel)"
host="jeff.app.dev.k2.holos.run:443"
read -p "Reset all data in $host? " choice
case "$choice" in
y|Y) echo "proceeding...";;
*) exit 1;;
esac
grpcurl -H "x-oidc-id-token: $(holos token)" $host holos.v1alpha1.SystemService.DropTables
grpcurl -H "x-oidc-id-token: $(holos token)" $host holos.v1alpha1.SystemService.SeedDatabase

View File

@@ -3,5 +3,6 @@ USER root
WORKDIR /app
ADD bin bin
RUN chown -R app: /app
USER app
# Kubernetes requires the user to be numeric
USER 8192
ENTRYPOINT bin/holos server

View File

@@ -101,15 +101,44 @@ spec:
gateways:
- istio-ingress/default
hosts:
- '{developer}.holos.dev.k2.ois.run'
- '{developer}.app.dev.k2.holos.run'
http:
- route:
- name: "coffee-ui"
match:
- uri:
prefix: "/ui"
route:
- destination:
host: coffee
port:
number: 4200
- name: "holos-api"
route:
- destination:
host: '{name}'
port:
number: {listen_port}
---
apiVersion: v1
kind: Service
metadata:
name: coffee
spec:
ports:
- protocol: TCP
port: 4200
---
apiVersion: v1
kind: Endpoints
metadata:
name: coffee
subsets:
- addresses:
- ip: 192.168.2.21
ports:
- port: 4200
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: holos
@@ -120,117 +149,6 @@ metadata:
imagePullSecrets:
- name: kube-system-ecr-image-pull-creds
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
labels:
app: '{name}'
holos.run/developer: '{developer}'
name: '{name}-allow-groups'
namespace: '{namespace}'
spec:
action: ALLOW
rules:
- when:
- key: request.auth.claims[groups]
values:
- holos-developer
- holos-developer@openinfrastructure.co
selector:
matchLabels:
holos.run/authz: dev-holos-sso
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: '{name}-allow-nothing'
namespace: '{namespace}'
labels:
app: '{name}'
holos.run/developer: '{developer}'
spec:
action: ALLOW
selector:
matchLabels:
holos.run/authz: dev-holos-sso
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: '{name}-allow-well-known-paths'
namespace: '{namespace}'
labels:
app: '{name}'
holos.run/developer: '{developer}'
spec:
action: ALLOW
rules:
- to:
- operation:
paths:
- /healthz
- /metrics
- /callbacks/github
selector:
matchLabels:
holos.run/authz: dev-holos-sso
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: '{name}-auth'
namespace: '{namespace}'
labels:
app: '{name}'
holos.run/developer: '{developer}'
spec:
action: CUSTOM
provider:
name: dev-holos-sso
rules:
- to:
- operation:
notPaths:
- /healthz
- /metrics
- /callbacks/github
when:
- key: request.headers[Authorization]
notValues:
- Bearer *
selector:
matchLabels:
holos.run/authz: dev-holos-sso
---
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: '{name}'
namespace: '{namespace}'
labels:
app: '{name}'
holos.run/developer: '{developer}'
spec:
jwtRules:
- audiences:
- https://sso.dev.holos.run
forwardOriginalToken: true
fromHeaders:
- name: x-auth-request-access-token
issuer: https://idex.core.ois.run
jwksUri: https://idex.core.ois.run/keys
- audiences:
- holos-cli
forwardOriginalToken: true
fromHeaders:
- name: authorization
prefix: 'Bearer '
issuer: https://idex.core.ois.run
jwksUri: https://idex.core.ois.run/keys
selector:
matchLabels:
holos.run/authz: dev-holos-sso
---
apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PGAdmin
metadata:

273
internal/builder/builder.go Normal file
View File

@@ -0,0 +1,273 @@
// Package builder is responsible for building fully rendered kubernetes api
// objects from various input directories. A directory may contain a platform
// spec or a component spec.
package builder
import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/load"
"github.com/holos-run/holos/api/v1alpha1"
"github.com/holos-run/holos"
"github.com/holos-run/holos/internal/errors"
"github.com/holos-run/holos/internal/logger"
)
const (
KubernetesObjects = v1alpha1.KubernetesObjectsKind
// Helm is the value of the kind field of holos build output indicating helm
// values and helm command information.
Helm = v1alpha1.HelmChartKind
// Skip is the value when the instance should be skipped
Skip = "Skip"
// KustomizeBuild is the value of the kind field of cue output indicating holos should process the component using kustomize build to render output.
KustomizeBuild = v1alpha1.KustomizeBuildKind
)
// An Option configures a Builder
type Option func(*config)
type config struct {
args []string
cluster string
}
type Builder struct {
cfg config
}
// New returns a new *Builder configured by opts Option.
func New(opts ...Option) *Builder {
var cfg config
for _, f := range opts {
f(&cfg)
}
b := &Builder{cfg: cfg}
return b
}
// Entrypoints configures the leaf directories Builder builds.
func Entrypoints(args []string) Option {
return func(cfg *config) { cfg.args = args }
}
// Cluster configures the cluster name for the holos component instance.
func Cluster(name string) Option {
return func(cfg *config) { cfg.cluster = name }
}
// Cluster returns the cluster name of the component instance being built.
func (b *Builder) Cluster() string {
return b.cfg.cluster
}
// Instances returns the cue build instances being built.
func (b *Builder) Instances(ctx context.Context) ([]*build.Instance, error) {
log := logger.FromContext(ctx)
mod, err := b.findCueMod()
if err != nil {
return nil, errors.Wrap(err)
}
dir := string(mod)
cfg := load.Config{Dir: dir}
// Make args relative to the module directory
args := make([]string, len(b.cfg.args))
for idx, path := range b.cfg.args {
target, err := filepath.Abs(path)
if err != nil {
return nil, errors.Wrap(fmt.Errorf("could not find absolute path: %w", err))
}
relPath, err := filepath.Rel(dir, target)
if err != nil {
return nil, errors.Wrap(fmt.Errorf("invalid argument, must be relative to cue.mod: %w", err))
}
relPath = "./" + relPath
args[idx] = relPath
equiv := fmt.Sprintf("cue export --out yaml -t cluster=%v %v", b.Cluster(), relPath)
log.Debug("cue: equivalent command: " + equiv)
}
// Refer to https://github.com/cue-lang/cue/blob/v0.7.0/cmd/cue/cmd/common.go#L429
cfg.Tags = append(cfg.Tags, "cluster="+b.Cluster())
log.DebugContext(ctx, fmt.Sprintf("cue: tags %v", cfg.Tags))
return load.Instances(args, &cfg), nil
}
func (b *Builder) Run(ctx context.Context) (results []*v1alpha1.Result, err error) {
log := logger.FromContext(ctx)
log.DebugContext(ctx, "cue: building instances")
instances, err := b.Instances(ctx)
if err != nil {
return nil, err
}
results = make([]*v1alpha1.Result, 0, len(instances)*8)
// Each CUE instance provides a BuildPlan
for idx, instance := range instances {
log.DebugContext(ctx, "cue: building instance", "idx", idx, "dir", instance.Dir)
r, err := b.runInstance(ctx, instance)
if err != nil {
return nil, errors.Wrap(fmt.Errorf("could not run: %w", err))
}
results = append(results, r...)
}
return results, nil
}
func (b Builder) runInstance(ctx context.Context, instance *build.Instance) (results []*v1alpha1.Result, err error) {
path := holos.InstancePath(instance.Dir)
log := logger.FromContext(ctx).With("dir", path)
if err := instance.Err; err != nil {
return nil, errors.Wrap(fmt.Errorf("could not load: %w", err))
}
cueCtx := cuecontext.New()
value := cueCtx.BuildInstance(instance)
if err := value.Err(); err != nil {
return nil, errors.Wrap(fmt.Errorf("could not build %s: %w", instance.Dir, err))
}
log.DebugContext(ctx, "cue: validating instance")
if err := value.Validate(); err != nil {
return nil, errors.Wrap(fmt.Errorf("could not validate: %w", err))
}
log.DebugContext(ctx, "cue: decoding holos build plan")
jsonBytes, err := value.MarshalJSON()
if err != nil {
return nil, errors.Wrap(fmt.Errorf("could not marshal cue instance %s: %w", instance.Dir, err))
}
decoder := json.NewDecoder(bytes.NewReader(jsonBytes))
// Discriminate the type of build plan.
tm := &v1alpha1.TypeMeta{}
err = decoder.Decode(tm)
if err != nil {
return nil, errors.Wrap(fmt.Errorf("invalid BuildPlan: %s: %w", instance.Dir, err))
}
log.DebugContext(ctx, "cue: discriminated build kind: "+tm.Kind, "kind", tm.Kind, "apiVersion", tm.APIVersion)
// New decoder for the full object
decoder = json.NewDecoder(bytes.NewReader(jsonBytes))
decoder.DisallowUnknownFields()
switch tm.Kind {
case "BuildPlan":
var bp v1alpha1.BuildPlan
if err = decoder.Decode(&bp); err != nil {
err = errors.Wrap(fmt.Errorf("could not decode BuildPlan %s: %w", instance.Dir, err))
return
}
results, err = b.buildPlan(ctx, &bp, path)
case "Platform":
var pf v1alpha1.Platform
if err = decoder.Decode(&pf); err != nil {
err = errors.Wrap(fmt.Errorf("could not decode Platform %s: %w", instance.Dir, err))
return
}
results, err = b.buildPlatform(ctx, &pf)
default:
err = errors.Wrap(fmt.Errorf("unknown kind: %v", tm.Kind))
}
return
}
func (b *Builder) buildPlatform(ctx context.Context, pf *v1alpha1.Platform) (results []*v1alpha1.Result, err error) {
log := logger.FromContext(ctx)
log.ErrorContext(ctx, "not implemented", "platform", pf)
return nil, errors.Wrap(fmt.Errorf("not implemeneted"))
}
func (b *Builder) buildPlan(ctx context.Context, buildPlan *v1alpha1.BuildPlan, path holos.InstancePath) (results []*v1alpha1.Result, err error) {
log := logger.FromContext(ctx)
if err := buildPlan.Validate(); err != nil {
log.WarnContext(ctx, "could not validate", "skipped", true, "err", err)
return nil, errors.Wrap(fmt.Errorf("could not validate %w", err))
}
if buildPlan.Spec.Disabled {
log.DebugContext(ctx, "skipped: spec.disabled is true", "skipped", true)
return
}
// TODO: concurrent renders
results = make([]*v1alpha1.Result, 0, buildPlan.ResultCapacity())
log.DebugContext(ctx, "allocated results slice", "cap", buildPlan.ResultCapacity())
for _, component := range buildPlan.Spec.Components.Resources {
if result, err := component.Render(ctx, path); err != nil {
return nil, errors.Wrap(fmt.Errorf("could not render: %w", err))
} else {
results = append(results, result)
}
}
for _, component := range buildPlan.Spec.Components.KubernetesObjectsList {
if result, err := component.Render(ctx, path); err != nil {
return nil, errors.Wrap(fmt.Errorf("could not render: %w", err))
} else {
results = append(results, result)
}
}
for _, component := range buildPlan.Spec.Components.HelmChartList {
if result, err := component.Render(ctx, path); err != nil {
return nil, errors.Wrap(fmt.Errorf("could not render: %w", err))
} else {
results = append(results, result)
}
}
for _, component := range buildPlan.Spec.Components.KustomizeBuildList {
if result, err := component.Render(ctx, path); err != nil {
return nil, errors.Wrap(fmt.Errorf("could not render: %w", err))
} else {
results = append(results, result)
}
}
log.DebugContext(ctx, "returning results", "len", len(results))
return results, nil
}
// findCueMod returns the root module location containing the cue.mod file or
// directory or an error if the builder arguments do not share a common root
// module.
func (b *Builder) findCueMod() (dir holos.PathCueMod, err error) {
for _, origPath := range b.cfg.args {
absPath, err := filepath.Abs(origPath)
if err != nil {
return "", err
}
path := holos.PathCueMod(absPath)
for {
if _, err := os.Stat(filepath.Join(string(path), "cue.mod")); err == nil {
if dir != "" && dir != path {
return "", fmt.Errorf("multiple modules not supported: %v is not %v", dir, path)
}
dir = path
break
} else if !os.IsNotExist(err) {
return "", err
}
parentPath := holos.PathCueMod(filepath.Dir(string(path)))
if parentPath == path {
return "", fmt.Errorf("no cue.mod from root to leaf: %v", origPath)
}
path = parentPath
}
}
return dir, nil
}

View File

@@ -2,12 +2,13 @@ package build
import (
"fmt"
"log/slog"
"strings"
"github.com/holos-run/holos/internal/builder"
"github.com/holos-run/holos/internal/cli/command"
"github.com/holos-run/holos/internal/errors"
"github.com/holos-run/holos/internal/holos"
"github.com/holos-run/holos/internal/internal/builder"
"github.com/spf13/cobra"
)
@@ -20,10 +21,12 @@ func makeBuildRunFunc(cfg *holos.Config) command.RunFunc {
return err
}
outs := make([]string, 0, len(results))
for _, result := range results {
if result.Skip {
for idx, result := range results {
if result == nil || result.Skip {
slog.Debug("skip result", "idx", idx, "result", result)
continue
}
slog.Debug("append result", "idx", idx, "result.kind", result.Kind)
outs = append(outs, result.AccumulatedOutput())
}
out := strings.Join(outs, "---\n")

View File

@@ -15,6 +15,7 @@ import (
// New returns a new login command.
func New(cfg *holos.Config) *cobra.Command {
cmd := command.New("login")
cmd.Short = "log in by caching credentials"
var printClaims bool
config := token.NewConfig()

View File

@@ -13,6 +13,7 @@ import (
func New(cfg *holos.Config) *cobra.Command {
cmd := command.New("logout")
cmd.Short = "log out by deleting cached credentials"
cmd.RunE = func(c *cobra.Command, args []string) error {
if err := os.RemoveAll(token.CacheDir); err != nil {
return errors.Wrap(fmt.Errorf("could not logout: %w", err))

View File

@@ -1,52 +1,18 @@
package render
import (
"context"
"flag"
"fmt"
"github.com/holos-run/holos/internal/builder"
"github.com/holos-run/holos/internal/cli/command"
"github.com/holos-run/holos/internal/errors"
"github.com/holos-run/holos/internal/holos"
"github.com/holos-run/holos/internal/internal/builder"
"github.com/holos-run/holos/internal/logger"
"github.com/spf13/cobra"
)
func makeRenderRunFunc(cfg *holos.Config) command.RunFunc {
return func(cmd *cobra.Command, args []string) error {
if cfg.ClusterName() == "" {
return errors.Wrap(fmt.Errorf("missing cluster name"))
}
ctx := cmd.Context()
log := logger.FromContext(ctx).With("cluster", cfg.ClusterName())
build := builder.New(builder.Entrypoints(args), builder.Cluster(cfg.ClusterName()))
results, err := build.Run(cmd.Context())
if err != nil {
return errors.Wrap(err)
}
// TODO: Avoid accidental over-writes if to holos component instances result in
// the same file path. Write files into a blank temporary directory, error if a
// file exists, then move the directory into place.
for _, result := range results {
if result.Skip {
continue
}
// API Objects
path := result.Filename(cfg.WriteTo(), cfg.ClusterName())
if err := result.Save(ctx, path, result.AccumulatedOutput()); err != nil {
return errors.Wrap(err)
}
// Kustomization
path = result.KustomizationFilename(cfg.WriteTo(), cfg.ClusterName())
if err := result.Save(ctx, path, result.KsContent); err != nil {
return errors.Wrap(err)
}
log.InfoContext(ctx, "rendered "+result.Name(), "status", "ok", "action", "rendered", "name", result.Name())
}
return nil
}
}
// New returns the render subcommand for the root command
func New(cfg *holos.Config) *cobra.Command {
cmd := command.New("render [directory...]")
@@ -55,6 +21,67 @@ func New(cfg *holos.Config) *cobra.Command {
cmd.Flags().SortFlags = false
cmd.Flags().AddGoFlagSet(cfg.WriteFlagSet())
cmd.Flags().AddGoFlagSet(cfg.ClusterFlagSet())
cmd.RunE = makeRenderRunFunc(cfg)
var printInstances bool
flagSet := flag.NewFlagSet("", flag.ContinueOnError)
flagSet.BoolVar(&printInstances, "print-instances", false, "expand /... paths for xargs")
cmd.Flags().AddGoFlagSet(flagSet)
cmd.RunE = func(cmd *cobra.Command, args []string) error {
if cfg.ClusterName() == "" {
return errors.Wrap(fmt.Errorf("missing cluster name"))
}
ctx := cmd.Context()
log := logger.FromContext(ctx).With("cluster", cfg.ClusterName())
build := builder.New(builder.Entrypoints(args), builder.Cluster(cfg.ClusterName()))
if printInstances {
instances, err := build.Instances(ctx)
if err != nil {
return errors.Wrap(err)
}
for _, instance := range instances {
fmt.Fprintln(cmd.OutOrStdout(), instance.Dir)
}
return nil
}
results, err := build.Run(cmd.Context())
if err != nil {
return errors.Wrap(err)
}
// TODO: Avoid accidental over-writes if to holos component instances result in
// the same file path. Write files into a blank temporary directory, error if a
// file exists, then move the directory into place.
var result Result
for _, result = range results {
if result.Continue() {
continue
}
// API Objects
path := result.Filename(cfg.WriteTo(), cfg.ClusterName())
if err := result.Save(ctx, path, result.AccumulatedOutput()); err != nil {
return errors.Wrap(err)
}
// Kustomization
path = result.KustomizationFilename(cfg.WriteTo(), cfg.ClusterName())
if err := result.Save(ctx, path, result.KustomizationContent()); err != nil {
return errors.Wrap(err)
}
log.InfoContext(ctx, "rendered "+result.Name(), "status", "ok", "action", "rendered", "name", result.Name())
}
return nil
}
return cmd
}
type Result interface {
Continue() bool
Name() string
Filename(writeTo string, cluster string) string
KustomizationFilename(writeTo string, cluster string) string
Save(ctx context.Context, path string, content string) error
AccumulatedOutput() string
KustomizationContent() string
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/holos-run/holos/internal/cli/logout"
"github.com/holos-run/holos/internal/cli/preflight"
"github.com/holos-run/holos/internal/cli/render"
"github.com/holos-run/holos/internal/cli/token"
"github.com/holos-run/holos/internal/cli/txtar"
"github.com/holos-run/holos/internal/holos"
"github.com/holos-run/holos/internal/logger"
@@ -61,6 +62,7 @@ func New(cfg *holos.Config) *cobra.Command {
rootCmd.AddCommand(preflight.New(cfg))
rootCmd.AddCommand(login.New(cfg))
rootCmd.AddCommand(logout.New(cfg))
rootCmd.AddCommand(token.New(cfg))
// Maybe not needed?
rootCmd.AddCommand(txtar.New(cfg))

View File

@@ -0,0 +1,44 @@
package token
import (
"context"
"flag"
"fmt"
"log/slog"
"github.com/holos-run/holos/internal/cli/command"
"github.com/holos-run/holos/internal/holos"
"github.com/holos-run/holos/internal/token"
"github.com/spf13/cobra"
)
// New returns a new login command.
func New(cfg *holos.Config) *cobra.Command {
cmd := command.New("token")
cmd.Short = "write id token to stdout"
cmd.Long = "Useful with curl / grpcurl -H $(holos token)"
config := token.NewConfig()
cmd.Flags().AddGoFlagSet(config.FlagSet())
fs := &flag.FlagSet{}
cmd.Flags().AddGoFlagSet(fs)
cmd.RunE = func(c *cobra.Command, args []string) error {
ctx := c.Context()
if ctx == nil {
ctx = context.Background()
}
token, err := token.Get(ctx, cfg.Logger(), config)
if err != nil {
slog.Error("could not get token", "err", err)
return fmt.Errorf("could not get token: %w", err)
}
fmt.Fprintf(cmd.OutOrStdout(), token.Bearer)
return nil
}
return cmd
}

View File

@@ -15,7 +15,9 @@ import (
"entgo.io/ent"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/user"
)
@@ -26,6 +28,8 @@ type Client struct {
Schema *migrate.Schema
// Organization is the client for interacting with the Organization builders.
Organization *OrganizationClient
// Platform is the client for interacting with the Platform builders.
Platform *PlatformClient
// User is the client for interacting with the User builders.
User *UserClient
}
@@ -40,6 +44,7 @@ func NewClient(opts ...Option) *Client {
func (c *Client) init() {
c.Schema = migrate.NewSchema(c.driver)
c.Organization = NewOrganizationClient(c.config)
c.Platform = NewPlatformClient(c.config)
c.User = NewUserClient(c.config)
}
@@ -134,6 +139,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
ctx: ctx,
config: cfg,
Organization: NewOrganizationClient(cfg),
Platform: NewPlatformClient(cfg),
User: NewUserClient(cfg),
}, nil
}
@@ -155,6 +161,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
ctx: ctx,
config: cfg,
Organization: NewOrganizationClient(cfg),
Platform: NewPlatformClient(cfg),
User: NewUserClient(cfg),
}, nil
}
@@ -185,6 +192,7 @@ func (c *Client) Close() error {
// In order to add hooks to a specific client, call: `client.Node.Use(...)`.
func (c *Client) Use(hooks ...Hook) {
c.Organization.Use(hooks...)
c.Platform.Use(hooks...)
c.User.Use(hooks...)
}
@@ -192,6 +200,7 @@ func (c *Client) Use(hooks ...Hook) {
// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.
func (c *Client) Intercept(interceptors ...Interceptor) {
c.Organization.Intercept(interceptors...)
c.Platform.Intercept(interceptors...)
c.User.Intercept(interceptors...)
}
@@ -200,6 +209,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
switch m := m.(type) {
case *OrganizationMutation:
return c.Organization.mutate(ctx, m)
case *PlatformMutation:
return c.Platform.mutate(ctx, m)
case *UserMutation:
return c.User.mutate(ctx, m)
default:
@@ -315,6 +326,54 @@ func (c *OrganizationClient) GetX(ctx context.Context, id uuid.UUID) *Organizati
return obj
}
// QueryCreator queries the creator edge of a Organization.
func (c *OrganizationClient) QueryCreator(o *Organization) *UserQuery {
query := (&UserClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := o.ID
step := sqlgraph.NewStep(
sqlgraph.From(organization.Table, organization.FieldID, id),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, organization.CreatorTable, organization.CreatorColumn),
)
fromV = sqlgraph.Neighbors(o.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryUsers queries the users edge of a Organization.
func (c *OrganizationClient) QueryUsers(o *Organization) *UserQuery {
query := (&UserClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := o.ID
step := sqlgraph.NewStep(
sqlgraph.From(organization.Table, organization.FieldID, id),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2M, false, organization.UsersTable, organization.UsersPrimaryKey...),
)
fromV = sqlgraph.Neighbors(o.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryPlatforms queries the platforms edge of a Organization.
func (c *OrganizationClient) QueryPlatforms(o *Organization) *PlatformQuery {
query := (&PlatformClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := o.ID
step := sqlgraph.NewStep(
sqlgraph.From(organization.Table, organization.FieldID, id),
sqlgraph.To(platform.Table, platform.FieldID),
sqlgraph.Edge(sqlgraph.O2M, true, organization.PlatformsTable, organization.PlatformsColumn),
)
fromV = sqlgraph.Neighbors(o.driver.Dialect(), step)
return fromV, nil
}
return query
}
// Hooks returns the client hooks.
func (c *OrganizationClient) Hooks() []Hook {
return c.hooks.Organization
@@ -340,6 +399,171 @@ func (c *OrganizationClient) mutate(ctx context.Context, m *OrganizationMutation
}
}
// PlatformClient is a client for the Platform schema.
type PlatformClient struct {
config
}
// NewPlatformClient returns a client for the Platform from the given config.
func NewPlatformClient(c config) *PlatformClient {
return &PlatformClient{config: c}
}
// Use adds a list of mutation hooks to the hooks stack.
// A call to `Use(f, g, h)` equals to `platform.Hooks(f(g(h())))`.
func (c *PlatformClient) Use(hooks ...Hook) {
c.hooks.Platform = append(c.hooks.Platform, hooks...)
}
// Intercept adds a list of query interceptors to the interceptors stack.
// A call to `Intercept(f, g, h)` equals to `platform.Intercept(f(g(h())))`.
func (c *PlatformClient) Intercept(interceptors ...Interceptor) {
c.inters.Platform = append(c.inters.Platform, interceptors...)
}
// Create returns a builder for creating a Platform entity.
func (c *PlatformClient) Create() *PlatformCreate {
mutation := newPlatformMutation(c.config, OpCreate)
return &PlatformCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// CreateBulk returns a builder for creating a bulk of Platform entities.
func (c *PlatformClient) CreateBulk(builders ...*PlatformCreate) *PlatformCreateBulk {
return &PlatformCreateBulk{config: c.config, builders: builders}
}
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *PlatformClient) MapCreateBulk(slice any, setFunc func(*PlatformCreate, int)) *PlatformCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &PlatformCreateBulk{err: fmt.Errorf("calling to PlatformClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*PlatformCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &PlatformCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for Platform.
func (c *PlatformClient) Update() *PlatformUpdate {
mutation := newPlatformMutation(c.config, OpUpdate)
return &PlatformUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOne returns an update builder for the given entity.
func (c *PlatformClient) UpdateOne(pl *Platform) *PlatformUpdateOne {
mutation := newPlatformMutation(c.config, OpUpdateOne, withPlatform(pl))
return &PlatformUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOneID returns an update builder for the given id.
func (c *PlatformClient) UpdateOneID(id uuid.UUID) *PlatformUpdateOne {
mutation := newPlatformMutation(c.config, OpUpdateOne, withPlatformID(id))
return &PlatformUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// Delete returns a delete builder for Platform.
func (c *PlatformClient) Delete() *PlatformDelete {
mutation := newPlatformMutation(c.config, OpDelete)
return &PlatformDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// DeleteOne returns a builder for deleting the given entity.
func (c *PlatformClient) DeleteOne(pl *Platform) *PlatformDeleteOne {
return c.DeleteOneID(pl.ID)
}
// DeleteOneID returns a builder for deleting the given entity by its id.
func (c *PlatformClient) DeleteOneID(id uuid.UUID) *PlatformDeleteOne {
builder := c.Delete().Where(platform.ID(id))
builder.mutation.id = &id
builder.mutation.op = OpDeleteOne
return &PlatformDeleteOne{builder}
}
// Query returns a query builder for Platform.
func (c *PlatformClient) Query() *PlatformQuery {
return &PlatformQuery{
config: c.config,
ctx: &QueryContext{Type: TypePlatform},
inters: c.Interceptors(),
}
}
// Get returns a Platform entity by its id.
func (c *PlatformClient) Get(ctx context.Context, id uuid.UUID) (*Platform, error) {
return c.Query().Where(platform.ID(id)).Only(ctx)
}
// GetX is like Get, but panics if an error occurs.
func (c *PlatformClient) GetX(ctx context.Context, id uuid.UUID) *Platform {
obj, err := c.Get(ctx, id)
if err != nil {
panic(err)
}
return obj
}
// QueryCreator queries the creator edge of a Platform.
func (c *PlatformClient) QueryCreator(pl *Platform) *UserQuery {
query := (&UserClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := pl.ID
step := sqlgraph.NewStep(
sqlgraph.From(platform.Table, platform.FieldID, id),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, platform.CreatorTable, platform.CreatorColumn),
)
fromV = sqlgraph.Neighbors(pl.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryOrganization queries the organization edge of a Platform.
func (c *PlatformClient) QueryOrganization(pl *Platform) *OrganizationQuery {
query := (&OrganizationClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := pl.ID
step := sqlgraph.NewStep(
sqlgraph.From(platform.Table, platform.FieldID, id),
sqlgraph.To(organization.Table, organization.FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, platform.OrganizationTable, platform.OrganizationColumn),
)
fromV = sqlgraph.Neighbors(pl.driver.Dialect(), step)
return fromV, nil
}
return query
}
// Hooks returns the client hooks.
func (c *PlatformClient) Hooks() []Hook {
return c.hooks.Platform
}
// Interceptors returns the client interceptors.
func (c *PlatformClient) Interceptors() []Interceptor {
return c.inters.Platform
}
func (c *PlatformClient) mutate(ctx context.Context, m *PlatformMutation) (Value, error) {
switch m.Op() {
case OpCreate:
return (&PlatformCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdate:
return (&PlatformUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdateOne:
return (&PlatformUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpDelete, OpDeleteOne:
return (&PlatformDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
default:
return nil, fmt.Errorf("ent: unknown Platform mutation op: %q", m.Op())
}
}
// UserClient is a client for the User schema.
type UserClient struct {
config
@@ -448,6 +672,22 @@ func (c *UserClient) GetX(ctx context.Context, id uuid.UUID) *User {
return obj
}
// QueryOrganizations queries the organizations edge of a User.
func (c *UserClient) QueryOrganizations(u *User) *OrganizationQuery {
query := (&OrganizationClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := u.ID
step := sqlgraph.NewStep(
sqlgraph.From(user.Table, user.FieldID, id),
sqlgraph.To(organization.Table, organization.FieldID),
sqlgraph.Edge(sqlgraph.M2M, true, user.OrganizationsTable, user.OrganizationsPrimaryKey...),
)
fromV = sqlgraph.Neighbors(u.driver.Dialect(), step)
return fromV, nil
}
return query
}
// Hooks returns the client hooks.
func (c *UserClient) Hooks() []Hook {
return c.hooks.User
@@ -476,9 +716,9 @@ func (c *UserClient) mutate(ctx context.Context, m *UserMutation) (Value, error)
// hooks and interceptors per client, for fast access.
type (
hooks struct {
Organization, User []ent.Hook
Organization, Platform, User []ent.Hook
}
inters struct {
Organization, User []ent.Interceptor
Organization, Platform, User []ent.Interceptor
}
)

View File

@@ -13,6 +13,7 @@ import (
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/user"
)
@@ -75,6 +76,7 @@ func checkColumn(table, column string) error {
initCheck.Do(func() {
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
organization.Table: organization.ValidColumn,
platform.Table: platform.ValidColumn,
user.Table: user.ValidColumn,
})
})

View File

@@ -21,6 +21,18 @@ func (f OrganizationFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.OrganizationMutation", m)
}
// The PlatformFunc type is an adapter to allow the use of ordinary
// function as Platform mutator.
type PlatformFunc func(context.Context, *ent.PlatformMutation) (ent.Value, error)
// Mutate calls f(ctx, m).
func (f PlatformFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if mv, ok := m.(*ent.PlatformMutation); ok {
return f(ctx, mv)
}
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.PlatformMutation", m)
}
// The UserFunc type is an adapter to allow the use of ordinary
// function as User mutator.
type UserFunc func(context.Context, *ent.UserMutation) (ent.Value, error)

View File

@@ -15,12 +15,62 @@ var (
{Name: "updated_at", Type: field.TypeTime},
{Name: "name", Type: field.TypeString, Unique: true},
{Name: "display_name", Type: field.TypeString},
{Name: "creator_id", Type: field.TypeUUID},
}
// OrganizationsTable holds the schema information for the "organizations" table.
OrganizationsTable = &schema.Table{
Name: "organizations",
Columns: OrganizationsColumns,
PrimaryKey: []*schema.Column{OrganizationsColumns[0]},
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "organizations_users_creator",
Columns: []*schema.Column{OrganizationsColumns[5]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.NoAction,
},
},
}
// PlatformsColumns holds the columns for the "platforms" table.
PlatformsColumns = []*schema.Column{
{Name: "id", Type: field.TypeUUID},
{Name: "created_at", Type: field.TypeTime},
{Name: "updated_at", Type: field.TypeTime},
{Name: "name", Type: field.TypeString},
{Name: "display_name", Type: field.TypeString},
{Name: "form", Type: field.TypeJSON, Nullable: true},
{Name: "model", Type: field.TypeJSON, Nullable: true},
{Name: "cue", Type: field.TypeBytes, Nullable: true},
{Name: "cue_definition", Type: field.TypeString, Nullable: true},
{Name: "creator_id", Type: field.TypeUUID},
{Name: "org_id", Type: field.TypeUUID},
}
// PlatformsTable holds the schema information for the "platforms" table.
PlatformsTable = &schema.Table{
Name: "platforms",
Columns: PlatformsColumns,
PrimaryKey: []*schema.Column{PlatformsColumns[0]},
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "platforms_users_creator",
Columns: []*schema.Column{PlatformsColumns[9]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.NoAction,
},
{
Symbol: "platforms_organizations_organization",
Columns: []*schema.Column{PlatformsColumns[10]},
RefColumns: []*schema.Column{OrganizationsColumns[0]},
OnDelete: schema.NoAction,
},
},
Indexes: []*schema.Index{
{
Name: "platform_org_id_name",
Unique: true,
Columns: []*schema.Column{PlatformsColumns[10], PlatformsColumns[3]},
},
},
}
// UsersColumns holds the columns for the "users" table.
UsersColumns = []*schema.Column{
@@ -37,13 +87,52 @@ var (
Name: "users",
Columns: UsersColumns,
PrimaryKey: []*schema.Column{UsersColumns[0]},
Indexes: []*schema.Index{
{
Name: "user_iss_sub",
Unique: true,
Columns: []*schema.Column{UsersColumns[4], UsersColumns[5]},
},
},
}
// OrganizationUsersColumns holds the columns for the "organization_users" table.
OrganizationUsersColumns = []*schema.Column{
{Name: "organization_id", Type: field.TypeUUID},
{Name: "user_id", Type: field.TypeUUID},
}
// OrganizationUsersTable holds the schema information for the "organization_users" table.
OrganizationUsersTable = &schema.Table{
Name: "organization_users",
Columns: OrganizationUsersColumns,
PrimaryKey: []*schema.Column{OrganizationUsersColumns[0], OrganizationUsersColumns[1]},
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "organization_users_organization_id",
Columns: []*schema.Column{OrganizationUsersColumns[0]},
RefColumns: []*schema.Column{OrganizationsColumns[0]},
OnDelete: schema.Cascade,
},
{
Symbol: "organization_users_user_id",
Columns: []*schema.Column{OrganizationUsersColumns[1]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.Cascade,
},
},
}
// Tables holds all the tables in the schema.
Tables = []*schema.Table{
OrganizationsTable,
PlatformsTable,
UsersTable,
OrganizationUsersTable,
}
)
func init() {
OrganizationsTable.ForeignKeys[0].RefTable = UsersTable
PlatformsTable.ForeignKeys[0].RefTable = UsersTable
PlatformsTable.ForeignKeys[1].RefTable = OrganizationsTable
OrganizationUsersTable.ForeignKeys[0].RefTable = OrganizationsTable
OrganizationUsersTable.ForeignKeys[1].RefTable = UsersTable
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@ import (
"entgo.io/ent/dialect/sql"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/user"
)
// Organization is the model entity for the Organization schema.
@@ -25,10 +26,57 @@ type Organization struct {
// Name holds the value of the "name" field.
Name string `json:"name,omitempty"`
// DisplayName holds the value of the "display_name" field.
DisplayName string `json:"display_name,omitempty"`
DisplayName string `json:"display_name,omitempty"`
// CreatorID holds the value of the "creator_id" field.
CreatorID uuid.UUID `json:"creator_id,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the OrganizationQuery when eager-loading is set.
Edges OrganizationEdges `json:"edges"`
selectValues sql.SelectValues
}
// OrganizationEdges holds the relations/edges for other nodes in the graph.
type OrganizationEdges struct {
// Creator holds the value of the creator edge.
Creator *User `json:"creator,omitempty"`
// Users holds the value of the users edge.
Users []*User `json:"users,omitempty"`
// Platforms holds the value of the platforms edge.
Platforms []*Platform `json:"platforms,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [3]bool
}
// CreatorOrErr returns the Creator value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e OrganizationEdges) CreatorOrErr() (*User, error) {
if e.Creator != nil {
return e.Creator, nil
} else if e.loadedTypes[0] {
return nil, &NotFoundError{label: user.Label}
}
return nil, &NotLoadedError{edge: "creator"}
}
// UsersOrErr returns the Users value or an error if the edge
// was not loaded in eager-loading.
func (e OrganizationEdges) UsersOrErr() ([]*User, error) {
if e.loadedTypes[1] {
return e.Users, nil
}
return nil, &NotLoadedError{edge: "users"}
}
// PlatformsOrErr returns the Platforms value or an error if the edge
// was not loaded in eager-loading.
func (e OrganizationEdges) PlatformsOrErr() ([]*Platform, error) {
if e.loadedTypes[2] {
return e.Platforms, nil
}
return nil, &NotLoadedError{edge: "platforms"}
}
// scanValues returns the types for scanning values from sql.Rows.
func (*Organization) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
@@ -38,7 +86,7 @@ func (*Organization) scanValues(columns []string) ([]any, error) {
values[i] = new(sql.NullString)
case organization.FieldCreatedAt, organization.FieldUpdatedAt:
values[i] = new(sql.NullTime)
case organization.FieldID:
case organization.FieldID, organization.FieldCreatorID:
values[i] = new(uuid.UUID)
default:
values[i] = new(sql.UnknownType)
@@ -85,6 +133,12 @@ func (o *Organization) assignValues(columns []string, values []any) error {
} else if value.Valid {
o.DisplayName = value.String
}
case organization.FieldCreatorID:
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field creator_id", values[i])
} else if value != nil {
o.CreatorID = *value
}
default:
o.selectValues.Set(columns[i], values[i])
}
@@ -98,6 +152,21 @@ func (o *Organization) Value(name string) (ent.Value, error) {
return o.selectValues.Get(name)
}
// QueryCreator queries the "creator" edge of the Organization entity.
func (o *Organization) QueryCreator() *UserQuery {
return NewOrganizationClient(o.config).QueryCreator(o)
}
// QueryUsers queries the "users" edge of the Organization entity.
func (o *Organization) QueryUsers() *UserQuery {
return NewOrganizationClient(o.config).QueryUsers(o)
}
// QueryPlatforms queries the "platforms" edge of the Organization entity.
func (o *Organization) QueryPlatforms() *PlatformQuery {
return NewOrganizationClient(o.config).QueryPlatforms(o)
}
// Update returns a builder for updating this Organization.
// Note that you need to call Organization.Unwrap() before calling this method if this Organization
// was returned from a transaction, and the transaction was committed or rolled back.
@@ -132,6 +201,9 @@ func (o *Organization) String() string {
builder.WriteString(", ")
builder.WriteString("display_name=")
builder.WriteString(o.DisplayName)
builder.WriteString(", ")
builder.WriteString("creator_id=")
builder.WriteString(fmt.Sprintf("%v", o.CreatorID))
builder.WriteByte(')')
return builder.String()
}

View File

@@ -6,6 +6,7 @@ import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/gofrs/uuid"
)
@@ -22,8 +23,35 @@ const (
FieldName = "name"
// FieldDisplayName holds the string denoting the display_name field in the database.
FieldDisplayName = "display_name"
// FieldCreatorID holds the string denoting the creator_id field in the database.
FieldCreatorID = "creator_id"
// EdgeCreator holds the string denoting the creator edge name in mutations.
EdgeCreator = "creator"
// EdgeUsers holds the string denoting the users edge name in mutations.
EdgeUsers = "users"
// EdgePlatforms holds the string denoting the platforms edge name in mutations.
EdgePlatforms = "platforms"
// Table holds the table name of the organization in the database.
Table = "organizations"
// CreatorTable is the table that holds the creator relation/edge.
CreatorTable = "organizations"
// CreatorInverseTable is the table name for the User entity.
// It exists in this package in order to avoid circular dependency with the "user" package.
CreatorInverseTable = "users"
// CreatorColumn is the table column denoting the creator relation/edge.
CreatorColumn = "creator_id"
// UsersTable is the table that holds the users relation/edge. The primary key declared below.
UsersTable = "organization_users"
// UsersInverseTable is the table name for the User entity.
// It exists in this package in order to avoid circular dependency with the "user" package.
UsersInverseTable = "users"
// PlatformsTable is the table that holds the platforms relation/edge.
PlatformsTable = "platforms"
// PlatformsInverseTable is the table name for the Platform entity.
// It exists in this package in order to avoid circular dependency with the "platform" package.
PlatformsInverseTable = "platforms"
// PlatformsColumn is the table column denoting the platforms relation/edge.
PlatformsColumn = "org_id"
)
// Columns holds all SQL columns for organization fields.
@@ -33,8 +61,15 @@ var Columns = []string{
FieldUpdatedAt,
FieldName,
FieldDisplayName,
FieldCreatorID,
}
var (
// UsersPrimaryKey and UsersColumn2 are the table columns denoting the
// primary key for the users relation (M2M).
UsersPrimaryKey = []string{"organization_id", "user_id"}
)
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
@@ -85,3 +120,64 @@ func ByName(opts ...sql.OrderTermOption) OrderOption {
func ByDisplayName(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDisplayName, opts...).ToFunc()
}
// ByCreatorID orders the results by the creator_id field.
func ByCreatorID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCreatorID, opts...).ToFunc()
}
// ByCreatorField orders the results by creator field.
func ByCreatorField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newCreatorStep(), sql.OrderByField(field, opts...))
}
}
// ByUsersCount orders the results by users count.
func ByUsersCount(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborsCount(s, newUsersStep(), opts...)
}
}
// ByUsers orders the results by users terms.
func ByUsers(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newUsersStep(), append([]sql.OrderTerm{term}, terms...)...)
}
}
// ByPlatformsCount orders the results by platforms count.
func ByPlatformsCount(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborsCount(s, newPlatformsStep(), opts...)
}
}
// ByPlatforms orders the results by platforms terms.
func ByPlatforms(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newPlatformsStep(), append([]sql.OrderTerm{term}, terms...)...)
}
}
func newCreatorStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(CreatorInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, CreatorTable, CreatorColumn),
)
}
func newUsersStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(UsersInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2M, false, UsersTable, UsersPrimaryKey...),
)
}
func newPlatformsStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(PlatformsInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.O2M, true, PlatformsTable, PlatformsColumn),
)
}

View File

@@ -6,6 +6,7 @@ import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/predicate"
)
@@ -75,6 +76,11 @@ func DisplayName(v string) predicate.Organization {
return predicate.Organization(sql.FieldEQ(FieldDisplayName, v))
}
// CreatorID applies equality check predicate on the "creator_id" field. It's identical to CreatorIDEQ.
func CreatorID(v uuid.UUID) predicate.Organization {
return predicate.Organization(sql.FieldEQ(FieldCreatorID, v))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.Organization {
return predicate.Organization(sql.FieldEQ(FieldCreatedAt, v))
@@ -285,6 +291,95 @@ func DisplayNameContainsFold(v string) predicate.Organization {
return predicate.Organization(sql.FieldContainsFold(FieldDisplayName, v))
}
// CreatorIDEQ applies the EQ predicate on the "creator_id" field.
func CreatorIDEQ(v uuid.UUID) predicate.Organization {
return predicate.Organization(sql.FieldEQ(FieldCreatorID, v))
}
// CreatorIDNEQ applies the NEQ predicate on the "creator_id" field.
func CreatorIDNEQ(v uuid.UUID) predicate.Organization {
return predicate.Organization(sql.FieldNEQ(FieldCreatorID, v))
}
// CreatorIDIn applies the In predicate on the "creator_id" field.
func CreatorIDIn(vs ...uuid.UUID) predicate.Organization {
return predicate.Organization(sql.FieldIn(FieldCreatorID, vs...))
}
// CreatorIDNotIn applies the NotIn predicate on the "creator_id" field.
func CreatorIDNotIn(vs ...uuid.UUID) predicate.Organization {
return predicate.Organization(sql.FieldNotIn(FieldCreatorID, vs...))
}
// HasCreator applies the HasEdge predicate on the "creator" edge.
func HasCreator() predicate.Organization {
return predicate.Organization(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, CreatorTable, CreatorColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasCreatorWith applies the HasEdge predicate on the "creator" edge with a given conditions (other predicates).
func HasCreatorWith(preds ...predicate.User) predicate.Organization {
return predicate.Organization(func(s *sql.Selector) {
step := newCreatorStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// HasUsers applies the HasEdge predicate on the "users" edge.
func HasUsers() predicate.Organization {
return predicate.Organization(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2M, false, UsersTable, UsersPrimaryKey...),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasUsersWith applies the HasEdge predicate on the "users" edge with a given conditions (other predicates).
func HasUsersWith(preds ...predicate.User) predicate.Organization {
return predicate.Organization(func(s *sql.Selector) {
step := newUsersStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// HasPlatforms applies the HasEdge predicate on the "platforms" edge.
func HasPlatforms() predicate.Organization {
return predicate.Organization(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.O2M, true, PlatformsTable, PlatformsColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasPlatformsWith applies the HasEdge predicate on the "platforms" edge with a given conditions (other predicates).
func HasPlatformsWith(preds ...predicate.Platform) predicate.Organization {
return predicate.Organization(func(s *sql.Selector) {
step := newPlatformsStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// And groups predicates with the AND operator between them.
func And(predicates ...predicate.Organization) predicate.Organization {
return predicate.Organization(sql.AndPredicates(predicates...))

View File

@@ -14,6 +14,8 @@ import (
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/user"
)
// OrganizationCreate is the builder for creating a Organization entity.
@@ -64,6 +66,12 @@ func (oc *OrganizationCreate) SetDisplayName(s string) *OrganizationCreate {
return oc
}
// SetCreatorID sets the "creator_id" field.
func (oc *OrganizationCreate) SetCreatorID(u uuid.UUID) *OrganizationCreate {
oc.mutation.SetCreatorID(u)
return oc
}
// SetID sets the "id" field.
func (oc *OrganizationCreate) SetID(u uuid.UUID) *OrganizationCreate {
oc.mutation.SetID(u)
@@ -78,6 +86,41 @@ func (oc *OrganizationCreate) SetNillableID(u *uuid.UUID) *OrganizationCreate {
return oc
}
// SetCreator sets the "creator" edge to the User entity.
func (oc *OrganizationCreate) SetCreator(u *User) *OrganizationCreate {
return oc.SetCreatorID(u.ID)
}
// AddUserIDs adds the "users" edge to the User entity by IDs.
func (oc *OrganizationCreate) AddUserIDs(ids ...uuid.UUID) *OrganizationCreate {
oc.mutation.AddUserIDs(ids...)
return oc
}
// AddUsers adds the "users" edges to the User entity.
func (oc *OrganizationCreate) AddUsers(u ...*User) *OrganizationCreate {
ids := make([]uuid.UUID, len(u))
for i := range u {
ids[i] = u[i].ID
}
return oc.AddUserIDs(ids...)
}
// AddPlatformIDs adds the "platforms" edge to the Platform entity by IDs.
func (oc *OrganizationCreate) AddPlatformIDs(ids ...uuid.UUID) *OrganizationCreate {
oc.mutation.AddPlatformIDs(ids...)
return oc
}
// AddPlatforms adds the "platforms" edges to the Platform entity.
func (oc *OrganizationCreate) AddPlatforms(p ...*Platform) *OrganizationCreate {
ids := make([]uuid.UUID, len(p))
for i := range p {
ids[i] = p[i].ID
}
return oc.AddPlatformIDs(ids...)
}
// Mutation returns the OrganizationMutation object of the builder.
func (oc *OrganizationCreate) Mutation() *OrganizationMutation {
return oc.mutation
@@ -146,6 +189,12 @@ func (oc *OrganizationCreate) check() error {
if _, ok := oc.mutation.DisplayName(); !ok {
return &ValidationError{Name: "display_name", err: errors.New(`ent: missing required field "Organization.display_name"`)}
}
if _, ok := oc.mutation.CreatorID(); !ok {
return &ValidationError{Name: "creator_id", err: errors.New(`ent: missing required field "Organization.creator_id"`)}
}
if _, ok := oc.mutation.CreatorID(); !ok {
return &ValidationError{Name: "creator", err: errors.New(`ent: missing required edge "Organization.creator"`)}
}
return nil
}
@@ -198,6 +247,55 @@ func (oc *OrganizationCreate) createSpec() (*Organization, *sqlgraph.CreateSpec)
_spec.SetField(organization.FieldDisplayName, field.TypeString, value)
_node.DisplayName = value
}
if nodes := oc.mutation.CreatorIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: organization.CreatorTable,
Columns: []string{organization.CreatorColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_node.CreatorID = nodes[0]
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := oc.mutation.UsersIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: false,
Table: organization.UsersTable,
Columns: organization.UsersPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := oc.mutation.PlatformsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: true,
Table: organization.PlatformsTable,
Columns: []string{organization.PlatformsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges = append(_spec.Edges, edge)
}
return _node, _spec
}
@@ -286,6 +384,18 @@ func (u *OrganizationUpsert) UpdateDisplayName() *OrganizationUpsert {
return u
}
// SetCreatorID sets the "creator_id" field.
func (u *OrganizationUpsert) SetCreatorID(v uuid.UUID) *OrganizationUpsert {
u.Set(organization.FieldCreatorID, v)
return u
}
// UpdateCreatorID sets the "creator_id" field to the value that was provided on create.
func (u *OrganizationUpsert) UpdateCreatorID() *OrganizationUpsert {
u.SetExcluded(organization.FieldCreatorID)
return u
}
// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field.
// Using this option is equivalent to using:
//
@@ -379,6 +489,20 @@ func (u *OrganizationUpsertOne) UpdateDisplayName() *OrganizationUpsertOne {
})
}
// SetCreatorID sets the "creator_id" field.
func (u *OrganizationUpsertOne) SetCreatorID(v uuid.UUID) *OrganizationUpsertOne {
return u.Update(func(s *OrganizationUpsert) {
s.SetCreatorID(v)
})
}
// UpdateCreatorID sets the "creator_id" field to the value that was provided on create.
func (u *OrganizationUpsertOne) UpdateCreatorID() *OrganizationUpsertOne {
return u.Update(func(s *OrganizationUpsert) {
s.UpdateCreatorID()
})
}
// Exec executes the query.
func (u *OrganizationUpsertOne) Exec(ctx context.Context) error {
if len(u.create.conflict) == 0 {
@@ -639,6 +763,20 @@ func (u *OrganizationUpsertBulk) UpdateDisplayName() *OrganizationUpsertBulk {
})
}
// SetCreatorID sets the "creator_id" field.
func (u *OrganizationUpsertBulk) SetCreatorID(v uuid.UUID) *OrganizationUpsertBulk {
return u.Update(func(s *OrganizationUpsert) {
s.SetCreatorID(v)
})
}
// UpdateCreatorID sets the "creator_id" field to the value that was provided on create.
func (u *OrganizationUpsertBulk) UpdateCreatorID() *OrganizationUpsertBulk {
return u.Update(func(s *OrganizationUpsert) {
s.UpdateCreatorID()
})
}
// Exec executes the query.
func (u *OrganizationUpsertBulk) Exec(ctx context.Context) error {
if u.create.err != nil {

View File

@@ -4,6 +4,7 @@ package ent
import (
"context"
"database/sql/driver"
"fmt"
"math"
@@ -12,16 +13,21 @@ import (
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/predicate"
"github.com/holos-run/holos/internal/ent/user"
)
// OrganizationQuery is the builder for querying Organization entities.
type OrganizationQuery struct {
config
ctx *QueryContext
order []organization.OrderOption
inters []Interceptor
predicates []predicate.Organization
ctx *QueryContext
order []organization.OrderOption
inters []Interceptor
predicates []predicate.Organization
withCreator *UserQuery
withUsers *UserQuery
withPlatforms *PlatformQuery
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
@@ -58,6 +64,72 @@ func (oq *OrganizationQuery) Order(o ...organization.OrderOption) *OrganizationQ
return oq
}
// QueryCreator chains the current query on the "creator" edge.
func (oq *OrganizationQuery) QueryCreator() *UserQuery {
query := (&UserClient{config: oq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := oq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := oq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(organization.Table, organization.FieldID, selector),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, organization.CreatorTable, organization.CreatorColumn),
)
fromU = sqlgraph.SetNeighbors(oq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryUsers chains the current query on the "users" edge.
func (oq *OrganizationQuery) QueryUsers() *UserQuery {
query := (&UserClient{config: oq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := oq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := oq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(organization.Table, organization.FieldID, selector),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2M, false, organization.UsersTable, organization.UsersPrimaryKey...),
)
fromU = sqlgraph.SetNeighbors(oq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryPlatforms chains the current query on the "platforms" edge.
func (oq *OrganizationQuery) QueryPlatforms() *PlatformQuery {
query := (&PlatformClient{config: oq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := oq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := oq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(organization.Table, organization.FieldID, selector),
sqlgraph.To(platform.Table, platform.FieldID),
sqlgraph.Edge(sqlgraph.O2M, true, organization.PlatformsTable, organization.PlatformsColumn),
)
fromU = sqlgraph.SetNeighbors(oq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// First returns the first Organization entity from the query.
// Returns a *NotFoundError when no Organization was found.
func (oq *OrganizationQuery) First(ctx context.Context) (*Organization, error) {
@@ -245,17 +317,53 @@ func (oq *OrganizationQuery) Clone() *OrganizationQuery {
return nil
}
return &OrganizationQuery{
config: oq.config,
ctx: oq.ctx.Clone(),
order: append([]organization.OrderOption{}, oq.order...),
inters: append([]Interceptor{}, oq.inters...),
predicates: append([]predicate.Organization{}, oq.predicates...),
config: oq.config,
ctx: oq.ctx.Clone(),
order: append([]organization.OrderOption{}, oq.order...),
inters: append([]Interceptor{}, oq.inters...),
predicates: append([]predicate.Organization{}, oq.predicates...),
withCreator: oq.withCreator.Clone(),
withUsers: oq.withUsers.Clone(),
withPlatforms: oq.withPlatforms.Clone(),
// clone intermediate query.
sql: oq.sql.Clone(),
path: oq.path,
}
}
// WithCreator tells the query-builder to eager-load the nodes that are connected to
// the "creator" edge. The optional arguments are used to configure the query builder of the edge.
func (oq *OrganizationQuery) WithCreator(opts ...func(*UserQuery)) *OrganizationQuery {
query := (&UserClient{config: oq.config}).Query()
for _, opt := range opts {
opt(query)
}
oq.withCreator = query
return oq
}
// WithUsers tells the query-builder to eager-load the nodes that are connected to
// the "users" edge. The optional arguments are used to configure the query builder of the edge.
func (oq *OrganizationQuery) WithUsers(opts ...func(*UserQuery)) *OrganizationQuery {
query := (&UserClient{config: oq.config}).Query()
for _, opt := range opts {
opt(query)
}
oq.withUsers = query
return oq
}
// WithPlatforms tells the query-builder to eager-load the nodes that are connected to
// the "platforms" edge. The optional arguments are used to configure the query builder of the edge.
func (oq *OrganizationQuery) WithPlatforms(opts ...func(*PlatformQuery)) *OrganizationQuery {
query := (&PlatformClient{config: oq.config}).Query()
for _, opt := range opts {
opt(query)
}
oq.withPlatforms = query
return oq
}
// GroupBy is used to group vertices by one or more fields/columns.
// It is often used with aggregate functions, like: count, max, mean, min, sum.
//
@@ -332,8 +440,13 @@ func (oq *OrganizationQuery) prepareQuery(ctx context.Context) error {
func (oq *OrganizationQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Organization, error) {
var (
nodes = []*Organization{}
_spec = oq.querySpec()
nodes = []*Organization{}
_spec = oq.querySpec()
loadedTypes = [3]bool{
oq.withCreator != nil,
oq.withUsers != nil,
oq.withPlatforms != nil,
}
)
_spec.ScanValues = func(columns []string) ([]any, error) {
return (*Organization).scanValues(nil, columns)
@@ -341,6 +454,7 @@ func (oq *OrganizationQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]
_spec.Assign = func(columns []string, values []any) error {
node := &Organization{config: oq.config}
nodes = append(nodes, node)
node.Edges.loadedTypes = loadedTypes
return node.assignValues(columns, values)
}
for i := range hooks {
@@ -352,9 +466,150 @@ func (oq *OrganizationQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]
if len(nodes) == 0 {
return nodes, nil
}
if query := oq.withCreator; query != nil {
if err := oq.loadCreator(ctx, query, nodes, nil,
func(n *Organization, e *User) { n.Edges.Creator = e }); err != nil {
return nil, err
}
}
if query := oq.withUsers; query != nil {
if err := oq.loadUsers(ctx, query, nodes,
func(n *Organization) { n.Edges.Users = []*User{} },
func(n *Organization, e *User) { n.Edges.Users = append(n.Edges.Users, e) }); err != nil {
return nil, err
}
}
if query := oq.withPlatforms; query != nil {
if err := oq.loadPlatforms(ctx, query, nodes,
func(n *Organization) { n.Edges.Platforms = []*Platform{} },
func(n *Organization, e *Platform) { n.Edges.Platforms = append(n.Edges.Platforms, e) }); err != nil {
return nil, err
}
}
return nodes, nil
}
func (oq *OrganizationQuery) loadCreator(ctx context.Context, query *UserQuery, nodes []*Organization, init func(*Organization), assign func(*Organization, *User)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Organization)
for i := range nodes {
fk := nodes[i].CreatorID
if _, ok := nodeids[fk]; !ok {
ids = append(ids, fk)
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(user.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
nodes, ok := nodeids[n.ID]
if !ok {
return fmt.Errorf(`unexpected foreign-key "creator_id" returned %v`, n.ID)
}
for i := range nodes {
assign(nodes[i], n)
}
}
return nil
}
func (oq *OrganizationQuery) loadUsers(ctx context.Context, query *UserQuery, nodes []*Organization, init func(*Organization), assign func(*Organization, *User)) error {
edgeIDs := make([]driver.Value, len(nodes))
byID := make(map[uuid.UUID]*Organization)
nids := make(map[uuid.UUID]map[*Organization]struct{})
for i, node := range nodes {
edgeIDs[i] = node.ID
byID[node.ID] = node
if init != nil {
init(node)
}
}
query.Where(func(s *sql.Selector) {
joinT := sql.Table(organization.UsersTable)
s.Join(joinT).On(s.C(user.FieldID), joinT.C(organization.UsersPrimaryKey[1]))
s.Where(sql.InValues(joinT.C(organization.UsersPrimaryKey[0]), edgeIDs...))
columns := s.SelectedColumns()
s.Select(joinT.C(organization.UsersPrimaryKey[0]))
s.AppendSelect(columns...)
s.SetDistinct(false)
})
if err := query.prepareQuery(ctx); err != nil {
return err
}
qr := QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
return query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) {
assign := spec.Assign
values := spec.ScanValues
spec.ScanValues = func(columns []string) ([]any, error) {
values, err := values(columns[1:])
if err != nil {
return nil, err
}
return append([]any{new(uuid.UUID)}, values...), nil
}
spec.Assign = func(columns []string, values []any) error {
outValue := *values[0].(*uuid.UUID)
inValue := *values[1].(*uuid.UUID)
if nids[inValue] == nil {
nids[inValue] = map[*Organization]struct{}{byID[outValue]: {}}
return assign(columns[1:], values[1:])
}
nids[inValue][byID[outValue]] = struct{}{}
return nil
}
})
})
neighbors, err := withInterceptors[[]*User](ctx, query, qr, query.inters)
if err != nil {
return err
}
for _, n := range neighbors {
nodes, ok := nids[n.ID]
if !ok {
return fmt.Errorf(`unexpected "users" node returned %v`, n.ID)
}
for kn := range nodes {
assign(kn, n)
}
}
return nil
}
func (oq *OrganizationQuery) loadPlatforms(ctx context.Context, query *PlatformQuery, nodes []*Organization, init func(*Organization), assign func(*Organization, *Platform)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Organization)
for i := range nodes {
fks = append(fks, nodes[i].ID)
nodeids[nodes[i].ID] = nodes[i]
if init != nil {
init(nodes[i])
}
}
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(platform.FieldOrgID)
}
query.Where(predicate.Platform(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(organization.PlatformsColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.OrgID
node, ok := nodeids[fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "org_id" returned %v for node %v`, fk, n.ID)
}
assign(node, n)
}
return nil
}
func (oq *OrganizationQuery) sqlCount(ctx context.Context) (int, error) {
_spec := oq.querySpec()
_spec.Node.Columns = oq.ctx.Fields
@@ -380,6 +635,9 @@ func (oq *OrganizationQuery) querySpec() *sqlgraph.QuerySpec {
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
}
}
if oq.withCreator != nil {
_spec.Node.AddColumnOnce(organization.FieldCreatorID)
}
}
if ps := oq.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {

View File

@@ -11,8 +11,11 @@ import (
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/predicate"
"github.com/holos-run/holos/internal/ent/user"
)
// OrganizationUpdate is the builder for updating Organization entities.
@@ -62,11 +65,108 @@ func (ou *OrganizationUpdate) SetNillableDisplayName(s *string) *OrganizationUpd
return ou
}
// SetCreatorID sets the "creator_id" field.
func (ou *OrganizationUpdate) SetCreatorID(u uuid.UUID) *OrganizationUpdate {
ou.mutation.SetCreatorID(u)
return ou
}
// SetNillableCreatorID sets the "creator_id" field if the given value is not nil.
func (ou *OrganizationUpdate) SetNillableCreatorID(u *uuid.UUID) *OrganizationUpdate {
if u != nil {
ou.SetCreatorID(*u)
}
return ou
}
// SetCreator sets the "creator" edge to the User entity.
func (ou *OrganizationUpdate) SetCreator(u *User) *OrganizationUpdate {
return ou.SetCreatorID(u.ID)
}
// AddUserIDs adds the "users" edge to the User entity by IDs.
func (ou *OrganizationUpdate) AddUserIDs(ids ...uuid.UUID) *OrganizationUpdate {
ou.mutation.AddUserIDs(ids...)
return ou
}
// AddUsers adds the "users" edges to the User entity.
func (ou *OrganizationUpdate) AddUsers(u ...*User) *OrganizationUpdate {
ids := make([]uuid.UUID, len(u))
for i := range u {
ids[i] = u[i].ID
}
return ou.AddUserIDs(ids...)
}
// AddPlatformIDs adds the "platforms" edge to the Platform entity by IDs.
func (ou *OrganizationUpdate) AddPlatformIDs(ids ...uuid.UUID) *OrganizationUpdate {
ou.mutation.AddPlatformIDs(ids...)
return ou
}
// AddPlatforms adds the "platforms" edges to the Platform entity.
func (ou *OrganizationUpdate) AddPlatforms(p ...*Platform) *OrganizationUpdate {
ids := make([]uuid.UUID, len(p))
for i := range p {
ids[i] = p[i].ID
}
return ou.AddPlatformIDs(ids...)
}
// Mutation returns the OrganizationMutation object of the builder.
func (ou *OrganizationUpdate) Mutation() *OrganizationMutation {
return ou.mutation
}
// ClearCreator clears the "creator" edge to the User entity.
func (ou *OrganizationUpdate) ClearCreator() *OrganizationUpdate {
ou.mutation.ClearCreator()
return ou
}
// ClearUsers clears all "users" edges to the User entity.
func (ou *OrganizationUpdate) ClearUsers() *OrganizationUpdate {
ou.mutation.ClearUsers()
return ou
}
// RemoveUserIDs removes the "users" edge to User entities by IDs.
func (ou *OrganizationUpdate) RemoveUserIDs(ids ...uuid.UUID) *OrganizationUpdate {
ou.mutation.RemoveUserIDs(ids...)
return ou
}
// RemoveUsers removes "users" edges to User entities.
func (ou *OrganizationUpdate) RemoveUsers(u ...*User) *OrganizationUpdate {
ids := make([]uuid.UUID, len(u))
for i := range u {
ids[i] = u[i].ID
}
return ou.RemoveUserIDs(ids...)
}
// ClearPlatforms clears all "platforms" edges to the Platform entity.
func (ou *OrganizationUpdate) ClearPlatforms() *OrganizationUpdate {
ou.mutation.ClearPlatforms()
return ou
}
// RemovePlatformIDs removes the "platforms" edge to Platform entities by IDs.
func (ou *OrganizationUpdate) RemovePlatformIDs(ids ...uuid.UUID) *OrganizationUpdate {
ou.mutation.RemovePlatformIDs(ids...)
return ou
}
// RemovePlatforms removes "platforms" edges to Platform entities.
func (ou *OrganizationUpdate) RemovePlatforms(p ...*Platform) *OrganizationUpdate {
ids := make([]uuid.UUID, len(p))
for i := range p {
ids[i] = p[i].ID
}
return ou.RemovePlatformIDs(ids...)
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (ou *OrganizationUpdate) Save(ctx context.Context) (int, error) {
ou.defaults()
@@ -110,6 +210,9 @@ func (ou *OrganizationUpdate) check() error {
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Organization.name": %w`, err)}
}
}
if _, ok := ou.mutation.CreatorID(); ou.mutation.CreatorCleared() && !ok {
return errors.New(`ent: clearing a required unique edge "Organization.creator"`)
}
return nil
}
@@ -134,6 +237,125 @@ func (ou *OrganizationUpdate) sqlSave(ctx context.Context) (n int, err error) {
if value, ok := ou.mutation.DisplayName(); ok {
_spec.SetField(organization.FieldDisplayName, field.TypeString, value)
}
if ou.mutation.CreatorCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: organization.CreatorTable,
Columns: []string{organization.CreatorColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ou.mutation.CreatorIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: organization.CreatorTable,
Columns: []string{organization.CreatorColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if ou.mutation.UsersCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: false,
Table: organization.UsersTable,
Columns: organization.UsersPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ou.mutation.RemovedUsersIDs(); len(nodes) > 0 && !ou.mutation.UsersCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: false,
Table: organization.UsersTable,
Columns: organization.UsersPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ou.mutation.UsersIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: false,
Table: organization.UsersTable,
Columns: organization.UsersPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if ou.mutation.PlatformsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: true,
Table: organization.PlatformsTable,
Columns: []string{organization.PlatformsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ou.mutation.RemovedPlatformsIDs(); len(nodes) > 0 && !ou.mutation.PlatformsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: true,
Table: organization.PlatformsTable,
Columns: []string{organization.PlatformsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ou.mutation.PlatformsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: true,
Table: organization.PlatformsTable,
Columns: []string{organization.PlatformsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if n, err = sqlgraph.UpdateNodes(ctx, ou.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{organization.Label}
@@ -188,11 +410,108 @@ func (ouo *OrganizationUpdateOne) SetNillableDisplayName(s *string) *Organizatio
return ouo
}
// SetCreatorID sets the "creator_id" field.
func (ouo *OrganizationUpdateOne) SetCreatorID(u uuid.UUID) *OrganizationUpdateOne {
ouo.mutation.SetCreatorID(u)
return ouo
}
// SetNillableCreatorID sets the "creator_id" field if the given value is not nil.
func (ouo *OrganizationUpdateOne) SetNillableCreatorID(u *uuid.UUID) *OrganizationUpdateOne {
if u != nil {
ouo.SetCreatorID(*u)
}
return ouo
}
// SetCreator sets the "creator" edge to the User entity.
func (ouo *OrganizationUpdateOne) SetCreator(u *User) *OrganizationUpdateOne {
return ouo.SetCreatorID(u.ID)
}
// AddUserIDs adds the "users" edge to the User entity by IDs.
func (ouo *OrganizationUpdateOne) AddUserIDs(ids ...uuid.UUID) *OrganizationUpdateOne {
ouo.mutation.AddUserIDs(ids...)
return ouo
}
// AddUsers adds the "users" edges to the User entity.
func (ouo *OrganizationUpdateOne) AddUsers(u ...*User) *OrganizationUpdateOne {
ids := make([]uuid.UUID, len(u))
for i := range u {
ids[i] = u[i].ID
}
return ouo.AddUserIDs(ids...)
}
// AddPlatformIDs adds the "platforms" edge to the Platform entity by IDs.
func (ouo *OrganizationUpdateOne) AddPlatformIDs(ids ...uuid.UUID) *OrganizationUpdateOne {
ouo.mutation.AddPlatformIDs(ids...)
return ouo
}
// AddPlatforms adds the "platforms" edges to the Platform entity.
func (ouo *OrganizationUpdateOne) AddPlatforms(p ...*Platform) *OrganizationUpdateOne {
ids := make([]uuid.UUID, len(p))
for i := range p {
ids[i] = p[i].ID
}
return ouo.AddPlatformIDs(ids...)
}
// Mutation returns the OrganizationMutation object of the builder.
func (ouo *OrganizationUpdateOne) Mutation() *OrganizationMutation {
return ouo.mutation
}
// ClearCreator clears the "creator" edge to the User entity.
func (ouo *OrganizationUpdateOne) ClearCreator() *OrganizationUpdateOne {
ouo.mutation.ClearCreator()
return ouo
}
// ClearUsers clears all "users" edges to the User entity.
func (ouo *OrganizationUpdateOne) ClearUsers() *OrganizationUpdateOne {
ouo.mutation.ClearUsers()
return ouo
}
// RemoveUserIDs removes the "users" edge to User entities by IDs.
func (ouo *OrganizationUpdateOne) RemoveUserIDs(ids ...uuid.UUID) *OrganizationUpdateOne {
ouo.mutation.RemoveUserIDs(ids...)
return ouo
}
// RemoveUsers removes "users" edges to User entities.
func (ouo *OrganizationUpdateOne) RemoveUsers(u ...*User) *OrganizationUpdateOne {
ids := make([]uuid.UUID, len(u))
for i := range u {
ids[i] = u[i].ID
}
return ouo.RemoveUserIDs(ids...)
}
// ClearPlatforms clears all "platforms" edges to the Platform entity.
func (ouo *OrganizationUpdateOne) ClearPlatforms() *OrganizationUpdateOne {
ouo.mutation.ClearPlatforms()
return ouo
}
// RemovePlatformIDs removes the "platforms" edge to Platform entities by IDs.
func (ouo *OrganizationUpdateOne) RemovePlatformIDs(ids ...uuid.UUID) *OrganizationUpdateOne {
ouo.mutation.RemovePlatformIDs(ids...)
return ouo
}
// RemovePlatforms removes "platforms" edges to Platform entities.
func (ouo *OrganizationUpdateOne) RemovePlatforms(p ...*Platform) *OrganizationUpdateOne {
ids := make([]uuid.UUID, len(p))
for i := range p {
ids[i] = p[i].ID
}
return ouo.RemovePlatformIDs(ids...)
}
// Where appends a list predicates to the OrganizationUpdate builder.
func (ouo *OrganizationUpdateOne) Where(ps ...predicate.Organization) *OrganizationUpdateOne {
ouo.mutation.Where(ps...)
@@ -249,6 +568,9 @@ func (ouo *OrganizationUpdateOne) check() error {
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Organization.name": %w`, err)}
}
}
if _, ok := ouo.mutation.CreatorID(); ouo.mutation.CreatorCleared() && !ok {
return errors.New(`ent: clearing a required unique edge "Organization.creator"`)
}
return nil
}
@@ -290,6 +612,125 @@ func (ouo *OrganizationUpdateOne) sqlSave(ctx context.Context) (_node *Organizat
if value, ok := ouo.mutation.DisplayName(); ok {
_spec.SetField(organization.FieldDisplayName, field.TypeString, value)
}
if ouo.mutation.CreatorCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: organization.CreatorTable,
Columns: []string{organization.CreatorColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ouo.mutation.CreatorIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: organization.CreatorTable,
Columns: []string{organization.CreatorColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if ouo.mutation.UsersCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: false,
Table: organization.UsersTable,
Columns: organization.UsersPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ouo.mutation.RemovedUsersIDs(); len(nodes) > 0 && !ouo.mutation.UsersCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: false,
Table: organization.UsersTable,
Columns: organization.UsersPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ouo.mutation.UsersIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: false,
Table: organization.UsersTable,
Columns: organization.UsersPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if ouo.mutation.PlatformsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: true,
Table: organization.PlatformsTable,
Columns: []string{organization.PlatformsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ouo.mutation.RemovedPlatformsIDs(); len(nodes) > 0 && !ouo.mutation.PlatformsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: true,
Table: organization.PlatformsTable,
Columns: []string{organization.PlatformsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := ouo.mutation.PlatformsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: true,
Table: organization.PlatformsTable,
Columns: []string{organization.PlatformsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
_node = &Organization{config: ouo.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues

262
internal/ent/platform.go Normal file
View File

@@ -0,0 +1,262 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"encoding/json"
"fmt"
"strings"
"time"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/user"
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
)
// Platform is the model entity for the Platform schema.
type Platform struct {
config `json:"-"`
// ID of the ent.
ID uuid.UUID `json:"id,omitempty"`
// CreatedAt holds the value of the "created_at" field.
CreatedAt time.Time `json:"created_at,omitempty"`
// UpdatedAt holds the value of the "updated_at" field.
UpdatedAt time.Time `json:"updated_at,omitempty"`
// OrgID holds the value of the "org_id" field.
OrgID uuid.UUID `json:"org_id,omitempty"`
// Name holds the value of the "name" field.
Name string `json:"name,omitempty"`
// DisplayName holds the value of the "display_name" field.
DisplayName string `json:"display_name,omitempty"`
// CreatorID holds the value of the "creator_id" field.
CreatorID uuid.UUID `json:"creator_id,omitempty"`
// JSON representation of FormlyFormConfig[] refer to https://github.com/holos-run/holos/issues/161
Form *holos.Form `json:"form,omitempty"`
// JSON representation of the form model which holds user input values refer to https://github.com/holos-run/holos/issues/161
Model *holos.Model `json:"model,omitempty"`
// CUE definition to vet the model against e.g. #PlatformConfig
Cue []byte `json:"cue,omitempty"`
// The definition name to vet config_values against config_cue e.g. '#PlatformSpec'
CueDefinition string `json:"cue_definition,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the PlatformQuery when eager-loading is set.
Edges PlatformEdges `json:"edges"`
selectValues sql.SelectValues
}
// PlatformEdges holds the relations/edges for other nodes in the graph.
type PlatformEdges struct {
// Creator holds the value of the creator edge.
Creator *User `json:"creator,omitempty"`
// Organization holds the value of the organization edge.
Organization *Organization `json:"organization,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [2]bool
}
// CreatorOrErr returns the Creator value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e PlatformEdges) CreatorOrErr() (*User, error) {
if e.Creator != nil {
return e.Creator, nil
} else if e.loadedTypes[0] {
return nil, &NotFoundError{label: user.Label}
}
return nil, &NotLoadedError{edge: "creator"}
}
// OrganizationOrErr returns the Organization value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e PlatformEdges) OrganizationOrErr() (*Organization, error) {
if e.Organization != nil {
return e.Organization, nil
} else if e.loadedTypes[1] {
return nil, &NotFoundError{label: organization.Label}
}
return nil, &NotLoadedError{edge: "organization"}
}
// scanValues returns the types for scanning values from sql.Rows.
func (*Platform) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
case platform.FieldForm, platform.FieldModel, platform.FieldCue:
values[i] = new([]byte)
case platform.FieldName, platform.FieldDisplayName, platform.FieldCueDefinition:
values[i] = new(sql.NullString)
case platform.FieldCreatedAt, platform.FieldUpdatedAt:
values[i] = new(sql.NullTime)
case platform.FieldID, platform.FieldOrgID, platform.FieldCreatorID:
values[i] = new(uuid.UUID)
default:
values[i] = new(sql.UnknownType)
}
}
return values, nil
}
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the Platform fields.
func (pl *Platform) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
for i := range columns {
switch columns[i] {
case platform.FieldID:
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field id", values[i])
} else if value != nil {
pl.ID = *value
}
case platform.FieldCreatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field created_at", values[i])
} else if value.Valid {
pl.CreatedAt = value.Time
}
case platform.FieldUpdatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
} else if value.Valid {
pl.UpdatedAt = value.Time
}
case platform.FieldOrgID:
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field org_id", values[i])
} else if value != nil {
pl.OrgID = *value
}
case platform.FieldName:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field name", values[i])
} else if value.Valid {
pl.Name = value.String
}
case platform.FieldDisplayName:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field display_name", values[i])
} else if value.Valid {
pl.DisplayName = value.String
}
case platform.FieldCreatorID:
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field creator_id", values[i])
} else if value != nil {
pl.CreatorID = *value
}
case platform.FieldForm:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field form", values[i])
} else if value != nil && len(*value) > 0 {
if err := json.Unmarshal(*value, &pl.Form); err != nil {
return fmt.Errorf("unmarshal field form: %w", err)
}
}
case platform.FieldModel:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field model", values[i])
} else if value != nil && len(*value) > 0 {
if err := json.Unmarshal(*value, &pl.Model); err != nil {
return fmt.Errorf("unmarshal field model: %w", err)
}
}
case platform.FieldCue:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field cue", values[i])
} else if value != nil {
pl.Cue = *value
}
case platform.FieldCueDefinition:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field cue_definition", values[i])
} else if value.Valid {
pl.CueDefinition = value.String
}
default:
pl.selectValues.Set(columns[i], values[i])
}
}
return nil
}
// Value returns the ent.Value that was dynamically selected and assigned to the Platform.
// This includes values selected through modifiers, order, etc.
func (pl *Platform) Value(name string) (ent.Value, error) {
return pl.selectValues.Get(name)
}
// QueryCreator queries the "creator" edge of the Platform entity.
func (pl *Platform) QueryCreator() *UserQuery {
return NewPlatformClient(pl.config).QueryCreator(pl)
}
// QueryOrganization queries the "organization" edge of the Platform entity.
func (pl *Platform) QueryOrganization() *OrganizationQuery {
return NewPlatformClient(pl.config).QueryOrganization(pl)
}
// Update returns a builder for updating this Platform.
// Note that you need to call Platform.Unwrap() before calling this method if this Platform
// was returned from a transaction, and the transaction was committed or rolled back.
func (pl *Platform) Update() *PlatformUpdateOne {
return NewPlatformClient(pl.config).UpdateOne(pl)
}
// Unwrap unwraps the Platform entity that was returned from a transaction after it was closed,
// so that all future queries will be executed through the driver which created the transaction.
func (pl *Platform) Unwrap() *Platform {
_tx, ok := pl.config.driver.(*txDriver)
if !ok {
panic("ent: Platform is not a transactional entity")
}
pl.config.driver = _tx.drv
return pl
}
// String implements the fmt.Stringer.
func (pl *Platform) String() string {
var builder strings.Builder
builder.WriteString("Platform(")
builder.WriteString(fmt.Sprintf("id=%v, ", pl.ID))
builder.WriteString("created_at=")
builder.WriteString(pl.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("updated_at=")
builder.WriteString(pl.UpdatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("org_id=")
builder.WriteString(fmt.Sprintf("%v", pl.OrgID))
builder.WriteString(", ")
builder.WriteString("name=")
builder.WriteString(pl.Name)
builder.WriteString(", ")
builder.WriteString("display_name=")
builder.WriteString(pl.DisplayName)
builder.WriteString(", ")
builder.WriteString("creator_id=")
builder.WriteString(fmt.Sprintf("%v", pl.CreatorID))
builder.WriteString(", ")
builder.WriteString("form=")
builder.WriteString(fmt.Sprintf("%v", pl.Form))
builder.WriteString(", ")
builder.WriteString("model=")
builder.WriteString(fmt.Sprintf("%v", pl.Model))
builder.WriteString(", ")
builder.WriteString("cue=")
builder.WriteString(fmt.Sprintf("%v", pl.Cue))
builder.WriteString(", ")
builder.WriteString("cue_definition=")
builder.WriteString(pl.CueDefinition)
builder.WriteByte(')')
return builder.String()
}
// Platforms is a parsable slice of Platform.
type Platforms []*Platform

View File

@@ -0,0 +1,167 @@
// Code generated by ent, DO NOT EDIT.
package platform
import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/gofrs/uuid"
)
const (
// Label holds the string label denoting the platform type in the database.
Label = "platform"
// FieldID holds the string denoting the id field in the database.
FieldID = "id"
// FieldCreatedAt holds the string denoting the created_at field in the database.
FieldCreatedAt = "created_at"
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
FieldUpdatedAt = "updated_at"
// FieldOrgID holds the string denoting the org_id field in the database.
FieldOrgID = "org_id"
// FieldName holds the string denoting the name field in the database.
FieldName = "name"
// FieldDisplayName holds the string denoting the display_name field in the database.
FieldDisplayName = "display_name"
// FieldCreatorID holds the string denoting the creator_id field in the database.
FieldCreatorID = "creator_id"
// FieldForm holds the string denoting the form field in the database.
FieldForm = "form"
// FieldModel holds the string denoting the model field in the database.
FieldModel = "model"
// FieldCue holds the string denoting the cue field in the database.
FieldCue = "cue"
// FieldCueDefinition holds the string denoting the cue_definition field in the database.
FieldCueDefinition = "cue_definition"
// EdgeCreator holds the string denoting the creator edge name in mutations.
EdgeCreator = "creator"
// EdgeOrganization holds the string denoting the organization edge name in mutations.
EdgeOrganization = "organization"
// Table holds the table name of the platform in the database.
Table = "platforms"
// CreatorTable is the table that holds the creator relation/edge.
CreatorTable = "platforms"
// CreatorInverseTable is the table name for the User entity.
// It exists in this package in order to avoid circular dependency with the "user" package.
CreatorInverseTable = "users"
// CreatorColumn is the table column denoting the creator relation/edge.
CreatorColumn = "creator_id"
// OrganizationTable is the table that holds the organization relation/edge.
OrganizationTable = "platforms"
// OrganizationInverseTable is the table name for the Organization entity.
// It exists in this package in order to avoid circular dependency with the "organization" package.
OrganizationInverseTable = "organizations"
// OrganizationColumn is the table column denoting the organization relation/edge.
OrganizationColumn = "org_id"
)
// Columns holds all SQL columns for platform fields.
var Columns = []string{
FieldID,
FieldCreatedAt,
FieldUpdatedAt,
FieldOrgID,
FieldName,
FieldDisplayName,
FieldCreatorID,
FieldForm,
FieldModel,
FieldCue,
FieldCueDefinition,
}
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
if column == Columns[i] {
return true
}
}
return false
}
var (
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
DefaultUpdatedAt func() time.Time
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
UpdateDefaultUpdatedAt func() time.Time
// NameValidator is a validator for the "name" field. It is called by the builders before save.
NameValidator func(string) error
// DefaultID holds the default value on creation for the "id" field.
DefaultID func() uuid.UUID
)
// OrderOption defines the ordering options for the Platform queries.
type OrderOption func(*sql.Selector)
// ByID orders the results by the id field.
func ByID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldID, opts...).ToFunc()
}
// ByCreatedAt orders the results by the created_at field.
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
}
// ByUpdatedAt orders the results by the updated_at field.
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
}
// ByOrgID orders the results by the org_id field.
func ByOrgID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldOrgID, opts...).ToFunc()
}
// ByName orders the results by the name field.
func ByName(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldName, opts...).ToFunc()
}
// ByDisplayName orders the results by the display_name field.
func ByDisplayName(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDisplayName, opts...).ToFunc()
}
// ByCreatorID orders the results by the creator_id field.
func ByCreatorID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCreatorID, opts...).ToFunc()
}
// ByCueDefinition orders the results by the cue_definition field.
func ByCueDefinition(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCueDefinition, opts...).ToFunc()
}
// ByCreatorField orders the results by creator field.
func ByCreatorField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newCreatorStep(), sql.OrderByField(field, opts...))
}
}
// ByOrganizationField orders the results by organization field.
func ByOrganizationField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newOrganizationStep(), sql.OrderByField(field, opts...))
}
}
func newCreatorStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(CreatorInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, CreatorTable, CreatorColumn),
)
}
func newOrganizationStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(OrganizationInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, OrganizationTable, OrganizationColumn),
)
}

View File

@@ -0,0 +1,553 @@
// Code generated by ent, DO NOT EDIT.
package platform
import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/predicate"
)
// ID filters vertices based on their ID field.
func ID(id uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldID, id))
}
// IDEQ applies the EQ predicate on the ID field.
func IDEQ(id uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldID, id))
}
// IDNEQ applies the NEQ predicate on the ID field.
func IDNEQ(id uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldNEQ(FieldID, id))
}
// IDIn applies the In predicate on the ID field.
func IDIn(ids ...uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldIn(FieldID, ids...))
}
// IDNotIn applies the NotIn predicate on the ID field.
func IDNotIn(ids ...uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldNotIn(FieldID, ids...))
}
// IDGT applies the GT predicate on the ID field.
func IDGT(id uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldGT(FieldID, id))
}
// IDGTE applies the GTE predicate on the ID field.
func IDGTE(id uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldGTE(FieldID, id))
}
// IDLT applies the LT predicate on the ID field.
func IDLT(id uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldLT(FieldID, id))
}
// IDLTE applies the LTE predicate on the ID field.
func IDLTE(id uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldLTE(FieldID, id))
}
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
func CreatedAt(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldCreatedAt, v))
}
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
func UpdatedAt(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldUpdatedAt, v))
}
// OrgID applies equality check predicate on the "org_id" field. It's identical to OrgIDEQ.
func OrgID(v uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldOrgID, v))
}
// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
func Name(v string) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldName, v))
}
// DisplayName applies equality check predicate on the "display_name" field. It's identical to DisplayNameEQ.
func DisplayName(v string) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldDisplayName, v))
}
// CreatorID applies equality check predicate on the "creator_id" field. It's identical to CreatorIDEQ.
func CreatorID(v uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldCreatorID, v))
}
// Cue applies equality check predicate on the "cue" field. It's identical to CueEQ.
func Cue(v []byte) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldCue, v))
}
// CueDefinition applies equality check predicate on the "cue_definition" field. It's identical to CueDefinitionEQ.
func CueDefinition(v string) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldCueDefinition, v))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldCreatedAt, v))
}
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
func CreatedAtNEQ(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldNEQ(FieldCreatedAt, v))
}
// CreatedAtIn applies the In predicate on the "created_at" field.
func CreatedAtIn(vs ...time.Time) predicate.Platform {
return predicate.Platform(sql.FieldIn(FieldCreatedAt, vs...))
}
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
func CreatedAtNotIn(vs ...time.Time) predicate.Platform {
return predicate.Platform(sql.FieldNotIn(FieldCreatedAt, vs...))
}
// CreatedAtGT applies the GT predicate on the "created_at" field.
func CreatedAtGT(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldGT(FieldCreatedAt, v))
}
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
func CreatedAtGTE(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldGTE(FieldCreatedAt, v))
}
// CreatedAtLT applies the LT predicate on the "created_at" field.
func CreatedAtLT(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldLT(FieldCreatedAt, v))
}
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
func CreatedAtLTE(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldLTE(FieldCreatedAt, v))
}
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
func UpdatedAtEQ(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldUpdatedAt, v))
}
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
func UpdatedAtNEQ(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldNEQ(FieldUpdatedAt, v))
}
// UpdatedAtIn applies the In predicate on the "updated_at" field.
func UpdatedAtIn(vs ...time.Time) predicate.Platform {
return predicate.Platform(sql.FieldIn(FieldUpdatedAt, vs...))
}
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
func UpdatedAtNotIn(vs ...time.Time) predicate.Platform {
return predicate.Platform(sql.FieldNotIn(FieldUpdatedAt, vs...))
}
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
func UpdatedAtGT(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldGT(FieldUpdatedAt, v))
}
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
func UpdatedAtGTE(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldGTE(FieldUpdatedAt, v))
}
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
func UpdatedAtLT(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldLT(FieldUpdatedAt, v))
}
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
func UpdatedAtLTE(v time.Time) predicate.Platform {
return predicate.Platform(sql.FieldLTE(FieldUpdatedAt, v))
}
// OrgIDEQ applies the EQ predicate on the "org_id" field.
func OrgIDEQ(v uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldOrgID, v))
}
// OrgIDNEQ applies the NEQ predicate on the "org_id" field.
func OrgIDNEQ(v uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldNEQ(FieldOrgID, v))
}
// OrgIDIn applies the In predicate on the "org_id" field.
func OrgIDIn(vs ...uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldIn(FieldOrgID, vs...))
}
// OrgIDNotIn applies the NotIn predicate on the "org_id" field.
func OrgIDNotIn(vs ...uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldNotIn(FieldOrgID, vs...))
}
// NameEQ applies the EQ predicate on the "name" field.
func NameEQ(v string) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldName, v))
}
// NameNEQ applies the NEQ predicate on the "name" field.
func NameNEQ(v string) predicate.Platform {
return predicate.Platform(sql.FieldNEQ(FieldName, v))
}
// NameIn applies the In predicate on the "name" field.
func NameIn(vs ...string) predicate.Platform {
return predicate.Platform(sql.FieldIn(FieldName, vs...))
}
// NameNotIn applies the NotIn predicate on the "name" field.
func NameNotIn(vs ...string) predicate.Platform {
return predicate.Platform(sql.FieldNotIn(FieldName, vs...))
}
// NameGT applies the GT predicate on the "name" field.
func NameGT(v string) predicate.Platform {
return predicate.Platform(sql.FieldGT(FieldName, v))
}
// NameGTE applies the GTE predicate on the "name" field.
func NameGTE(v string) predicate.Platform {
return predicate.Platform(sql.FieldGTE(FieldName, v))
}
// NameLT applies the LT predicate on the "name" field.
func NameLT(v string) predicate.Platform {
return predicate.Platform(sql.FieldLT(FieldName, v))
}
// NameLTE applies the LTE predicate on the "name" field.
func NameLTE(v string) predicate.Platform {
return predicate.Platform(sql.FieldLTE(FieldName, v))
}
// NameContains applies the Contains predicate on the "name" field.
func NameContains(v string) predicate.Platform {
return predicate.Platform(sql.FieldContains(FieldName, v))
}
// NameHasPrefix applies the HasPrefix predicate on the "name" field.
func NameHasPrefix(v string) predicate.Platform {
return predicate.Platform(sql.FieldHasPrefix(FieldName, v))
}
// NameHasSuffix applies the HasSuffix predicate on the "name" field.
func NameHasSuffix(v string) predicate.Platform {
return predicate.Platform(sql.FieldHasSuffix(FieldName, v))
}
// NameEqualFold applies the EqualFold predicate on the "name" field.
func NameEqualFold(v string) predicate.Platform {
return predicate.Platform(sql.FieldEqualFold(FieldName, v))
}
// NameContainsFold applies the ContainsFold predicate on the "name" field.
func NameContainsFold(v string) predicate.Platform {
return predicate.Platform(sql.FieldContainsFold(FieldName, v))
}
// DisplayNameEQ applies the EQ predicate on the "display_name" field.
func DisplayNameEQ(v string) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldDisplayName, v))
}
// DisplayNameNEQ applies the NEQ predicate on the "display_name" field.
func DisplayNameNEQ(v string) predicate.Platform {
return predicate.Platform(sql.FieldNEQ(FieldDisplayName, v))
}
// DisplayNameIn applies the In predicate on the "display_name" field.
func DisplayNameIn(vs ...string) predicate.Platform {
return predicate.Platform(sql.FieldIn(FieldDisplayName, vs...))
}
// DisplayNameNotIn applies the NotIn predicate on the "display_name" field.
func DisplayNameNotIn(vs ...string) predicate.Platform {
return predicate.Platform(sql.FieldNotIn(FieldDisplayName, vs...))
}
// DisplayNameGT applies the GT predicate on the "display_name" field.
func DisplayNameGT(v string) predicate.Platform {
return predicate.Platform(sql.FieldGT(FieldDisplayName, v))
}
// DisplayNameGTE applies the GTE predicate on the "display_name" field.
func DisplayNameGTE(v string) predicate.Platform {
return predicate.Platform(sql.FieldGTE(FieldDisplayName, v))
}
// DisplayNameLT applies the LT predicate on the "display_name" field.
func DisplayNameLT(v string) predicate.Platform {
return predicate.Platform(sql.FieldLT(FieldDisplayName, v))
}
// DisplayNameLTE applies the LTE predicate on the "display_name" field.
func DisplayNameLTE(v string) predicate.Platform {
return predicate.Platform(sql.FieldLTE(FieldDisplayName, v))
}
// DisplayNameContains applies the Contains predicate on the "display_name" field.
func DisplayNameContains(v string) predicate.Platform {
return predicate.Platform(sql.FieldContains(FieldDisplayName, v))
}
// DisplayNameHasPrefix applies the HasPrefix predicate on the "display_name" field.
func DisplayNameHasPrefix(v string) predicate.Platform {
return predicate.Platform(sql.FieldHasPrefix(FieldDisplayName, v))
}
// DisplayNameHasSuffix applies the HasSuffix predicate on the "display_name" field.
func DisplayNameHasSuffix(v string) predicate.Platform {
return predicate.Platform(sql.FieldHasSuffix(FieldDisplayName, v))
}
// DisplayNameEqualFold applies the EqualFold predicate on the "display_name" field.
func DisplayNameEqualFold(v string) predicate.Platform {
return predicate.Platform(sql.FieldEqualFold(FieldDisplayName, v))
}
// DisplayNameContainsFold applies the ContainsFold predicate on the "display_name" field.
func DisplayNameContainsFold(v string) predicate.Platform {
return predicate.Platform(sql.FieldContainsFold(FieldDisplayName, v))
}
// CreatorIDEQ applies the EQ predicate on the "creator_id" field.
func CreatorIDEQ(v uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldCreatorID, v))
}
// CreatorIDNEQ applies the NEQ predicate on the "creator_id" field.
func CreatorIDNEQ(v uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldNEQ(FieldCreatorID, v))
}
// CreatorIDIn applies the In predicate on the "creator_id" field.
func CreatorIDIn(vs ...uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldIn(FieldCreatorID, vs...))
}
// CreatorIDNotIn applies the NotIn predicate on the "creator_id" field.
func CreatorIDNotIn(vs ...uuid.UUID) predicate.Platform {
return predicate.Platform(sql.FieldNotIn(FieldCreatorID, vs...))
}
// FormIsNil applies the IsNil predicate on the "form" field.
func FormIsNil() predicate.Platform {
return predicate.Platform(sql.FieldIsNull(FieldForm))
}
// FormNotNil applies the NotNil predicate on the "form" field.
func FormNotNil() predicate.Platform {
return predicate.Platform(sql.FieldNotNull(FieldForm))
}
// ModelIsNil applies the IsNil predicate on the "model" field.
func ModelIsNil() predicate.Platform {
return predicate.Platform(sql.FieldIsNull(FieldModel))
}
// ModelNotNil applies the NotNil predicate on the "model" field.
func ModelNotNil() predicate.Platform {
return predicate.Platform(sql.FieldNotNull(FieldModel))
}
// CueEQ applies the EQ predicate on the "cue" field.
func CueEQ(v []byte) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldCue, v))
}
// CueNEQ applies the NEQ predicate on the "cue" field.
func CueNEQ(v []byte) predicate.Platform {
return predicate.Platform(sql.FieldNEQ(FieldCue, v))
}
// CueIn applies the In predicate on the "cue" field.
func CueIn(vs ...[]byte) predicate.Platform {
return predicate.Platform(sql.FieldIn(FieldCue, vs...))
}
// CueNotIn applies the NotIn predicate on the "cue" field.
func CueNotIn(vs ...[]byte) predicate.Platform {
return predicate.Platform(sql.FieldNotIn(FieldCue, vs...))
}
// CueGT applies the GT predicate on the "cue" field.
func CueGT(v []byte) predicate.Platform {
return predicate.Platform(sql.FieldGT(FieldCue, v))
}
// CueGTE applies the GTE predicate on the "cue" field.
func CueGTE(v []byte) predicate.Platform {
return predicate.Platform(sql.FieldGTE(FieldCue, v))
}
// CueLT applies the LT predicate on the "cue" field.
func CueLT(v []byte) predicate.Platform {
return predicate.Platform(sql.FieldLT(FieldCue, v))
}
// CueLTE applies the LTE predicate on the "cue" field.
func CueLTE(v []byte) predicate.Platform {
return predicate.Platform(sql.FieldLTE(FieldCue, v))
}
// CueIsNil applies the IsNil predicate on the "cue" field.
func CueIsNil() predicate.Platform {
return predicate.Platform(sql.FieldIsNull(FieldCue))
}
// CueNotNil applies the NotNil predicate on the "cue" field.
func CueNotNil() predicate.Platform {
return predicate.Platform(sql.FieldNotNull(FieldCue))
}
// CueDefinitionEQ applies the EQ predicate on the "cue_definition" field.
func CueDefinitionEQ(v string) predicate.Platform {
return predicate.Platform(sql.FieldEQ(FieldCueDefinition, v))
}
// CueDefinitionNEQ applies the NEQ predicate on the "cue_definition" field.
func CueDefinitionNEQ(v string) predicate.Platform {
return predicate.Platform(sql.FieldNEQ(FieldCueDefinition, v))
}
// CueDefinitionIn applies the In predicate on the "cue_definition" field.
func CueDefinitionIn(vs ...string) predicate.Platform {
return predicate.Platform(sql.FieldIn(FieldCueDefinition, vs...))
}
// CueDefinitionNotIn applies the NotIn predicate on the "cue_definition" field.
func CueDefinitionNotIn(vs ...string) predicate.Platform {
return predicate.Platform(sql.FieldNotIn(FieldCueDefinition, vs...))
}
// CueDefinitionGT applies the GT predicate on the "cue_definition" field.
func CueDefinitionGT(v string) predicate.Platform {
return predicate.Platform(sql.FieldGT(FieldCueDefinition, v))
}
// CueDefinitionGTE applies the GTE predicate on the "cue_definition" field.
func CueDefinitionGTE(v string) predicate.Platform {
return predicate.Platform(sql.FieldGTE(FieldCueDefinition, v))
}
// CueDefinitionLT applies the LT predicate on the "cue_definition" field.
func CueDefinitionLT(v string) predicate.Platform {
return predicate.Platform(sql.FieldLT(FieldCueDefinition, v))
}
// CueDefinitionLTE applies the LTE predicate on the "cue_definition" field.
func CueDefinitionLTE(v string) predicate.Platform {
return predicate.Platform(sql.FieldLTE(FieldCueDefinition, v))
}
// CueDefinitionContains applies the Contains predicate on the "cue_definition" field.
func CueDefinitionContains(v string) predicate.Platform {
return predicate.Platform(sql.FieldContains(FieldCueDefinition, v))
}
// CueDefinitionHasPrefix applies the HasPrefix predicate on the "cue_definition" field.
func CueDefinitionHasPrefix(v string) predicate.Platform {
return predicate.Platform(sql.FieldHasPrefix(FieldCueDefinition, v))
}
// CueDefinitionHasSuffix applies the HasSuffix predicate on the "cue_definition" field.
func CueDefinitionHasSuffix(v string) predicate.Platform {
return predicate.Platform(sql.FieldHasSuffix(FieldCueDefinition, v))
}
// CueDefinitionIsNil applies the IsNil predicate on the "cue_definition" field.
func CueDefinitionIsNil() predicate.Platform {
return predicate.Platform(sql.FieldIsNull(FieldCueDefinition))
}
// CueDefinitionNotNil applies the NotNil predicate on the "cue_definition" field.
func CueDefinitionNotNil() predicate.Platform {
return predicate.Platform(sql.FieldNotNull(FieldCueDefinition))
}
// CueDefinitionEqualFold applies the EqualFold predicate on the "cue_definition" field.
func CueDefinitionEqualFold(v string) predicate.Platform {
return predicate.Platform(sql.FieldEqualFold(FieldCueDefinition, v))
}
// CueDefinitionContainsFold applies the ContainsFold predicate on the "cue_definition" field.
func CueDefinitionContainsFold(v string) predicate.Platform {
return predicate.Platform(sql.FieldContainsFold(FieldCueDefinition, v))
}
// HasCreator applies the HasEdge predicate on the "creator" edge.
func HasCreator() predicate.Platform {
return predicate.Platform(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, CreatorTable, CreatorColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasCreatorWith applies the HasEdge predicate on the "creator" edge with a given conditions (other predicates).
func HasCreatorWith(preds ...predicate.User) predicate.Platform {
return predicate.Platform(func(s *sql.Selector) {
step := newCreatorStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// HasOrganization applies the HasEdge predicate on the "organization" edge.
func HasOrganization() predicate.Platform {
return predicate.Platform(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, OrganizationTable, OrganizationColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasOrganizationWith applies the HasEdge predicate on the "organization" edge with a given conditions (other predicates).
func HasOrganizationWith(preds ...predicate.Organization) predicate.Platform {
return predicate.Platform(func(s *sql.Selector) {
step := newOrganizationStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// And groups predicates with the AND operator between them.
func And(predicates ...predicate.Platform) predicate.Platform {
return predicate.Platform(sql.AndPredicates(predicates...))
}
// Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Platform) predicate.Platform {
return predicate.Platform(sql.OrPredicates(predicates...))
}
// Not applies the not operator on the given predicate.
func Not(p predicate.Platform) predicate.Platform {
return predicate.Platform(sql.NotPredicates(p))
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/predicate"
)
// PlatformDelete is the builder for deleting a Platform entity.
type PlatformDelete struct {
config
hooks []Hook
mutation *PlatformMutation
}
// Where appends a list predicates to the PlatformDelete builder.
func (pd *PlatformDelete) Where(ps ...predicate.Platform) *PlatformDelete {
pd.mutation.Where(ps...)
return pd
}
// Exec executes the deletion query and returns how many vertices were deleted.
func (pd *PlatformDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, pd.sqlExec, pd.mutation, pd.hooks)
}
// ExecX is like Exec, but panics if an error occurs.
func (pd *PlatformDelete) ExecX(ctx context.Context) int {
n, err := pd.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
func (pd *PlatformDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(platform.Table, sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID))
if ps := pd.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
affected, err := sqlgraph.DeleteNodes(ctx, pd.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
pd.mutation.done = true
return affected, err
}
// PlatformDeleteOne is the builder for deleting a single Platform entity.
type PlatformDeleteOne struct {
pd *PlatformDelete
}
// Where appends a list predicates to the PlatformDelete builder.
func (pdo *PlatformDeleteOne) Where(ps ...predicate.Platform) *PlatformDeleteOne {
pdo.pd.mutation.Where(ps...)
return pdo
}
// Exec executes the deletion query.
func (pdo *PlatformDeleteOne) Exec(ctx context.Context) error {
n, err := pdo.pd.Exec(ctx)
switch {
case err != nil:
return err
case n == 0:
return &NotFoundError{platform.Label}
default:
return nil
}
}
// ExecX is like Exec, but panics if an error occurs.
func (pdo *PlatformDeleteOne) ExecX(ctx context.Context) {
if err := pdo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -0,0 +1,681 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"fmt"
"math"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/predicate"
"github.com/holos-run/holos/internal/ent/user"
)
// PlatformQuery is the builder for querying Platform entities.
type PlatformQuery struct {
config
ctx *QueryContext
order []platform.OrderOption
inters []Interceptor
predicates []predicate.Platform
withCreator *UserQuery
withOrganization *OrganizationQuery
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
}
// Where adds a new predicate for the PlatformQuery builder.
func (pq *PlatformQuery) Where(ps ...predicate.Platform) *PlatformQuery {
pq.predicates = append(pq.predicates, ps...)
return pq
}
// Limit the number of records to be returned by this query.
func (pq *PlatformQuery) Limit(limit int) *PlatformQuery {
pq.ctx.Limit = &limit
return pq
}
// Offset to start from.
func (pq *PlatformQuery) Offset(offset int) *PlatformQuery {
pq.ctx.Offset = &offset
return pq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (pq *PlatformQuery) Unique(unique bool) *PlatformQuery {
pq.ctx.Unique = &unique
return pq
}
// Order specifies how the records should be ordered.
func (pq *PlatformQuery) Order(o ...platform.OrderOption) *PlatformQuery {
pq.order = append(pq.order, o...)
return pq
}
// QueryCreator chains the current query on the "creator" edge.
func (pq *PlatformQuery) QueryCreator() *UserQuery {
query := (&UserClient{config: pq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := pq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := pq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(platform.Table, platform.FieldID, selector),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, platform.CreatorTable, platform.CreatorColumn),
)
fromU = sqlgraph.SetNeighbors(pq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryOrganization chains the current query on the "organization" edge.
func (pq *PlatformQuery) QueryOrganization() *OrganizationQuery {
query := (&OrganizationClient{config: pq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := pq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := pq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(platform.Table, platform.FieldID, selector),
sqlgraph.To(organization.Table, organization.FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, platform.OrganizationTable, platform.OrganizationColumn),
)
fromU = sqlgraph.SetNeighbors(pq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// First returns the first Platform entity from the query.
// Returns a *NotFoundError when no Platform was found.
func (pq *PlatformQuery) First(ctx context.Context) (*Platform, error) {
nodes, err := pq.Limit(1).All(setContextOp(ctx, pq.ctx, "First"))
if err != nil {
return nil, err
}
if len(nodes) == 0 {
return nil, &NotFoundError{platform.Label}
}
return nodes[0], nil
}
// FirstX is like First, but panics if an error occurs.
func (pq *PlatformQuery) FirstX(ctx context.Context) *Platform {
node, err := pq.First(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return node
}
// FirstID returns the first Platform ID from the query.
// Returns a *NotFoundError when no Platform ID was found.
func (pq *PlatformQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = pq.Limit(1).IDs(setContextOp(ctx, pq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
err = &NotFoundError{platform.Label}
return
}
return ids[0], nil
}
// FirstIDX is like FirstID, but panics if an error occurs.
func (pq *PlatformQuery) FirstIDX(ctx context.Context) uuid.UUID {
id, err := pq.FirstID(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return id
}
// Only returns a single Platform entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one Platform entity is found.
// Returns a *NotFoundError when no Platform entities are found.
func (pq *PlatformQuery) Only(ctx context.Context) (*Platform, error) {
nodes, err := pq.Limit(2).All(setContextOp(ctx, pq.ctx, "Only"))
if err != nil {
return nil, err
}
switch len(nodes) {
case 1:
return nodes[0], nil
case 0:
return nil, &NotFoundError{platform.Label}
default:
return nil, &NotSingularError{platform.Label}
}
}
// OnlyX is like Only, but panics if an error occurs.
func (pq *PlatformQuery) OnlyX(ctx context.Context) *Platform {
node, err := pq.Only(ctx)
if err != nil {
panic(err)
}
return node
}
// OnlyID is like Only, but returns the only Platform ID in the query.
// Returns a *NotSingularError when more than one Platform ID is found.
// Returns a *NotFoundError when no entities are found.
func (pq *PlatformQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = pq.Limit(2).IDs(setContextOp(ctx, pq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
case 1:
id = ids[0]
case 0:
err = &NotFoundError{platform.Label}
default:
err = &NotSingularError{platform.Label}
}
return
}
// OnlyIDX is like OnlyID, but panics if an error occurs.
func (pq *PlatformQuery) OnlyIDX(ctx context.Context) uuid.UUID {
id, err := pq.OnlyID(ctx)
if err != nil {
panic(err)
}
return id
}
// All executes the query and returns a list of Platforms.
func (pq *PlatformQuery) All(ctx context.Context) ([]*Platform, error) {
ctx = setContextOp(ctx, pq.ctx, "All")
if err := pq.prepareQuery(ctx); err != nil {
return nil, err
}
qr := querierAll[[]*Platform, *PlatformQuery]()
return withInterceptors[[]*Platform](ctx, pq, qr, pq.inters)
}
// AllX is like All, but panics if an error occurs.
func (pq *PlatformQuery) AllX(ctx context.Context) []*Platform {
nodes, err := pq.All(ctx)
if err != nil {
panic(err)
}
return nodes
}
// IDs executes the query and returns a list of Platform IDs.
func (pq *PlatformQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
if pq.ctx.Unique == nil && pq.path != nil {
pq.Unique(true)
}
ctx = setContextOp(ctx, pq.ctx, "IDs")
if err = pq.Select(platform.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
return ids, nil
}
// IDsX is like IDs, but panics if an error occurs.
func (pq *PlatformQuery) IDsX(ctx context.Context) []uuid.UUID {
ids, err := pq.IDs(ctx)
if err != nil {
panic(err)
}
return ids
}
// Count returns the count of the given query.
func (pq *PlatformQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, pq.ctx, "Count")
if err := pq.prepareQuery(ctx); err != nil {
return 0, err
}
return withInterceptors[int](ctx, pq, querierCount[*PlatformQuery](), pq.inters)
}
// CountX is like Count, but panics if an error occurs.
func (pq *PlatformQuery) CountX(ctx context.Context) int {
count, err := pq.Count(ctx)
if err != nil {
panic(err)
}
return count
}
// Exist returns true if the query has elements in the graph.
func (pq *PlatformQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, pq.ctx, "Exist")
switch _, err := pq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
case err != nil:
return false, fmt.Errorf("ent: check existence: %w", err)
default:
return true, nil
}
}
// ExistX is like Exist, but panics if an error occurs.
func (pq *PlatformQuery) ExistX(ctx context.Context) bool {
exist, err := pq.Exist(ctx)
if err != nil {
panic(err)
}
return exist
}
// Clone returns a duplicate of the PlatformQuery builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made.
func (pq *PlatformQuery) Clone() *PlatformQuery {
if pq == nil {
return nil
}
return &PlatformQuery{
config: pq.config,
ctx: pq.ctx.Clone(),
order: append([]platform.OrderOption{}, pq.order...),
inters: append([]Interceptor{}, pq.inters...),
predicates: append([]predicate.Platform{}, pq.predicates...),
withCreator: pq.withCreator.Clone(),
withOrganization: pq.withOrganization.Clone(),
// clone intermediate query.
sql: pq.sql.Clone(),
path: pq.path,
}
}
// WithCreator tells the query-builder to eager-load the nodes that are connected to
// the "creator" edge. The optional arguments are used to configure the query builder of the edge.
func (pq *PlatformQuery) WithCreator(opts ...func(*UserQuery)) *PlatformQuery {
query := (&UserClient{config: pq.config}).Query()
for _, opt := range opts {
opt(query)
}
pq.withCreator = query
return pq
}
// WithOrganization tells the query-builder to eager-load the nodes that are connected to
// the "organization" edge. The optional arguments are used to configure the query builder of the edge.
func (pq *PlatformQuery) WithOrganization(opts ...func(*OrganizationQuery)) *PlatformQuery {
query := (&OrganizationClient{config: pq.config}).Query()
for _, opt := range opts {
opt(query)
}
pq.withOrganization = query
return pq
}
// GroupBy is used to group vertices by one or more fields/columns.
// It is often used with aggregate functions, like: count, max, mean, min, sum.
//
// Example:
//
// var v []struct {
// CreatedAt time.Time `json:"created_at,omitempty"`
// Count int `json:"count,omitempty"`
// }
//
// client.Platform.Query().
// GroupBy(platform.FieldCreatedAt).
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (pq *PlatformQuery) GroupBy(field string, fields ...string) *PlatformGroupBy {
pq.ctx.Fields = append([]string{field}, fields...)
grbuild := &PlatformGroupBy{build: pq}
grbuild.flds = &pq.ctx.Fields
grbuild.label = platform.Label
grbuild.scan = grbuild.Scan
return grbuild
}
// Select allows the selection one or more fields/columns for the given query,
// instead of selecting all fields in the entity.
//
// Example:
//
// var v []struct {
// CreatedAt time.Time `json:"created_at,omitempty"`
// }
//
// client.Platform.Query().
// Select(platform.FieldCreatedAt).
// Scan(ctx, &v)
func (pq *PlatformQuery) Select(fields ...string) *PlatformSelect {
pq.ctx.Fields = append(pq.ctx.Fields, fields...)
sbuild := &PlatformSelect{PlatformQuery: pq}
sbuild.label = platform.Label
sbuild.flds, sbuild.scan = &pq.ctx.Fields, sbuild.Scan
return sbuild
}
// Aggregate returns a PlatformSelect configured with the given aggregations.
func (pq *PlatformQuery) Aggregate(fns ...AggregateFunc) *PlatformSelect {
return pq.Select().Aggregate(fns...)
}
func (pq *PlatformQuery) prepareQuery(ctx context.Context) error {
for _, inter := range pq.inters {
if inter == nil {
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
}
if trv, ok := inter.(Traverser); ok {
if err := trv.Traverse(ctx, pq); err != nil {
return err
}
}
}
for _, f := range pq.ctx.Fields {
if !platform.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
}
if pq.path != nil {
prev, err := pq.path(ctx)
if err != nil {
return err
}
pq.sql = prev
}
return nil
}
func (pq *PlatformQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Platform, error) {
var (
nodes = []*Platform{}
_spec = pq.querySpec()
loadedTypes = [2]bool{
pq.withCreator != nil,
pq.withOrganization != nil,
}
)
_spec.ScanValues = func(columns []string) ([]any, error) {
return (*Platform).scanValues(nil, columns)
}
_spec.Assign = func(columns []string, values []any) error {
node := &Platform{config: pq.config}
nodes = append(nodes, node)
node.Edges.loadedTypes = loadedTypes
return node.assignValues(columns, values)
}
for i := range hooks {
hooks[i](ctx, _spec)
}
if err := sqlgraph.QueryNodes(ctx, pq.driver, _spec); err != nil {
return nil, err
}
if len(nodes) == 0 {
return nodes, nil
}
if query := pq.withCreator; query != nil {
if err := pq.loadCreator(ctx, query, nodes, nil,
func(n *Platform, e *User) { n.Edges.Creator = e }); err != nil {
return nil, err
}
}
if query := pq.withOrganization; query != nil {
if err := pq.loadOrganization(ctx, query, nodes, nil,
func(n *Platform, e *Organization) { n.Edges.Organization = e }); err != nil {
return nil, err
}
}
return nodes, nil
}
func (pq *PlatformQuery) loadCreator(ctx context.Context, query *UserQuery, nodes []*Platform, init func(*Platform), assign func(*Platform, *User)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Platform)
for i := range nodes {
fk := nodes[i].CreatorID
if _, ok := nodeids[fk]; !ok {
ids = append(ids, fk)
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(user.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
nodes, ok := nodeids[n.ID]
if !ok {
return fmt.Errorf(`unexpected foreign-key "creator_id" returned %v`, n.ID)
}
for i := range nodes {
assign(nodes[i], n)
}
}
return nil
}
func (pq *PlatformQuery) loadOrganization(ctx context.Context, query *OrganizationQuery, nodes []*Platform, init func(*Platform), assign func(*Platform, *Organization)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Platform)
for i := range nodes {
fk := nodes[i].OrgID
if _, ok := nodeids[fk]; !ok {
ids = append(ids, fk)
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(organization.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
nodes, ok := nodeids[n.ID]
if !ok {
return fmt.Errorf(`unexpected foreign-key "org_id" returned %v`, n.ID)
}
for i := range nodes {
assign(nodes[i], n)
}
}
return nil
}
func (pq *PlatformQuery) sqlCount(ctx context.Context) (int, error) {
_spec := pq.querySpec()
_spec.Node.Columns = pq.ctx.Fields
if len(pq.ctx.Fields) > 0 {
_spec.Unique = pq.ctx.Unique != nil && *pq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, pq.driver, _spec)
}
func (pq *PlatformQuery) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec(platform.Table, platform.Columns, sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID))
_spec.From = pq.sql
if unique := pq.ctx.Unique; unique != nil {
_spec.Unique = *unique
} else if pq.path != nil {
_spec.Unique = true
}
if fields := pq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, platform.FieldID)
for i := range fields {
if fields[i] != platform.FieldID {
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
}
}
if pq.withCreator != nil {
_spec.Node.AddColumnOnce(platform.FieldCreatorID)
}
if pq.withOrganization != nil {
_spec.Node.AddColumnOnce(platform.FieldOrgID)
}
}
if ps := pq.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if limit := pq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := pq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := pq.order; len(ps) > 0 {
_spec.Order = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
return _spec
}
func (pq *PlatformQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(pq.driver.Dialect())
t1 := builder.Table(platform.Table)
columns := pq.ctx.Fields
if len(columns) == 0 {
columns = platform.Columns
}
selector := builder.Select(t1.Columns(columns...)...).From(t1)
if pq.sql != nil {
selector = pq.sql
selector.Select(selector.Columns(columns...)...)
}
if pq.ctx.Unique != nil && *pq.ctx.Unique {
selector.Distinct()
}
for _, p := range pq.predicates {
p(selector)
}
for _, p := range pq.order {
p(selector)
}
if offset := pq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := pq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
}
// PlatformGroupBy is the group-by builder for Platform entities.
type PlatformGroupBy struct {
selector
build *PlatformQuery
}
// Aggregate adds the given aggregation functions to the group-by query.
func (pgb *PlatformGroupBy) Aggregate(fns ...AggregateFunc) *PlatformGroupBy {
pgb.fns = append(pgb.fns, fns...)
return pgb
}
// Scan applies the selector query and scans the result into the given value.
func (pgb *PlatformGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, pgb.build.ctx, "GroupBy")
if err := pgb.build.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*PlatformQuery, *PlatformGroupBy](ctx, pgb.build, pgb, pgb.build.inters, v)
}
func (pgb *PlatformGroupBy) sqlScan(ctx context.Context, root *PlatformQuery, v any) error {
selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len(pgb.fns))
for _, fn := range pgb.fns {
aggregation = append(aggregation, fn(selector))
}
if len(selector.SelectedColumns()) == 0 {
columns := make([]string, 0, len(*pgb.flds)+len(pgb.fns))
for _, f := range *pgb.flds {
columns = append(columns, selector.C(f))
}
columns = append(columns, aggregation...)
selector.Select(columns...)
}
selector.GroupBy(selector.Columns(*pgb.flds...)...)
if err := selector.Err(); err != nil {
return err
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := pgb.build.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}
// PlatformSelect is the builder for selecting fields of Platform entities.
type PlatformSelect struct {
*PlatformQuery
selector
}
// Aggregate adds the given aggregation functions to the selector query.
func (ps *PlatformSelect) Aggregate(fns ...AggregateFunc) *PlatformSelect {
ps.fns = append(ps.fns, fns...)
return ps
}
// Scan applies the selector query and scans the result into the given value.
func (ps *PlatformSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, ps.ctx, "Select")
if err := ps.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*PlatformQuery, *PlatformSelect](ctx, ps.PlatformQuery, ps, ps.inters, v)
}
func (ps *PlatformSelect) sqlScan(ctx context.Context, root *PlatformQuery, v any) error {
selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len(ps.fns))
for _, fn := range ps.fns {
aggregation = append(aggregation, fn(selector))
}
switch n := len(*ps.selector.flds); {
case n == 0 && len(aggregation) > 0:
selector.Select(aggregation...)
case n != 0 && len(aggregation) > 0:
selector.AppendSelect(aggregation...)
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := ps.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}

View File

@@ -0,0 +1,710 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/predicate"
"github.com/holos-run/holos/internal/ent/user"
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
)
// PlatformUpdate is the builder for updating Platform entities.
type PlatformUpdate struct {
config
hooks []Hook
mutation *PlatformMutation
}
// Where appends a list predicates to the PlatformUpdate builder.
func (pu *PlatformUpdate) Where(ps ...predicate.Platform) *PlatformUpdate {
pu.mutation.Where(ps...)
return pu
}
// SetUpdatedAt sets the "updated_at" field.
func (pu *PlatformUpdate) SetUpdatedAt(t time.Time) *PlatformUpdate {
pu.mutation.SetUpdatedAt(t)
return pu
}
// SetOrgID sets the "org_id" field.
func (pu *PlatformUpdate) SetOrgID(u uuid.UUID) *PlatformUpdate {
pu.mutation.SetOrgID(u)
return pu
}
// SetNillableOrgID sets the "org_id" field if the given value is not nil.
func (pu *PlatformUpdate) SetNillableOrgID(u *uuid.UUID) *PlatformUpdate {
if u != nil {
pu.SetOrgID(*u)
}
return pu
}
// SetName sets the "name" field.
func (pu *PlatformUpdate) SetName(s string) *PlatformUpdate {
pu.mutation.SetName(s)
return pu
}
// SetNillableName sets the "name" field if the given value is not nil.
func (pu *PlatformUpdate) SetNillableName(s *string) *PlatformUpdate {
if s != nil {
pu.SetName(*s)
}
return pu
}
// SetDisplayName sets the "display_name" field.
func (pu *PlatformUpdate) SetDisplayName(s string) *PlatformUpdate {
pu.mutation.SetDisplayName(s)
return pu
}
// SetNillableDisplayName sets the "display_name" field if the given value is not nil.
func (pu *PlatformUpdate) SetNillableDisplayName(s *string) *PlatformUpdate {
if s != nil {
pu.SetDisplayName(*s)
}
return pu
}
// SetCreatorID sets the "creator_id" field.
func (pu *PlatformUpdate) SetCreatorID(u uuid.UUID) *PlatformUpdate {
pu.mutation.SetCreatorID(u)
return pu
}
// SetNillableCreatorID sets the "creator_id" field if the given value is not nil.
func (pu *PlatformUpdate) SetNillableCreatorID(u *uuid.UUID) *PlatformUpdate {
if u != nil {
pu.SetCreatorID(*u)
}
return pu
}
// SetForm sets the "form" field.
func (pu *PlatformUpdate) SetForm(h *holos.Form) *PlatformUpdate {
pu.mutation.SetForm(h)
return pu
}
// ClearForm clears the value of the "form" field.
func (pu *PlatformUpdate) ClearForm() *PlatformUpdate {
pu.mutation.ClearForm()
return pu
}
// SetModel sets the "model" field.
func (pu *PlatformUpdate) SetModel(h *holos.Model) *PlatformUpdate {
pu.mutation.SetModel(h)
return pu
}
// ClearModel clears the value of the "model" field.
func (pu *PlatformUpdate) ClearModel() *PlatformUpdate {
pu.mutation.ClearModel()
return pu
}
// SetCue sets the "cue" field.
func (pu *PlatformUpdate) SetCue(b []byte) *PlatformUpdate {
pu.mutation.SetCue(b)
return pu
}
// ClearCue clears the value of the "cue" field.
func (pu *PlatformUpdate) ClearCue() *PlatformUpdate {
pu.mutation.ClearCue()
return pu
}
// SetCueDefinition sets the "cue_definition" field.
func (pu *PlatformUpdate) SetCueDefinition(s string) *PlatformUpdate {
pu.mutation.SetCueDefinition(s)
return pu
}
// SetNillableCueDefinition sets the "cue_definition" field if the given value is not nil.
func (pu *PlatformUpdate) SetNillableCueDefinition(s *string) *PlatformUpdate {
if s != nil {
pu.SetCueDefinition(*s)
}
return pu
}
// ClearCueDefinition clears the value of the "cue_definition" field.
func (pu *PlatformUpdate) ClearCueDefinition() *PlatformUpdate {
pu.mutation.ClearCueDefinition()
return pu
}
// SetCreator sets the "creator" edge to the User entity.
func (pu *PlatformUpdate) SetCreator(u *User) *PlatformUpdate {
return pu.SetCreatorID(u.ID)
}
// SetOrganizationID sets the "organization" edge to the Organization entity by ID.
func (pu *PlatformUpdate) SetOrganizationID(id uuid.UUID) *PlatformUpdate {
pu.mutation.SetOrganizationID(id)
return pu
}
// SetOrganization sets the "organization" edge to the Organization entity.
func (pu *PlatformUpdate) SetOrganization(o *Organization) *PlatformUpdate {
return pu.SetOrganizationID(o.ID)
}
// Mutation returns the PlatformMutation object of the builder.
func (pu *PlatformUpdate) Mutation() *PlatformMutation {
return pu.mutation
}
// ClearCreator clears the "creator" edge to the User entity.
func (pu *PlatformUpdate) ClearCreator() *PlatformUpdate {
pu.mutation.ClearCreator()
return pu
}
// ClearOrganization clears the "organization" edge to the Organization entity.
func (pu *PlatformUpdate) ClearOrganization() *PlatformUpdate {
pu.mutation.ClearOrganization()
return pu
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (pu *PlatformUpdate) Save(ctx context.Context) (int, error) {
pu.defaults()
return withHooks(ctx, pu.sqlSave, pu.mutation, pu.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (pu *PlatformUpdate) SaveX(ctx context.Context) int {
affected, err := pu.Save(ctx)
if err != nil {
panic(err)
}
return affected
}
// Exec executes the query.
func (pu *PlatformUpdate) Exec(ctx context.Context) error {
_, err := pu.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (pu *PlatformUpdate) ExecX(ctx context.Context) {
if err := pu.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (pu *PlatformUpdate) defaults() {
if _, ok := pu.mutation.UpdatedAt(); !ok {
v := platform.UpdateDefaultUpdatedAt()
pu.mutation.SetUpdatedAt(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (pu *PlatformUpdate) check() error {
if v, ok := pu.mutation.Name(); ok {
if err := platform.NameValidator(v); err != nil {
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Platform.name": %w`, err)}
}
}
if _, ok := pu.mutation.CreatorID(); pu.mutation.CreatorCleared() && !ok {
return errors.New(`ent: clearing a required unique edge "Platform.creator"`)
}
if _, ok := pu.mutation.OrganizationID(); pu.mutation.OrganizationCleared() && !ok {
return errors.New(`ent: clearing a required unique edge "Platform.organization"`)
}
return nil
}
func (pu *PlatformUpdate) sqlSave(ctx context.Context) (n int, err error) {
if err := pu.check(); err != nil {
return n, err
}
_spec := sqlgraph.NewUpdateSpec(platform.Table, platform.Columns, sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID))
if ps := pu.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := pu.mutation.UpdatedAt(); ok {
_spec.SetField(platform.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := pu.mutation.Name(); ok {
_spec.SetField(platform.FieldName, field.TypeString, value)
}
if value, ok := pu.mutation.DisplayName(); ok {
_spec.SetField(platform.FieldDisplayName, field.TypeString, value)
}
if value, ok := pu.mutation.Form(); ok {
_spec.SetField(platform.FieldForm, field.TypeJSON, value)
}
if pu.mutation.FormCleared() {
_spec.ClearField(platform.FieldForm, field.TypeJSON)
}
if value, ok := pu.mutation.Model(); ok {
_spec.SetField(platform.FieldModel, field.TypeJSON, value)
}
if pu.mutation.ModelCleared() {
_spec.ClearField(platform.FieldModel, field.TypeJSON)
}
if value, ok := pu.mutation.Cue(); ok {
_spec.SetField(platform.FieldCue, field.TypeBytes, value)
}
if pu.mutation.CueCleared() {
_spec.ClearField(platform.FieldCue, field.TypeBytes)
}
if value, ok := pu.mutation.CueDefinition(); ok {
_spec.SetField(platform.FieldCueDefinition, field.TypeString, value)
}
if pu.mutation.CueDefinitionCleared() {
_spec.ClearField(platform.FieldCueDefinition, field.TypeString)
}
if pu.mutation.CreatorCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: platform.CreatorTable,
Columns: []string{platform.CreatorColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := pu.mutation.CreatorIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: platform.CreatorTable,
Columns: []string{platform.CreatorColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if pu.mutation.OrganizationCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: platform.OrganizationTable,
Columns: []string{platform.OrganizationColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := pu.mutation.OrganizationIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: platform.OrganizationTable,
Columns: []string{platform.OrganizationColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if n, err = sqlgraph.UpdateNodes(ctx, pu.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{platform.Label}
} else if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return 0, err
}
pu.mutation.done = true
return n, nil
}
// PlatformUpdateOne is the builder for updating a single Platform entity.
type PlatformUpdateOne struct {
config
fields []string
hooks []Hook
mutation *PlatformMutation
}
// SetUpdatedAt sets the "updated_at" field.
func (puo *PlatformUpdateOne) SetUpdatedAt(t time.Time) *PlatformUpdateOne {
puo.mutation.SetUpdatedAt(t)
return puo
}
// SetOrgID sets the "org_id" field.
func (puo *PlatformUpdateOne) SetOrgID(u uuid.UUID) *PlatformUpdateOne {
puo.mutation.SetOrgID(u)
return puo
}
// SetNillableOrgID sets the "org_id" field if the given value is not nil.
func (puo *PlatformUpdateOne) SetNillableOrgID(u *uuid.UUID) *PlatformUpdateOne {
if u != nil {
puo.SetOrgID(*u)
}
return puo
}
// SetName sets the "name" field.
func (puo *PlatformUpdateOne) SetName(s string) *PlatformUpdateOne {
puo.mutation.SetName(s)
return puo
}
// SetNillableName sets the "name" field if the given value is not nil.
func (puo *PlatformUpdateOne) SetNillableName(s *string) *PlatformUpdateOne {
if s != nil {
puo.SetName(*s)
}
return puo
}
// SetDisplayName sets the "display_name" field.
func (puo *PlatformUpdateOne) SetDisplayName(s string) *PlatformUpdateOne {
puo.mutation.SetDisplayName(s)
return puo
}
// SetNillableDisplayName sets the "display_name" field if the given value is not nil.
func (puo *PlatformUpdateOne) SetNillableDisplayName(s *string) *PlatformUpdateOne {
if s != nil {
puo.SetDisplayName(*s)
}
return puo
}
// SetCreatorID sets the "creator_id" field.
func (puo *PlatformUpdateOne) SetCreatorID(u uuid.UUID) *PlatformUpdateOne {
puo.mutation.SetCreatorID(u)
return puo
}
// SetNillableCreatorID sets the "creator_id" field if the given value is not nil.
func (puo *PlatformUpdateOne) SetNillableCreatorID(u *uuid.UUID) *PlatformUpdateOne {
if u != nil {
puo.SetCreatorID(*u)
}
return puo
}
// SetForm sets the "form" field.
func (puo *PlatformUpdateOne) SetForm(h *holos.Form) *PlatformUpdateOne {
puo.mutation.SetForm(h)
return puo
}
// ClearForm clears the value of the "form" field.
func (puo *PlatformUpdateOne) ClearForm() *PlatformUpdateOne {
puo.mutation.ClearForm()
return puo
}
// SetModel sets the "model" field.
func (puo *PlatformUpdateOne) SetModel(h *holos.Model) *PlatformUpdateOne {
puo.mutation.SetModel(h)
return puo
}
// ClearModel clears the value of the "model" field.
func (puo *PlatformUpdateOne) ClearModel() *PlatformUpdateOne {
puo.mutation.ClearModel()
return puo
}
// SetCue sets the "cue" field.
func (puo *PlatformUpdateOne) SetCue(b []byte) *PlatformUpdateOne {
puo.mutation.SetCue(b)
return puo
}
// ClearCue clears the value of the "cue" field.
func (puo *PlatformUpdateOne) ClearCue() *PlatformUpdateOne {
puo.mutation.ClearCue()
return puo
}
// SetCueDefinition sets the "cue_definition" field.
func (puo *PlatformUpdateOne) SetCueDefinition(s string) *PlatformUpdateOne {
puo.mutation.SetCueDefinition(s)
return puo
}
// SetNillableCueDefinition sets the "cue_definition" field if the given value is not nil.
func (puo *PlatformUpdateOne) SetNillableCueDefinition(s *string) *PlatformUpdateOne {
if s != nil {
puo.SetCueDefinition(*s)
}
return puo
}
// ClearCueDefinition clears the value of the "cue_definition" field.
func (puo *PlatformUpdateOne) ClearCueDefinition() *PlatformUpdateOne {
puo.mutation.ClearCueDefinition()
return puo
}
// SetCreator sets the "creator" edge to the User entity.
func (puo *PlatformUpdateOne) SetCreator(u *User) *PlatformUpdateOne {
return puo.SetCreatorID(u.ID)
}
// SetOrganizationID sets the "organization" edge to the Organization entity by ID.
func (puo *PlatformUpdateOne) SetOrganizationID(id uuid.UUID) *PlatformUpdateOne {
puo.mutation.SetOrganizationID(id)
return puo
}
// SetOrganization sets the "organization" edge to the Organization entity.
func (puo *PlatformUpdateOne) SetOrganization(o *Organization) *PlatformUpdateOne {
return puo.SetOrganizationID(o.ID)
}
// Mutation returns the PlatformMutation object of the builder.
func (puo *PlatformUpdateOne) Mutation() *PlatformMutation {
return puo.mutation
}
// ClearCreator clears the "creator" edge to the User entity.
func (puo *PlatformUpdateOne) ClearCreator() *PlatformUpdateOne {
puo.mutation.ClearCreator()
return puo
}
// ClearOrganization clears the "organization" edge to the Organization entity.
func (puo *PlatformUpdateOne) ClearOrganization() *PlatformUpdateOne {
puo.mutation.ClearOrganization()
return puo
}
// Where appends a list predicates to the PlatformUpdate builder.
func (puo *PlatformUpdateOne) Where(ps ...predicate.Platform) *PlatformUpdateOne {
puo.mutation.Where(ps...)
return puo
}
// Select allows selecting one or more fields (columns) of the returned entity.
// The default is selecting all fields defined in the entity schema.
func (puo *PlatformUpdateOne) Select(field string, fields ...string) *PlatformUpdateOne {
puo.fields = append([]string{field}, fields...)
return puo
}
// Save executes the query and returns the updated Platform entity.
func (puo *PlatformUpdateOne) Save(ctx context.Context) (*Platform, error) {
puo.defaults()
return withHooks(ctx, puo.sqlSave, puo.mutation, puo.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (puo *PlatformUpdateOne) SaveX(ctx context.Context) *Platform {
node, err := puo.Save(ctx)
if err != nil {
panic(err)
}
return node
}
// Exec executes the query on the entity.
func (puo *PlatformUpdateOne) Exec(ctx context.Context) error {
_, err := puo.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (puo *PlatformUpdateOne) ExecX(ctx context.Context) {
if err := puo.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (puo *PlatformUpdateOne) defaults() {
if _, ok := puo.mutation.UpdatedAt(); !ok {
v := platform.UpdateDefaultUpdatedAt()
puo.mutation.SetUpdatedAt(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (puo *PlatformUpdateOne) check() error {
if v, ok := puo.mutation.Name(); ok {
if err := platform.NameValidator(v); err != nil {
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Platform.name": %w`, err)}
}
}
if _, ok := puo.mutation.CreatorID(); puo.mutation.CreatorCleared() && !ok {
return errors.New(`ent: clearing a required unique edge "Platform.creator"`)
}
if _, ok := puo.mutation.OrganizationID(); puo.mutation.OrganizationCleared() && !ok {
return errors.New(`ent: clearing a required unique edge "Platform.organization"`)
}
return nil
}
func (puo *PlatformUpdateOne) sqlSave(ctx context.Context) (_node *Platform, err error) {
if err := puo.check(); err != nil {
return _node, err
}
_spec := sqlgraph.NewUpdateSpec(platform.Table, platform.Columns, sqlgraph.NewFieldSpec(platform.FieldID, field.TypeUUID))
id, ok := puo.mutation.ID()
if !ok {
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Platform.id" for update`)}
}
_spec.Node.ID.Value = id
if fields := puo.fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, platform.FieldID)
for _, f := range fields {
if !platform.ValidColumn(f) {
return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
if f != platform.FieldID {
_spec.Node.Columns = append(_spec.Node.Columns, f)
}
}
}
if ps := puo.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := puo.mutation.UpdatedAt(); ok {
_spec.SetField(platform.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := puo.mutation.Name(); ok {
_spec.SetField(platform.FieldName, field.TypeString, value)
}
if value, ok := puo.mutation.DisplayName(); ok {
_spec.SetField(platform.FieldDisplayName, field.TypeString, value)
}
if value, ok := puo.mutation.Form(); ok {
_spec.SetField(platform.FieldForm, field.TypeJSON, value)
}
if puo.mutation.FormCleared() {
_spec.ClearField(platform.FieldForm, field.TypeJSON)
}
if value, ok := puo.mutation.Model(); ok {
_spec.SetField(platform.FieldModel, field.TypeJSON, value)
}
if puo.mutation.ModelCleared() {
_spec.ClearField(platform.FieldModel, field.TypeJSON)
}
if value, ok := puo.mutation.Cue(); ok {
_spec.SetField(platform.FieldCue, field.TypeBytes, value)
}
if puo.mutation.CueCleared() {
_spec.ClearField(platform.FieldCue, field.TypeBytes)
}
if value, ok := puo.mutation.CueDefinition(); ok {
_spec.SetField(platform.FieldCueDefinition, field.TypeString, value)
}
if puo.mutation.CueDefinitionCleared() {
_spec.ClearField(platform.FieldCueDefinition, field.TypeString)
}
if puo.mutation.CreatorCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: platform.CreatorTable,
Columns: []string{platform.CreatorColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := puo.mutation.CreatorIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: platform.CreatorTable,
Columns: []string{platform.CreatorColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if puo.mutation.OrganizationCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: platform.OrganizationTable,
Columns: []string{platform.OrganizationColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := puo.mutation.OrganizationIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: false,
Table: platform.OrganizationTable,
Columns: []string{platform.OrganizationColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
_node = &Platform{config: puo.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues
if err = sqlgraph.UpdateNode(ctx, puo.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{platform.Label}
} else if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return nil, err
}
puo.mutation.done = true
return _node, nil
}

View File

@@ -9,5 +9,8 @@ import (
// Organization is the predicate function for organization builders.
type Organization func(*sql.Selector)
// Platform is the predicate function for platform builders.
type Platform func(*sql.Selector)
// User is the predicate function for user builders.
type User func(*sql.Selector)

View File

@@ -7,6 +7,7 @@ import (
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/platform"
"github.com/holos-run/holos/internal/ent/schema"
"github.com/holos-run/holos/internal/ent/user"
)
@@ -40,6 +41,31 @@ func init() {
organizationDescID := organizationMixinFields0[0].Descriptor()
// organization.DefaultID holds the default value on creation for the id field.
organization.DefaultID = organizationDescID.Default.(func() uuid.UUID)
platformMixin := schema.Platform{}.Mixin()
platformMixinFields0 := platformMixin[0].Fields()
_ = platformMixinFields0
platformMixinFields1 := platformMixin[1].Fields()
_ = platformMixinFields1
platformFields := schema.Platform{}.Fields()
_ = platformFields
// platformDescCreatedAt is the schema descriptor for created_at field.
platformDescCreatedAt := platformMixinFields1[0].Descriptor()
// platform.DefaultCreatedAt holds the default value on creation for the created_at field.
platform.DefaultCreatedAt = platformDescCreatedAt.Default.(func() time.Time)
// platformDescUpdatedAt is the schema descriptor for updated_at field.
platformDescUpdatedAt := platformMixinFields1[1].Descriptor()
// platform.DefaultUpdatedAt holds the default value on creation for the updated_at field.
platform.DefaultUpdatedAt = platformDescUpdatedAt.Default.(func() time.Time)
// platform.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
platform.UpdateDefaultUpdatedAt = platformDescUpdatedAt.UpdateDefault.(func() time.Time)
// platformDescName is the schema descriptor for name field.
platformDescName := platformFields[1].Descriptor()
// platform.NameValidator is a validator for the "name" field. It is called by the builders before save.
platform.NameValidator = platformDescName.Validators[0].(func(string) error)
// platformDescID is the schema descriptor for id field.
platformDescID := platformMixinFields0[0].Descriptor()
// platform.DefaultID holds the default value on creation for the id field.
platform.DefaultID = platformDescID.Default.(func() uuid.UUID)
userMixin := schema.User{}.Mixin()
userMixinFields0 := userMixin[0].Fields()
_ = userMixinFields0

View File

@@ -1,11 +1,12 @@
package schema
import (
"time"
"entgo.io/ent"
"entgo.io/ent/schema/field"
"entgo.io/ent/schema/mixin"
"github.com/gofrs/uuid"
"time"
)
func newUUID() uuid.UUID {
@@ -18,6 +19,7 @@ type BaseMixin struct {
func (BaseMixin) Fields() []ent.Field {
return []ent.Field{
// id represents the identity of the entity.
field.UUID("id", uuid.UUID{}).Default(newUUID),
}
}

View File

@@ -2,26 +2,39 @@ package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
)
// User holds the schema definition for the User entity, the internal
// representation and identity of a single human user. Users are scoped
// globally.
// Organization represents an organization account.
type Organization struct {
ent.Schema
}
func (Organization) Fields() []ent.Field {
return []ent.Field{
field.String("name").NotEmpty().Unique(),
field.String("display_name"),
}
}
func (Organization) Mixin() []ent.Mixin {
return []ent.Mixin{
BaseMixin{},
TimeMixin{},
}
}
func (Organization) Fields() []ent.Field {
return []ent.Field{
field.String("name").NotEmpty().Unique(),
field.String("display_name"),
field.UUID("creator_id", uuid.UUID{}),
}
}
func (Organization) Edges() []ent.Edge {
return []ent.Edge{
edge.To("creator", User.Type).
Field("creator_id").
Unique().
Required(),
edge.To("users", User.Type),
edge.From("platforms", Platform.Type).
Ref("organization"),
}
}

View File

@@ -0,0 +1,62 @@
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
"entgo.io/ent/schema/index"
"github.com/gofrs/uuid"
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
)
type Platform struct {
ent.Schema
}
func (Platform) Mixin() []ent.Mixin {
return []ent.Mixin{
BaseMixin{},
TimeMixin{},
}
}
func (Platform) Fields() []ent.Field {
return []ent.Field{
field.UUID("org_id", uuid.UUID{}),
field.String("name").NotEmpty(),
field.String("display_name"),
field.UUID("creator_id", uuid.UUID{}),
field.JSON("form", &holos.Form{}).
Optional().
Comment("JSON representation of FormlyFormConfig[] refer to https://github.com/holos-run/holos/issues/161"),
field.JSON("model", &holos.Model{}).
Optional().
Comment("JSON representation of the form model which holds user input values refer to https://github.com/holos-run/holos/issues/161"),
field.Bytes("cue").
Optional().
Comment("CUE definition to vet the model against e.g. #PlatformConfig"),
field.String("cue_definition").
Optional().
Comment("The definition name to vet config_values against config_cue e.g. '#PlatformSpec'"),
}
}
func (Platform) Edges() []ent.Edge {
return []ent.Edge{
edge.To("creator", User.Type).
Field("creator_id").
Unique().
Required(),
edge.To("organization", Organization.Type).
Field("org_id").
Unique().
Required(),
}
}
func (Platform) Indexes() []ent.Index {
return []ent.Index{
// One org cannot have two platforms with the same name.
index.Fields("org_id", "name").Unique(),
}
}

View File

@@ -2,7 +2,9 @@ package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
"entgo.io/ent/schema/index"
)
// User holds the schema definition for the User entity, the internal
@@ -28,3 +30,16 @@ func (User) Fields() []ent.Field {
field.String("name"),
}
}
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.From("organizations", Organization.Type).
Ref("users"),
}
}
func (User) Indexes() []ent.Index {
return []ent.Index{
index.Fields("iss", "sub").Unique(),
}
}

View File

@@ -14,6 +14,8 @@ type Tx struct {
config
// Organization is the client for interacting with the Organization builders.
Organization *OrganizationClient
// Platform is the client for interacting with the Platform builders.
Platform *PlatformClient
// User is the client for interacting with the User builders.
User *UserClient
@@ -148,6 +150,7 @@ func (tx *Tx) Client() *Client {
func (tx *Tx) init() {
tx.Organization = NewOrganizationClient(tx.config)
tx.Platform = NewPlatformClient(tx.config)
tx.User = NewUserClient(tx.config)
}

View File

@@ -29,10 +29,31 @@ type User struct {
// Sub holds the value of the "sub" field.
Sub string `json:"sub,omitempty"`
// Name holds the value of the "name" field.
Name string `json:"name,omitempty"`
Name string `json:"name,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the UserQuery when eager-loading is set.
Edges UserEdges `json:"edges"`
selectValues sql.SelectValues
}
// UserEdges holds the relations/edges for other nodes in the graph.
type UserEdges struct {
// Organizations holds the value of the organizations edge.
Organizations []*Organization `json:"organizations,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [1]bool
}
// OrganizationsOrErr returns the Organizations value or an error if the edge
// was not loaded in eager-loading.
func (e UserEdges) OrganizationsOrErr() ([]*Organization, error) {
if e.loadedTypes[0] {
return e.Organizations, nil
}
return nil, &NotLoadedError{edge: "organizations"}
}
// scanValues returns the types for scanning values from sql.Rows.
func (*User) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
@@ -114,6 +135,11 @@ func (u *User) Value(name string) (ent.Value, error) {
return u.selectValues.Get(name)
}
// QueryOrganizations queries the "organizations" edge of the User entity.
func (u *User) QueryOrganizations() *OrganizationQuery {
return NewUserClient(u.config).QueryOrganizations(u)
}
// Update returns a builder for updating this User.
// Note that you need to call User.Unwrap() before calling this method if this User
// was returned from a transaction, and the transaction was committed or rolled back.

View File

@@ -6,6 +6,7 @@ import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/gofrs/uuid"
)
@@ -26,8 +27,15 @@ const (
FieldSub = "sub"
// FieldName holds the string denoting the name field in the database.
FieldName = "name"
// EdgeOrganizations holds the string denoting the organizations edge name in mutations.
EdgeOrganizations = "organizations"
// Table holds the table name of the user in the database.
Table = "users"
// OrganizationsTable is the table that holds the organizations relation/edge. The primary key declared below.
OrganizationsTable = "organization_users"
// OrganizationsInverseTable is the table name for the Organization entity.
// It exists in this package in order to avoid circular dependency with the "organization" package.
OrganizationsInverseTable = "organizations"
)
// Columns holds all SQL columns for user fields.
@@ -41,6 +49,12 @@ var Columns = []string{
FieldName,
}
var (
// OrganizationsPrimaryKey and OrganizationsColumn2 are the table columns denoting the
// primary key for the organizations relation (M2M).
OrganizationsPrimaryKey = []string{"organization_id", "user_id"}
)
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
@@ -101,3 +115,24 @@ func BySub(opts ...sql.OrderTermOption) OrderOption {
func ByName(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldName, opts...).ToFunc()
}
// ByOrganizationsCount orders the results by organizations count.
func ByOrganizationsCount(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborsCount(s, newOrganizationsStep(), opts...)
}
}
// ByOrganizations orders the results by organizations terms.
func ByOrganizations(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newOrganizationsStep(), append([]sql.OrderTerm{term}, terms...)...)
}
}
func newOrganizationsStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(OrganizationsInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2M, true, OrganizationsTable, OrganizationsPrimaryKey...),
)
}

View File

@@ -6,6 +6,7 @@ import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/predicate"
)
@@ -425,6 +426,29 @@ func NameContainsFold(v string) predicate.User {
return predicate.User(sql.FieldContainsFold(FieldName, v))
}
// HasOrganizations applies the HasEdge predicate on the "organizations" edge.
func HasOrganizations() predicate.User {
return predicate.User(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2M, true, OrganizationsTable, OrganizationsPrimaryKey...),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasOrganizationsWith applies the HasEdge predicate on the "organizations" edge with a given conditions (other predicates).
func HasOrganizationsWith(preds ...predicate.Organization) predicate.User {
return predicate.User(func(s *sql.Selector) {
step := newOrganizationsStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// And groups predicates with the AND operator between them.
func And(predicates ...predicate.User) predicate.User {
return predicate.User(sql.AndPredicates(predicates...))

View File

@@ -13,6 +13,7 @@ import (
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/user"
)
@@ -90,6 +91,21 @@ func (uc *UserCreate) SetNillableID(u *uuid.UUID) *UserCreate {
return uc
}
// AddOrganizationIDs adds the "organizations" edge to the Organization entity by IDs.
func (uc *UserCreate) AddOrganizationIDs(ids ...uuid.UUID) *UserCreate {
uc.mutation.AddOrganizationIDs(ids...)
return uc
}
// AddOrganizations adds the "organizations" edges to the Organization entity.
func (uc *UserCreate) AddOrganizations(o ...*Organization) *UserCreate {
ids := make([]uuid.UUID, len(o))
for i := range o {
ids[i] = o[i].ID
}
return uc.AddOrganizationIDs(ids...)
}
// Mutation returns the UserMutation object of the builder.
func (uc *UserCreate) Mutation() *UserMutation {
return uc.mutation
@@ -224,6 +240,22 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
_spec.SetField(user.FieldName, field.TypeString, value)
_node.Name = value
}
if nodes := uc.mutation.OrganizationsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: true,
Table: user.OrganizationsTable,
Columns: user.OrganizationsPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges = append(_spec.Edges, edge)
}
return _node, _spec
}

View File

@@ -4,6 +4,7 @@ package ent
import (
"context"
"database/sql/driver"
"fmt"
"math"
@@ -11,6 +12,7 @@ import (
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/predicate"
"github.com/holos-run/holos/internal/ent/user"
)
@@ -18,10 +20,11 @@ import (
// UserQuery is the builder for querying User entities.
type UserQuery struct {
config
ctx *QueryContext
order []user.OrderOption
inters []Interceptor
predicates []predicate.User
ctx *QueryContext
order []user.OrderOption
inters []Interceptor
predicates []predicate.User
withOrganizations *OrganizationQuery
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
@@ -58,6 +61,28 @@ func (uq *UserQuery) Order(o ...user.OrderOption) *UserQuery {
return uq
}
// QueryOrganizations chains the current query on the "organizations" edge.
func (uq *UserQuery) QueryOrganizations() *OrganizationQuery {
query := (&OrganizationClient{config: uq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := uq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := uq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(user.Table, user.FieldID, selector),
sqlgraph.To(organization.Table, organization.FieldID),
sqlgraph.Edge(sqlgraph.M2M, true, user.OrganizationsTable, user.OrganizationsPrimaryKey...),
)
fromU = sqlgraph.SetNeighbors(uq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// First returns the first User entity from the query.
// Returns a *NotFoundError when no User was found.
func (uq *UserQuery) First(ctx context.Context) (*User, error) {
@@ -245,17 +270,29 @@ func (uq *UserQuery) Clone() *UserQuery {
return nil
}
return &UserQuery{
config: uq.config,
ctx: uq.ctx.Clone(),
order: append([]user.OrderOption{}, uq.order...),
inters: append([]Interceptor{}, uq.inters...),
predicates: append([]predicate.User{}, uq.predicates...),
config: uq.config,
ctx: uq.ctx.Clone(),
order: append([]user.OrderOption{}, uq.order...),
inters: append([]Interceptor{}, uq.inters...),
predicates: append([]predicate.User{}, uq.predicates...),
withOrganizations: uq.withOrganizations.Clone(),
// clone intermediate query.
sql: uq.sql.Clone(),
path: uq.path,
}
}
// WithOrganizations tells the query-builder to eager-load the nodes that are connected to
// the "organizations" edge. The optional arguments are used to configure the query builder of the edge.
func (uq *UserQuery) WithOrganizations(opts ...func(*OrganizationQuery)) *UserQuery {
query := (&OrganizationClient{config: uq.config}).Query()
for _, opt := range opts {
opt(query)
}
uq.withOrganizations = query
return uq
}
// GroupBy is used to group vertices by one or more fields/columns.
// It is often used with aggregate functions, like: count, max, mean, min, sum.
//
@@ -332,8 +369,11 @@ func (uq *UserQuery) prepareQuery(ctx context.Context) error {
func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, error) {
var (
nodes = []*User{}
_spec = uq.querySpec()
nodes = []*User{}
_spec = uq.querySpec()
loadedTypes = [1]bool{
uq.withOrganizations != nil,
}
)
_spec.ScanValues = func(columns []string) ([]any, error) {
return (*User).scanValues(nil, columns)
@@ -341,6 +381,7 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
_spec.Assign = func(columns []string, values []any) error {
node := &User{config: uq.config}
nodes = append(nodes, node)
node.Edges.loadedTypes = loadedTypes
return node.assignValues(columns, values)
}
for i := range hooks {
@@ -352,9 +393,78 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
if len(nodes) == 0 {
return nodes, nil
}
if query := uq.withOrganizations; query != nil {
if err := uq.loadOrganizations(ctx, query, nodes,
func(n *User) { n.Edges.Organizations = []*Organization{} },
func(n *User, e *Organization) { n.Edges.Organizations = append(n.Edges.Organizations, e) }); err != nil {
return nil, err
}
}
return nodes, nil
}
func (uq *UserQuery) loadOrganizations(ctx context.Context, query *OrganizationQuery, nodes []*User, init func(*User), assign func(*User, *Organization)) error {
edgeIDs := make([]driver.Value, len(nodes))
byID := make(map[uuid.UUID]*User)
nids := make(map[uuid.UUID]map[*User]struct{})
for i, node := range nodes {
edgeIDs[i] = node.ID
byID[node.ID] = node
if init != nil {
init(node)
}
}
query.Where(func(s *sql.Selector) {
joinT := sql.Table(user.OrganizationsTable)
s.Join(joinT).On(s.C(organization.FieldID), joinT.C(user.OrganizationsPrimaryKey[0]))
s.Where(sql.InValues(joinT.C(user.OrganizationsPrimaryKey[1]), edgeIDs...))
columns := s.SelectedColumns()
s.Select(joinT.C(user.OrganizationsPrimaryKey[1]))
s.AppendSelect(columns...)
s.SetDistinct(false)
})
if err := query.prepareQuery(ctx); err != nil {
return err
}
qr := QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
return query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) {
assign := spec.Assign
values := spec.ScanValues
spec.ScanValues = func(columns []string) ([]any, error) {
values, err := values(columns[1:])
if err != nil {
return nil, err
}
return append([]any{new(uuid.UUID)}, values...), nil
}
spec.Assign = func(columns []string, values []any) error {
outValue := *values[0].(*uuid.UUID)
inValue := *values[1].(*uuid.UUID)
if nids[inValue] == nil {
nids[inValue] = map[*User]struct{}{byID[outValue]: {}}
return assign(columns[1:], values[1:])
}
nids[inValue][byID[outValue]] = struct{}{}
return nil
}
})
})
neighbors, err := withInterceptors[[]*Organization](ctx, query, qr, query.inters)
if err != nil {
return err
}
for _, n := range neighbors {
nodes, ok := nids[n.ID]
if !ok {
return fmt.Errorf(`unexpected "organizations" node returned %v`, n.ID)
}
for kn := range nodes {
assign(kn, n)
}
}
return nil
}
func (uq *UserQuery) sqlCount(ctx context.Context) (int, error) {
_spec := uq.querySpec()
_spec.Node.Columns = uq.ctx.Fields

View File

@@ -11,6 +11,8 @@ import (
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent/organization"
"github.com/holos-run/holos/internal/ent/predicate"
"github.com/holos-run/holos/internal/ent/user"
)
@@ -90,11 +92,47 @@ func (uu *UserUpdate) SetNillableName(s *string) *UserUpdate {
return uu
}
// AddOrganizationIDs adds the "organizations" edge to the Organization entity by IDs.
func (uu *UserUpdate) AddOrganizationIDs(ids ...uuid.UUID) *UserUpdate {
uu.mutation.AddOrganizationIDs(ids...)
return uu
}
// AddOrganizations adds the "organizations" edges to the Organization entity.
func (uu *UserUpdate) AddOrganizations(o ...*Organization) *UserUpdate {
ids := make([]uuid.UUID, len(o))
for i := range o {
ids[i] = o[i].ID
}
return uu.AddOrganizationIDs(ids...)
}
// Mutation returns the UserMutation object of the builder.
func (uu *UserUpdate) Mutation() *UserMutation {
return uu.mutation
}
// ClearOrganizations clears all "organizations" edges to the Organization entity.
func (uu *UserUpdate) ClearOrganizations() *UserUpdate {
uu.mutation.ClearOrganizations()
return uu
}
// RemoveOrganizationIDs removes the "organizations" edge to Organization entities by IDs.
func (uu *UserUpdate) RemoveOrganizationIDs(ids ...uuid.UUID) *UserUpdate {
uu.mutation.RemoveOrganizationIDs(ids...)
return uu
}
// RemoveOrganizations removes "organizations" edges to Organization entities.
func (uu *UserUpdate) RemoveOrganizations(o ...*Organization) *UserUpdate {
ids := make([]uuid.UUID, len(o))
for i := range o {
ids[i] = o[i].ID
}
return uu.RemoveOrganizationIDs(ids...)
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (uu *UserUpdate) Save(ctx context.Context) (int, error) {
uu.defaults()
@@ -168,6 +206,51 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
if value, ok := uu.mutation.Name(); ok {
_spec.SetField(user.FieldName, field.TypeString, value)
}
if uu.mutation.OrganizationsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: true,
Table: user.OrganizationsTable,
Columns: user.OrganizationsPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uu.mutation.RemovedOrganizationsIDs(); len(nodes) > 0 && !uu.mutation.OrganizationsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: true,
Table: user.OrganizationsTable,
Columns: user.OrganizationsPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uu.mutation.OrganizationsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: true,
Table: user.OrganizationsTable,
Columns: user.OrganizationsPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if n, err = sqlgraph.UpdateNodes(ctx, uu.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{user.Label}
@@ -250,11 +333,47 @@ func (uuo *UserUpdateOne) SetNillableName(s *string) *UserUpdateOne {
return uuo
}
// AddOrganizationIDs adds the "organizations" edge to the Organization entity by IDs.
func (uuo *UserUpdateOne) AddOrganizationIDs(ids ...uuid.UUID) *UserUpdateOne {
uuo.mutation.AddOrganizationIDs(ids...)
return uuo
}
// AddOrganizations adds the "organizations" edges to the Organization entity.
func (uuo *UserUpdateOne) AddOrganizations(o ...*Organization) *UserUpdateOne {
ids := make([]uuid.UUID, len(o))
for i := range o {
ids[i] = o[i].ID
}
return uuo.AddOrganizationIDs(ids...)
}
// Mutation returns the UserMutation object of the builder.
func (uuo *UserUpdateOne) Mutation() *UserMutation {
return uuo.mutation
}
// ClearOrganizations clears all "organizations" edges to the Organization entity.
func (uuo *UserUpdateOne) ClearOrganizations() *UserUpdateOne {
uuo.mutation.ClearOrganizations()
return uuo
}
// RemoveOrganizationIDs removes the "organizations" edge to Organization entities by IDs.
func (uuo *UserUpdateOne) RemoveOrganizationIDs(ids ...uuid.UUID) *UserUpdateOne {
uuo.mutation.RemoveOrganizationIDs(ids...)
return uuo
}
// RemoveOrganizations removes "organizations" edges to Organization entities.
func (uuo *UserUpdateOne) RemoveOrganizations(o ...*Organization) *UserUpdateOne {
ids := make([]uuid.UUID, len(o))
for i := range o {
ids[i] = o[i].ID
}
return uuo.RemoveOrganizationIDs(ids...)
}
// Where appends a list predicates to the UserUpdate builder.
func (uuo *UserUpdateOne) Where(ps ...predicate.User) *UserUpdateOne {
uuo.mutation.Where(ps...)
@@ -358,6 +477,51 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
if value, ok := uuo.mutation.Name(); ok {
_spec.SetField(user.FieldName, field.TypeString, value)
}
if uuo.mutation.OrganizationsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: true,
Table: user.OrganizationsTable,
Columns: user.OrganizationsPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uuo.mutation.RemovedOrganizationsIDs(); len(nodes) > 0 && !uuo.mutation.OrganizationsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: true,
Table: user.OrganizationsTable,
Columns: user.OrganizationsPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uuo.mutation.OrganizationsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2M,
Inverse: true,
Table: user.OrganizationsTable,
Columns: user.OrganizationsPrimaryKey,
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
_node = &User{config: uuo.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues

View File

@@ -0,0 +1,47 @@
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended",
"plugin:@angular-eslint/template/accessibility"
],
"rules": {}
}
]
}

View File

@@ -40,3 +40,6 @@ testem.log
# System files
.DS_Store
Thumbs.db
# NX?
/.nx/

View File

@@ -45,7 +45,7 @@
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
@@ -100,8 +100,22 @@
],
"scripts": []
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
}
}
},
"cli": {
"schematicCollections": [
"@angular-eslint/schematics"
]
}
}

View File

@@ -1,35 +0,0 @@
// @generated by protoc-gen-connect-query v1.3.1 with parameter "target=ts"
// @generated from file holos/v1alpha1/holos.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import { MethodKind } from "@bufbuild/protobuf";
import { GetUserClaimsRequest, GetUserClaimsResponse, RegisterUserRequest, RegisterUserResponse } from "./holos_pb.js";
/**
* @generated from rpc holos.v1alpha1.HolosService.GetUserClaims
*/
export const getUserClaims = {
localName: "getUserClaims",
name: "GetUserClaims",
kind: MethodKind.Unary,
I: GetUserClaimsRequest,
O: GetUserClaimsResponse,
service: {
typeName: "holos.v1alpha1.HolosService"
}
} as const;
/**
* @generated from rpc holos.v1alpha1.HolosService.RegisterUser
*/
export const registerUser = {
localName: "registerUser",
name: "RegisterUser",
kind: MethodKind.Unary,
I: RegisterUserRequest,
O: RegisterUserResponse,
service: {
typeName: "holos.v1alpha1.HolosService"
}
} as const;

View File

@@ -1,35 +0,0 @@
// @generated by protoc-gen-connect-es v1.4.0 with parameter "target=ts"
// @generated from file holos/v1alpha1/holos.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import { GetUserClaimsRequest, GetUserClaimsResponse, RegisterUserRequest, RegisterUserResponse } from "./holos_pb.js";
import { MethodKind } from "@bufbuild/protobuf";
/**
* @generated from service holos.v1alpha1.HolosService
*/
export const HolosService = {
typeName: "holos.v1alpha1.HolosService",
methods: {
/**
* @generated from rpc holos.v1alpha1.HolosService.GetUserClaims
*/
getUserClaims: {
name: "GetUserClaims",
I: GetUserClaimsRequest,
O: GetUserClaimsResponse,
kind: MethodKind.Unary,
},
/**
* @generated from rpc holos.v1alpha1.HolosService.RegisterUser
*/
registerUser: {
name: "RegisterUser",
I: RegisterUserRequest,
O: RegisterUserResponse,
kind: MethodKind.Unary,
},
}
} as const;

View File

@@ -1,296 +0,0 @@
// @generated by protoc-gen-es v1.8.0 with parameter "target=ts"
// @generated from file holos/v1alpha1/holos.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message, proto3, Timestamp } from "@bufbuild/protobuf";
/**
* @generated from message holos.v1alpha1.Timestamps
*/
export class Timestamps extends Message<Timestamps> {
/**
* Created at timestamp
*
* @generated from field: google.protobuf.Timestamp created_at = 1;
*/
createdAt?: Timestamp;
/**
* Updated at timestamp
*
* @generated from field: google.protobuf.Timestamp updated_at = 2;
*/
updatedAt?: Timestamp;
constructor(data?: PartialMessage<Timestamps>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.Timestamps";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "created_at", kind: "message", T: Timestamp },
{ no: 2, name: "updated_at", kind: "message", T: Timestamp },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Timestamps {
return new Timestamps().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Timestamps {
return new Timestamps().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Timestamps {
return new Timestamps().fromJsonString(jsonString, options);
}
static equals(a: Timestamps | PlainMessage<Timestamps> | undefined, b: Timestamps | PlainMessage<Timestamps> | undefined): boolean {
return proto3.util.equals(Timestamps, a, b);
}
}
/**
* Empty request, claims are pulled from the id token
*
* @generated from message holos.v1alpha1.GetUserClaimsRequest
*/
export class GetUserClaimsRequest extends Message<GetUserClaimsRequest> {
constructor(data?: PartialMessage<GetUserClaimsRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.GetUserClaimsRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetUserClaimsRequest {
return new GetUserClaimsRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetUserClaimsRequest {
return new GetUserClaimsRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetUserClaimsRequest {
return new GetUserClaimsRequest().fromJsonString(jsonString, options);
}
static equals(a: GetUserClaimsRequest | PlainMessage<GetUserClaimsRequest> | undefined, b: GetUserClaimsRequest | PlainMessage<GetUserClaimsRequest> | undefined): boolean {
return proto3.util.equals(GetUserClaimsRequest, a, b);
}
}
/**
* UserClaims represents id token claims
*
* @generated from message holos.v1alpha1.GetUserClaimsResponse
*/
export class GetUserClaimsResponse extends Message<GetUserClaimsResponse> {
/**
* @generated from field: string iss = 1;
*/
iss = "";
/**
* @generated from field: string sub = 2;
*/
sub = "";
/**
* @generated from field: string email = 3;
*/
email = "";
/**
* @generated from field: bool email_verified = 4;
*/
emailVerified = false;
/**
* @generated from field: string name = 5;
*/
name = "";
constructor(data?: PartialMessage<GetUserClaimsResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.GetUserClaimsResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "iss", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "sub", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 3, name: "email", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 4, name: "email_verified", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
{ no: 5, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetUserClaimsResponse {
return new GetUserClaimsResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetUserClaimsResponse {
return new GetUserClaimsResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetUserClaimsResponse {
return new GetUserClaimsResponse().fromJsonString(jsonString, options);
}
static equals(a: GetUserClaimsResponse | PlainMessage<GetUserClaimsResponse> | undefined, b: GetUserClaimsResponse | PlainMessage<GetUserClaimsResponse> | undefined): boolean {
return proto3.util.equals(GetUserClaimsResponse, a, b);
}
}
/**
* User represents a human user in the system. See db schema in ent/schema/user.go
*
* @generated from message holos.v1alpha1.User
*/
export class User extends Message<User> {
/**
* Unique id assigned by the server.
*
* @generated from field: string id = 1;
*/
id = "";
/**
* @generated from field: string email = 2;
*/
email = "";
/**
* @generated from field: bool email_verified = 3;
*/
emailVerified = false;
/**
* @generated from field: string name = 4;
*/
name = "";
/**
* @generated from field: holos.v1alpha1.Timestamps timestamps = 5;
*/
timestamps?: Timestamps;
constructor(data?: PartialMessage<User>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.User";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "email", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 3, name: "email_verified", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
{ no: 4, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 5, name: "timestamps", kind: "message", T: Timestamps },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): User {
return new User().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): User {
return new User().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): User {
return new User().fromJsonString(jsonString, options);
}
static equals(a: User | PlainMessage<User> | undefined, b: User | PlainMessage<User> | undefined): boolean {
return proto3.util.equals(User, a, b);
}
}
/**
* @generated from message holos.v1alpha1.RegisterUserRequest
*/
export class RegisterUserRequest extends Message<RegisterUserRequest> {
/**
* @generated from field: optional string name = 1;
*/
name?: string;
constructor(data?: PartialMessage<RegisterUserRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.RegisterUserRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): RegisterUserRequest {
return new RegisterUserRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): RegisterUserRequest {
return new RegisterUserRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): RegisterUserRequest {
return new RegisterUserRequest().fromJsonString(jsonString, options);
}
static equals(a: RegisterUserRequest | PlainMessage<RegisterUserRequest> | undefined, b: RegisterUserRequest | PlainMessage<RegisterUserRequest> | undefined): boolean {
return proto3.util.equals(RegisterUserRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.RegisterUserResponse
*/
export class RegisterUserResponse extends Message<RegisterUserResponse> {
/**
* @generated from field: holos.v1alpha1.User user = 1;
*/
user?: User;
/**
* @generated from field: bool already_exists = 2;
*/
alreadyExists = false;
constructor(data?: PartialMessage<RegisterUserResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.RegisterUserResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "user", kind: "message", T: User },
{ no: 2, name: "already_exists", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): RegisterUserResponse {
return new RegisterUserResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): RegisterUserResponse {
return new RegisterUserResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): RegisterUserResponse {
return new RegisterUserResponse().fromJsonString(jsonString, options);
}
static equals(a: RegisterUserResponse | PlainMessage<RegisterUserResponse> | undefined, b: RegisterUserResponse | PlainMessage<RegisterUserResponse> | undefined): boolean {
return proto3.util.equals(RegisterUserResponse, a, b);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,8 @@
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
"test": "ng test",
"lint": "ng lint"
},
"private": true,
"dependencies": {
@@ -20,23 +21,34 @@
"@angular/platform-browser": "^17.3.0",
"@angular/platform-browser-dynamic": "^17.3.0",
"@angular/router": "^17.3.0",
"@bufbuild/protobuf": "^1.8.0",
"@bufbuild/protobuf": "^1.9.0",
"@connectrpc/connect": "^1.4.0",
"@connectrpc/connect-query": "^1.3.1",
"@connectrpc/connect-web": "^1.4.0",
"@ngx-formly/core": "^6.3.0",
"@ngx-formly/material": "^6.3.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.3.4",
"@angular-eslint/builder": "17.3.0",
"@angular-eslint/eslint-plugin": "17.3.0",
"@angular-eslint/eslint-plugin-template": "17.3.0",
"@angular-eslint/schematics": "17.3.0",
"@angular-eslint/template-parser": "17.3.0",
"@angular/cli": "^17.3.4",
"@angular/compiler-cli": "^17.3.0",
"@bufbuild/buf": "^1.30.1",
"@bufbuild/protoc-gen-es": "^1.8.0",
"@bufbuild/buf": "^1.31.0",
"@bufbuild/protoc-gen-es": "^1.9.0",
"@connectrpc/protoc-gen-connect-es": "^1.4.0",
"@connectrpc/protoc-gen-connect-query": "^1.3.1",
"@ngx-formly/schematics": "^6.3.0",
"@types/jasmine": "~5.1.0",
"@typescript-eslint/eslint-plugin": "7.2.0",
"@typescript-eslint/parser": "7.2.0",
"eslint": "^8.57.0",
"jasmine-core": "~5.1.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0",

View File

@@ -1,9 +1,31 @@
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { FormlyModule } from '@ngx-formly/core';
// import { provideHttpClient, withFetch } from '@angular/common/http';
import { routes } from './app.routes';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { ConnectModule } from '../connect/connect.module';
import { provideClient } from "../connect/client.provider";
import { UserService } from './gen/holos/v1alpha1/user_connect';
import { OrganizationService } from './gen/holos/v1alpha1/organization_connect';
import { PlatformService } from './gen/holos/v1alpha1/platform_connect';
import { HolosPanelWrapperComponent } from '../wrappers/holos-panel-wrapper/holos-panel-wrapper.component';
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideAnimationsAsync()]
providers: [
provideRouter(routes, withComponentInputBinding()),
provideAnimationsAsync(),
// provideHttpClient(withFetch()),
provideClient(UserService),
provideClient(OrganizationService),
provideClient(PlatformService),
importProvidersFrom(
ConnectModule.forRoot({
baseUrl: window.location.origin
}),
FormlyModule.forRoot({
wrappers: [{ name: 'holos-panel', component: HolosPanelWrapperComponent }],
}),
),
]
};

View File

@@ -1,11 +1,13 @@
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { ClusterListComponent } from './cluster-list/cluster-list.component';
import { ErrorNotFoundComponent } from './error-not-found/error-not-found.component';
import { PlatformsComponent } from './views/platforms/platforms.component'
import { PlatformDetailComponent } from './views/platform-detail/platform-detail.component';
export const routes: Routes = [
{ path: 'platform/:id', component: PlatformDetailComponent },
{ path: 'platforms', component: PlatformsComponent },
{ path: 'home', component: HomeComponent },
{ path: 'clusters', component: ClusterListComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '', redirectTo: '/platforms', pathMatch: 'full' },
{ path: '**', component: ErrorNotFoundComponent },
];

View File

@@ -1,26 +0,0 @@
<div class="grid-container">
<h1 class="mat-h1">Clusters</h1>
<mat-grid-list cols="2" rowHeight="350px">
@for (card of cards | async; track card) {
<mat-grid-tile [colspan]="card.cols" [rowspan]="card.rows">
<mat-card class="dashboard-card">
<mat-card-header>
<mat-card-title>
{{card.title}}
<button mat-icon-button class="more-button" [matMenuTriggerFor]="menu" aria-label="Toggle menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu" xPosition="before">
<button mat-menu-item>Expand</button>
<button mat-menu-item>Remove</button>
</mat-menu>
</mat-card-title>
</mat-card-header>
<mat-card-content class="dashboard-card-content">
<div>Card Content Here</div>
</mat-card-content>
</mat-card>
</mat-grid-tile>
}
</mat-grid-list>
</div>

View File

@@ -1,21 +0,0 @@
.grid-container {
margin: 20px;
}
.dashboard-card {
position: absolute;
top: 15px;
left: 15px;
right: 15px;
bottom: 15px;
}
.more-button {
position: absolute;
top: 5px;
right: 10px;
}
.dashboard-card-content {
text-align: center;
}

View File

@@ -1,25 +0,0 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ClusterListComponent } from './cluster-list.component';
describe('ClusterListComponent', () => {
let component: ClusterListComponent;
let fixture: ComponentFixture<ClusterListComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ClusterListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should compile', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,48 +0,0 @@
import { Component, inject } from '@angular/core';
import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout';
import { map } from 'rxjs/operators';
import { AsyncPipe } from '@angular/common';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatMenuModule } from '@angular/material/menu';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
@Component({
selector: 'app-cluster-list',
templateUrl: './cluster-list.component.html',
styleUrl: './cluster-list.component.scss',
standalone: true,
imports: [
AsyncPipe,
MatGridListModule,
MatMenuModule,
MatIconModule,
MatButtonModule,
MatCardModule
]
})
export class ClusterListComponent {
private breakpointObserver = inject(BreakpointObserver);
/** Based on the screen size, switch from standard to one column per row */
cards = this.breakpointObserver.observe(Breakpoints.Handset).pipe(
map(({ matches }) => {
if (matches) {
return [
{ title: 'Card 1', cols: 1, rows: 1 },
{ title: 'Card 2', cols: 1, rows: 1 },
{ title: 'Card 3', cols: 1, rows: 1 },
{ title: 'Card 4', cols: 1, rows: 1 }
];
}
return [
{ title: 'Card 1', cols: 2, rows: 1 },
{ title: 'Card 2', cols: 1, rows: 1 },
{ title: 'Card 3', cols: 1, rows: 2 },
{ title: 'Card 4', cols: 1, rows: 1 }
];
})
);
}

View File

@@ -0,0 +1,35 @@
// @generated by protoc-gen-connect-es v1.4.0 with parameter "target=ts"
// @generated from file holos/v1alpha1/organization.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import { CreateCallerOrganizationRequest, CreateCallerOrganizationResponse, ListCallerOrganizationsRequest, ListCallerOrganizationsResponse } from "./organization_pb.js";
import { MethodKind } from "@bufbuild/protobuf";
/**
* @generated from service holos.v1alpha1.OrganizationService
*/
export const OrganizationService = {
typeName: "holos.v1alpha1.OrganizationService",
methods: {
/**
* @generated from rpc holos.v1alpha1.OrganizationService.ListCallerOrganizations
*/
listCallerOrganizations: {
name: "ListCallerOrganizations",
I: ListCallerOrganizationsRequest,
O: ListCallerOrganizationsResponse,
kind: MethodKind.Unary,
},
/**
* @generated from rpc holos.v1alpha1.OrganizationService.CreateCallerOrganization
*/
createCallerOrganization: {
name: "CreateCallerOrganization",
I: CreateCallerOrganizationRequest,
O: CreateCallerOrganizationResponse,
kind: MethodKind.Unary,
},
}
} as const;

View File

@@ -0,0 +1,221 @@
// @generated by protoc-gen-es v1.9.0 with parameter "target=ts"
// @generated from file holos/v1alpha1/organization.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message, proto3 } from "@bufbuild/protobuf";
import { Timestamps } from "./timestamps_pb.js";
import { Creator, User } from "./user_pb.js";
/**
* @generated from message holos.v1alpha1.Organization
*/
export class Organization extends Message<Organization> {
/**
* Unique id assigned by the server.
*
* @generated from field: string id = 1;
*/
id = "";
/**
* @generated from field: string name = 2;
*/
name = "";
/**
* @generated from field: string display_name = 3;
*/
displayName = "";
/**
* @generated from field: holos.v1alpha1.Timestamps timestamps = 4;
*/
timestamps?: Timestamps;
/**
* @generated from field: holos.v1alpha1.Creator creator = 5;
*/
creator?: Creator;
constructor(data?: PartialMessage<Organization>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.Organization";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 3, name: "display_name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 4, name: "timestamps", kind: "message", T: Timestamps },
{ no: 5, name: "creator", kind: "message", T: Creator },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Organization {
return new Organization().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Organization {
return new Organization().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Organization {
return new Organization().fromJsonString(jsonString, options);
}
static equals(a: Organization | PlainMessage<Organization> | undefined, b: Organization | PlainMessage<Organization> | undefined): boolean {
return proto3.util.equals(Organization, a, b);
}
}
/**
* @generated from message holos.v1alpha1.ListCallerOrganizationsRequest
*/
export class ListCallerOrganizationsRequest extends Message<ListCallerOrganizationsRequest> {
constructor(data?: PartialMessage<ListCallerOrganizationsRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.ListCallerOrganizationsRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListCallerOrganizationsRequest {
return new ListCallerOrganizationsRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListCallerOrganizationsRequest {
return new ListCallerOrganizationsRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListCallerOrganizationsRequest {
return new ListCallerOrganizationsRequest().fromJsonString(jsonString, options);
}
static equals(a: ListCallerOrganizationsRequest | PlainMessage<ListCallerOrganizationsRequest> | undefined, b: ListCallerOrganizationsRequest | PlainMessage<ListCallerOrganizationsRequest> | undefined): boolean {
return proto3.util.equals(ListCallerOrganizationsRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.ListCallerOrganizationsResponse
*/
export class ListCallerOrganizationsResponse extends Message<ListCallerOrganizationsResponse> {
/**
* @generated from field: holos.v1alpha1.User user = 1;
*/
user?: User;
/**
* @generated from field: repeated holos.v1alpha1.Organization organizations = 2;
*/
organizations: Organization[] = [];
constructor(data?: PartialMessage<ListCallerOrganizationsResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.ListCallerOrganizationsResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "user", kind: "message", T: User },
{ no: 2, name: "organizations", kind: "message", T: Organization, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListCallerOrganizationsResponse {
return new ListCallerOrganizationsResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListCallerOrganizationsResponse {
return new ListCallerOrganizationsResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListCallerOrganizationsResponse {
return new ListCallerOrganizationsResponse().fromJsonString(jsonString, options);
}
static equals(a: ListCallerOrganizationsResponse | PlainMessage<ListCallerOrganizationsResponse> | undefined, b: ListCallerOrganizationsResponse | PlainMessage<ListCallerOrganizationsResponse> | undefined): boolean {
return proto3.util.equals(ListCallerOrganizationsResponse, a, b);
}
}
/**
* @generated from message holos.v1alpha1.CreateCallerOrganizationRequest
*/
export class CreateCallerOrganizationRequest extends Message<CreateCallerOrganizationRequest> {
constructor(data?: PartialMessage<CreateCallerOrganizationRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.CreateCallerOrganizationRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateCallerOrganizationRequest {
return new CreateCallerOrganizationRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateCallerOrganizationRequest {
return new CreateCallerOrganizationRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateCallerOrganizationRequest {
return new CreateCallerOrganizationRequest().fromJsonString(jsonString, options);
}
static equals(a: CreateCallerOrganizationRequest | PlainMessage<CreateCallerOrganizationRequest> | undefined, b: CreateCallerOrganizationRequest | PlainMessage<CreateCallerOrganizationRequest> | undefined): boolean {
return proto3.util.equals(CreateCallerOrganizationRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.CreateCallerOrganizationResponse
*/
export class CreateCallerOrganizationResponse extends Message<CreateCallerOrganizationResponse> {
/**
* @generated from field: holos.v1alpha1.User user = 1;
*/
user?: User;
/**
* @generated from field: repeated holos.v1alpha1.Organization organizations = 2;
*/
organizations: Organization[] = [];
constructor(data?: PartialMessage<CreateCallerOrganizationResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.CreateCallerOrganizationResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "user", kind: "message", T: User },
{ no: 2, name: "organizations", kind: "message", T: Organization, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateCallerOrganizationResponse {
return new CreateCallerOrganizationResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateCallerOrganizationResponse {
return new CreateCallerOrganizationResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateCallerOrganizationResponse {
return new CreateCallerOrganizationResponse().fromJsonString(jsonString, options);
}
static equals(a: CreateCallerOrganizationResponse | PlainMessage<CreateCallerOrganizationResponse> | undefined, b: CreateCallerOrganizationResponse | PlainMessage<CreateCallerOrganizationResponse> | undefined): boolean {
return proto3.util.equals(CreateCallerOrganizationResponse, a, b);
}
}

View File

@@ -0,0 +1,80 @@
// @generated by protoc-gen-connect-es v1.4.0 with parameter "target=ts"
// @generated from file holos/v1alpha1/platform.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import { AddPlatformRequest, AddPlatformResponse, GetFormRequest, GetFormResponse, GetModelRequest, GetModelResponse, GetPlatformRequest, GetPlatformResponse, ListPlatformsRequest, ListPlatformsResponse, PutFormRequest, PutFormResponse, PutModelRequest, PutModelResponse } from "./platform_pb.js";
import { MethodKind } from "@bufbuild/protobuf";
/**
* @generated from service holos.v1alpha1.PlatformService
*/
export const PlatformService = {
typeName: "holos.v1alpha1.PlatformService",
methods: {
/**
* @generated from rpc holos.v1alpha1.PlatformService.AddPlatform
*/
addPlatform: {
name: "AddPlatform",
I: AddPlatformRequest,
O: AddPlatformResponse,
kind: MethodKind.Unary,
},
/**
* @generated from rpc holos.v1alpha1.PlatformService.GetPlatform
*/
getPlatform: {
name: "GetPlatform",
I: GetPlatformRequest,
O: GetPlatformResponse,
kind: MethodKind.Unary,
},
/**
* @generated from rpc holos.v1alpha1.PlatformService.ListPlatforms
*/
listPlatforms: {
name: "ListPlatforms",
I: ListPlatformsRequest,
O: ListPlatformsResponse,
kind: MethodKind.Unary,
},
/**
* @generated from rpc holos.v1alpha1.PlatformService.GetForm
*/
getForm: {
name: "GetForm",
I: GetFormRequest,
O: GetFormResponse,
kind: MethodKind.Unary,
},
/**
* @generated from rpc holos.v1alpha1.PlatformService.PutForm
*/
putForm: {
name: "PutForm",
I: PutFormRequest,
O: PutFormResponse,
kind: MethodKind.Unary,
},
/**
* @generated from rpc holos.v1alpha1.PlatformService.GetModel
*/
getModel: {
name: "GetModel",
I: GetModelRequest,
O: GetModelResponse,
kind: MethodKind.Unary,
},
/**
* @generated from rpc holos.v1alpha1.PlatformService.PutModel
*/
putModel: {
name: "PutModel",
I: PutModelRequest,
O: PutModelResponse,
kind: MethodKind.Unary,
},
}
} as const;

View File

@@ -0,0 +1,732 @@
// @generated by protoc-gen-es v1.9.0 with parameter "target=ts"
// @generated from file holos/v1alpha1/platform.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message, proto3, Struct } from "@bufbuild/protobuf";
/**
* @generated from message holos.v1alpha1.Platform
*/
export class Platform extends Message<Platform> {
/**
* Unique id assigned by the server.
*
* @generated from field: string id = 1;
*/
id = "";
/**
* Organization ID resource owner.
*
* @generated from field: string org_id = 2;
*/
orgId = "";
/**
* name is the platform short name as a dns label.
*
* @generated from field: string name = 3;
*/
name = "";
/**
* @generated from field: string display_name = 4;
*/
displayName = "";
/**
* @generated from field: holos.v1alpha1.PlatformSpec spec = 5;
*/
spec?: PlatformSpec;
constructor(data?: PartialMessage<Platform>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.Platform";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "org_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 3, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 4, name: "display_name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 5, name: "spec", kind: "message", T: PlatformSpec },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Platform {
return new Platform().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Platform {
return new Platform().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Platform {
return new Platform().fromJsonString(jsonString, options);
}
static equals(a: Platform | PlainMessage<Platform> | undefined, b: Platform | PlainMessage<Platform> | undefined): boolean {
return proto3.util.equals(Platform, a, b);
}
}
/**
* @generated from message holos.v1alpha1.PlatformSpec
*/
export class PlatformSpec extends Message<PlatformSpec> {
/**
* model represents the user-defined and user-supplied form field values.
*
* @generated from field: google.protobuf.Struct model = 1;
*/
model?: Struct;
constructor(data?: PartialMessage<PlatformSpec>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.PlatformSpec";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "model", kind: "message", T: Struct },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PlatformSpec {
return new PlatformSpec().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PlatformSpec {
return new PlatformSpec().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PlatformSpec {
return new PlatformSpec().fromJsonString(jsonString, options);
}
static equals(a: PlatformSpec | PlainMessage<PlatformSpec> | undefined, b: PlatformSpec | PlainMessage<PlatformSpec> | undefined): boolean {
return proto3.util.equals(PlatformSpec, a, b);
}
}
/**
* Form represents the Formly input form.
*
* @generated from message holos.v1alpha1.Form
*/
export class Form extends Message<Form> {
/**
* fields represents FormlyFieldConfig[] encoded as a JSON array.
*
* @generated from field: repeated google.protobuf.Struct fields = 1;
*/
fields: Struct[] = [];
constructor(data?: PartialMessage<Form>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.Form";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "fields", kind: "message", T: Struct, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Form {
return new Form().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Form {
return new Form().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Form {
return new Form().fromJsonString(jsonString, options);
}
static equals(a: Form | PlainMessage<Form> | undefined, b: Form | PlainMessage<Form> | undefined): boolean {
return proto3.util.equals(Form, a, b);
}
}
/**
* Model represents the values entered into the form, stored in the form's model
* in the web app, and persisted into the backend database. The model is
* ultimately intended as the input to platform rendering.
*
* @generated from message holos.v1alpha1.Model
*/
export class Model extends Message<Model> {
/**
* @generated from field: google.protobuf.Struct model = 1;
*/
model?: Struct;
constructor(data?: PartialMessage<Model>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.Model";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "model", kind: "message", T: Struct },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Model {
return new Model().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Model {
return new Model().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Model {
return new Model().fromJsonString(jsonString, options);
}
static equals(a: Model | PlainMessage<Model> | undefined, b: Model | PlainMessage<Model> | undefined): boolean {
return proto3.util.equals(Model, a, b);
}
}
/**
* @generated from message holos.v1alpha1.ListPlatformsRequest
*/
export class ListPlatformsRequest extends Message<ListPlatformsRequest> {
/**
* @generated from field: string org_id = 1;
*/
orgId = "";
constructor(data?: PartialMessage<ListPlatformsRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.ListPlatformsRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "org_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListPlatformsRequest {
return new ListPlatformsRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListPlatformsRequest {
return new ListPlatformsRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListPlatformsRequest {
return new ListPlatformsRequest().fromJsonString(jsonString, options);
}
static equals(a: ListPlatformsRequest | PlainMessage<ListPlatformsRequest> | undefined, b: ListPlatformsRequest | PlainMessage<ListPlatformsRequest> | undefined): boolean {
return proto3.util.equals(ListPlatformsRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.ListPlatformsResponse
*/
export class ListPlatformsResponse extends Message<ListPlatformsResponse> {
/**
* @generated from field: repeated holos.v1alpha1.Platform platforms = 1;
*/
platforms: Platform[] = [];
constructor(data?: PartialMessage<ListPlatformsResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.ListPlatformsResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "platforms", kind: "message", T: Platform, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListPlatformsResponse {
return new ListPlatformsResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListPlatformsResponse {
return new ListPlatformsResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListPlatformsResponse {
return new ListPlatformsResponse().fromJsonString(jsonString, options);
}
static equals(a: ListPlatformsResponse | PlainMessage<ListPlatformsResponse> | undefined, b: ListPlatformsResponse | PlainMessage<ListPlatformsResponse> | undefined): boolean {
return proto3.util.equals(ListPlatformsResponse, a, b);
}
}
/**
* @generated from message holos.v1alpha1.AddPlatformRequest
*/
export class AddPlatformRequest extends Message<AddPlatformRequest> {
/**
* @generated from field: holos.v1alpha1.Platform platform = 1;
*/
platform?: Platform;
constructor(data?: PartialMessage<AddPlatformRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.AddPlatformRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "platform", kind: "message", T: Platform },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): AddPlatformRequest {
return new AddPlatformRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): AddPlatformRequest {
return new AddPlatformRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): AddPlatformRequest {
return new AddPlatformRequest().fromJsonString(jsonString, options);
}
static equals(a: AddPlatformRequest | PlainMessage<AddPlatformRequest> | undefined, b: AddPlatformRequest | PlainMessage<AddPlatformRequest> | undefined): boolean {
return proto3.util.equals(AddPlatformRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.AddPlatformResponse
*/
export class AddPlatformResponse extends Message<AddPlatformResponse> {
/**
* @generated from field: repeated holos.v1alpha1.Platform platforms = 1;
*/
platforms: Platform[] = [];
constructor(data?: PartialMessage<AddPlatformResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.AddPlatformResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "platforms", kind: "message", T: Platform, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): AddPlatformResponse {
return new AddPlatformResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): AddPlatformResponse {
return new AddPlatformResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): AddPlatformResponse {
return new AddPlatformResponse().fromJsonString(jsonString, options);
}
static equals(a: AddPlatformResponse | PlainMessage<AddPlatformResponse> | undefined, b: AddPlatformResponse | PlainMessage<AddPlatformResponse> | undefined): boolean {
return proto3.util.equals(AddPlatformResponse, a, b);
}
}
/**
* @generated from message holos.v1alpha1.GetPlatformRequest
*/
export class GetPlatformRequest extends Message<GetPlatformRequest> {
/**
* @generated from field: string platform_id = 1;
*/
platformId = "";
constructor(data?: PartialMessage<GetPlatformRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.GetPlatformRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetPlatformRequest {
return new GetPlatformRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetPlatformRequest {
return new GetPlatformRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetPlatformRequest {
return new GetPlatformRequest().fromJsonString(jsonString, options);
}
static equals(a: GetPlatformRequest | PlainMessage<GetPlatformRequest> | undefined, b: GetPlatformRequest | PlainMessage<GetPlatformRequest> | undefined): boolean {
return proto3.util.equals(GetPlatformRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.GetPlatformResponse
*/
export class GetPlatformResponse extends Message<GetPlatformResponse> {
/**
* @generated from field: holos.v1alpha1.Platform platform = 1;
*/
platform?: Platform;
constructor(data?: PartialMessage<GetPlatformResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.GetPlatformResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "platform", kind: "message", T: Platform },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetPlatformResponse {
return new GetPlatformResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetPlatformResponse {
return new GetPlatformResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetPlatformResponse {
return new GetPlatformResponse().fromJsonString(jsonString, options);
}
static equals(a: GetPlatformResponse | PlainMessage<GetPlatformResponse> | undefined, b: GetPlatformResponse | PlainMessage<GetPlatformResponse> | undefined): boolean {
return proto3.util.equals(GetPlatformResponse, a, b);
}
}
/**
* @generated from message holos.v1alpha1.GetFormRequest
*/
export class GetFormRequest extends Message<GetFormRequest> {
/**
* @generated from field: string platform_id = 1;
*/
platformId = "";
constructor(data?: PartialMessage<GetFormRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.GetFormRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetFormRequest {
return new GetFormRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetFormRequest {
return new GetFormRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetFormRequest {
return new GetFormRequest().fromJsonString(jsonString, options);
}
static equals(a: GetFormRequest | PlainMessage<GetFormRequest> | undefined, b: GetFormRequest | PlainMessage<GetFormRequest> | undefined): boolean {
return proto3.util.equals(GetFormRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.GetFormResponse
*/
export class GetFormResponse extends Message<GetFormResponse> {
/**
* @generated from field: repeated google.protobuf.Struct fields = 1;
*/
fields: Struct[] = [];
/**
* @generated from field: google.protobuf.Struct model = 2;
*/
model?: Struct;
constructor(data?: PartialMessage<GetFormResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.GetFormResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "fields", kind: "message", T: Struct, repeated: true },
{ no: 2, name: "model", kind: "message", T: Struct },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetFormResponse {
return new GetFormResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetFormResponse {
return new GetFormResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetFormResponse {
return new GetFormResponse().fromJsonString(jsonString, options);
}
static equals(a: GetFormResponse | PlainMessage<GetFormResponse> | undefined, b: GetFormResponse | PlainMessage<GetFormResponse> | undefined): boolean {
return proto3.util.equals(GetFormResponse, a, b);
}
}
/**
* @generated from message holos.v1alpha1.GetModelRequest
*/
export class GetModelRequest extends Message<GetModelRequest> {
/**
* @generated from field: string platform_id = 1;
*/
platformId = "";
constructor(data?: PartialMessage<GetModelRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.GetModelRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetModelRequest {
return new GetModelRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetModelRequest {
return new GetModelRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetModelRequest {
return new GetModelRequest().fromJsonString(jsonString, options);
}
static equals(a: GetModelRequest | PlainMessage<GetModelRequest> | undefined, b: GetModelRequest | PlainMessage<GetModelRequest> | undefined): boolean {
return proto3.util.equals(GetModelRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.GetModelResponse
*/
export class GetModelResponse extends Message<GetModelResponse> {
/**
* @generated from field: google.protobuf.Struct model = 1;
*/
model?: Struct;
constructor(data?: PartialMessage<GetModelResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.GetModelResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "model", kind: "message", T: Struct },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetModelResponse {
return new GetModelResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetModelResponse {
return new GetModelResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetModelResponse {
return new GetModelResponse().fromJsonString(jsonString, options);
}
static equals(a: GetModelResponse | PlainMessage<GetModelResponse> | undefined, b: GetModelResponse | PlainMessage<GetModelResponse> | undefined): boolean {
return proto3.util.equals(GetModelResponse, a, b);
}
}
/**
* @generated from message holos.v1alpha1.PutModelRequest
*/
export class PutModelRequest extends Message<PutModelRequest> {
/**
* @generated from field: string platform_id = 1;
*/
platformId = "";
/**
* @generated from field: google.protobuf.Struct model = 2;
*/
model?: Struct;
constructor(data?: PartialMessage<PutModelRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.PutModelRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "model", kind: "message", T: Struct },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PutModelRequest {
return new PutModelRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PutModelRequest {
return new PutModelRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PutModelRequest {
return new PutModelRequest().fromJsonString(jsonString, options);
}
static equals(a: PutModelRequest | PlainMessage<PutModelRequest> | undefined, b: PutModelRequest | PlainMessage<PutModelRequest> | undefined): boolean {
return proto3.util.equals(PutModelRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.PutModelResponse
*/
export class PutModelResponse extends Message<PutModelResponse> {
/**
* @generated from field: google.protobuf.Struct model = 1;
*/
model?: Struct;
constructor(data?: PartialMessage<PutModelResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.PutModelResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "model", kind: "message", T: Struct },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PutModelResponse {
return new PutModelResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PutModelResponse {
return new PutModelResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PutModelResponse {
return new PutModelResponse().fromJsonString(jsonString, options);
}
static equals(a: PutModelResponse | PlainMessage<PutModelResponse> | undefined, b: PutModelResponse | PlainMessage<PutModelResponse> | undefined): boolean {
return proto3.util.equals(PutModelResponse, a, b);
}
}
/**
* @generated from message holos.v1alpha1.PutFormRequest
*/
export class PutFormRequest extends Message<PutFormRequest> {
/**
* @generated from field: string platform_id = 1;
*/
platformId = "";
/**
* @generated from field: repeated google.protobuf.Struct fields = 2;
*/
fields: Struct[] = [];
constructor(data?: PartialMessage<PutFormRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.PutFormRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "fields", kind: "message", T: Struct, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PutFormRequest {
return new PutFormRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PutFormRequest {
return new PutFormRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PutFormRequest {
return new PutFormRequest().fromJsonString(jsonString, options);
}
static equals(a: PutFormRequest | PlainMessage<PutFormRequest> | undefined, b: PutFormRequest | PlainMessage<PutFormRequest> | undefined): boolean {
return proto3.util.equals(PutFormRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.PutFormResponse
*/
export class PutFormResponse extends Message<PutFormResponse> {
/**
* @generated from field: repeated google.protobuf.Struct fields = 1;
*/
fields: Struct[] = [];
constructor(data?: PartialMessage<PutFormResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.PutFormResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "fields", kind: "message", T: Struct, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PutFormResponse {
return new PutFormResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PutFormResponse {
return new PutFormResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PutFormResponse {
return new PutFormResponse().fromJsonString(jsonString, options);
}
static equals(a: PutFormResponse | PlainMessage<PutFormResponse> | undefined, b: PutFormResponse | PlainMessage<PutFormResponse> | undefined): boolean {
return proto3.util.equals(PutFormResponse, a, b);
}
}

View File

@@ -0,0 +1,35 @@
// @generated by protoc-gen-connect-es v1.4.0 with parameter "target=ts"
// @generated from file holos/v1alpha1/system.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import { DropTablesRequest, DropTablesResponse, SeedDatabaseRequest, SeedDatabaseResponse } from "./system_pb.js";
import { MethodKind } from "@bufbuild/protobuf";
/**
* @generated from service holos.v1alpha1.SystemService
*/
export const SystemService = {
typeName: "holos.v1alpha1.SystemService",
methods: {
/**
* @generated from rpc holos.v1alpha1.SystemService.SeedDatabase
*/
seedDatabase: {
name: "SeedDatabase",
I: SeedDatabaseRequest,
O: SeedDatabaseResponse,
kind: MethodKind.Unary,
},
/**
* @generated from rpc holos.v1alpha1.SystemService.DropTables
*/
dropTables: {
name: "DropTables",
I: DropTablesRequest,
O: DropTablesResponse,
kind: MethodKind.Unary,
},
}
} as const;

View File

@@ -0,0 +1,132 @@
// @generated by protoc-gen-es v1.9.0 with parameter "target=ts"
// @generated from file holos/v1alpha1/system.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message, proto3 } from "@bufbuild/protobuf";
/**
* @generated from message holos.v1alpha1.SeedDatabaseRequest
*/
export class SeedDatabaseRequest extends Message<SeedDatabaseRequest> {
constructor(data?: PartialMessage<SeedDatabaseRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.SeedDatabaseRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): SeedDatabaseRequest {
return new SeedDatabaseRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): SeedDatabaseRequest {
return new SeedDatabaseRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): SeedDatabaseRequest {
return new SeedDatabaseRequest().fromJsonString(jsonString, options);
}
static equals(a: SeedDatabaseRequest | PlainMessage<SeedDatabaseRequest> | undefined, b: SeedDatabaseRequest | PlainMessage<SeedDatabaseRequest> | undefined): boolean {
return proto3.util.equals(SeedDatabaseRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.SeedDatabaseResponse
*/
export class SeedDatabaseResponse extends Message<SeedDatabaseResponse> {
constructor(data?: PartialMessage<SeedDatabaseResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.SeedDatabaseResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): SeedDatabaseResponse {
return new SeedDatabaseResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): SeedDatabaseResponse {
return new SeedDatabaseResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): SeedDatabaseResponse {
return new SeedDatabaseResponse().fromJsonString(jsonString, options);
}
static equals(a: SeedDatabaseResponse | PlainMessage<SeedDatabaseResponse> | undefined, b: SeedDatabaseResponse | PlainMessage<SeedDatabaseResponse> | undefined): boolean {
return proto3.util.equals(SeedDatabaseResponse, a, b);
}
}
/**
* @generated from message holos.v1alpha1.DropTablesRequest
*/
export class DropTablesRequest extends Message<DropTablesRequest> {
constructor(data?: PartialMessage<DropTablesRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.DropTablesRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DropTablesRequest {
return new DropTablesRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DropTablesRequest {
return new DropTablesRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DropTablesRequest {
return new DropTablesRequest().fromJsonString(jsonString, options);
}
static equals(a: DropTablesRequest | PlainMessage<DropTablesRequest> | undefined, b: DropTablesRequest | PlainMessage<DropTablesRequest> | undefined): boolean {
return proto3.util.equals(DropTablesRequest, a, b);
}
}
/**
* @generated from message holos.v1alpha1.DropTablesResponse
*/
export class DropTablesResponse extends Message<DropTablesResponse> {
constructor(data?: PartialMessage<DropTablesResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.DropTablesResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DropTablesResponse {
return new DropTablesResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DropTablesResponse {
return new DropTablesResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DropTablesResponse {
return new DropTablesResponse().fromJsonString(jsonString, options);
}
static equals(a: DropTablesResponse | PlainMessage<DropTablesResponse> | undefined, b: DropTablesResponse | PlainMessage<DropTablesResponse> | undefined): boolean {
return proto3.util.equals(DropTablesResponse, a, b);
}
}

View File

@@ -0,0 +1,55 @@
// @generated by protoc-gen-es v1.9.0 with parameter "target=ts"
// @generated from file holos/v1alpha1/timestamps.proto (package holos.v1alpha1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message, proto3, Timestamp } from "@bufbuild/protobuf";
/**
* @generated from message holos.v1alpha1.Timestamps
*/
export class Timestamps extends Message<Timestamps> {
/**
* Created at timestamp
*
* @generated from field: google.protobuf.Timestamp created_at = 1;
*/
createdAt?: Timestamp;
/**
* Updated at timestamp
*
* @generated from field: google.protobuf.Timestamp updated_at = 2;
*/
updatedAt?: Timestamp;
constructor(data?: PartialMessage<Timestamps>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "holos.v1alpha1.Timestamps";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "created_at", kind: "message", T: Timestamp },
{ no: 2, name: "updated_at", kind: "message", T: Timestamp },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Timestamps {
return new Timestamps().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Timestamps {
return new Timestamps().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Timestamps {
return new Timestamps().fromJsonString(jsonString, options);
}
static equals(a: Timestamps | PlainMessage<Timestamps> | undefined, b: Timestamps | PlainMessage<Timestamps> | undefined): boolean {
return proto3.util.equals(Timestamps, a, b);
}
}

Some files were not shown because too many files have changed in this diff Show More