From 3007199d9260e5f7b09859fc5be7e9b4bcb41172 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 20 Jun 2024 20:22:33 +0530 Subject: [PATCH 1/9] feat(console): allows deletion of archived ENVs --- apps/console/internal/app/gqlgen.yml | 2 +- .../internal/app/graph/generated/generated.go | 77 +++++-------------- .../app/graph/matchfilter.resolvers.go | 55 ------------- .../internal/app/graph/model/models_gen.go | 45 ----------- .../internal/app/graph/schema.resolvers.go | 1 + apps/console/internal/domain/environment.go | 4 + 6 files changed, 27 insertions(+), 157 deletions(-) delete mode 100644 apps/console/internal/app/graph/matchfilter.resolvers.go diff --git a/apps/console/internal/app/gqlgen.yml b/apps/console/internal/app/gqlgen.yml index e7e61a474..6efaeff16 100644 --- a/apps/console/internal/app/gqlgen.yml +++ b/apps/console/internal/app/gqlgen.yml @@ -171,7 +171,7 @@ models: model: github.com/kloudlite/api/pkg/repos.MatchFilter MatchFilterIn: *match-filter-model - MatchFilterMatchType: + Github__com___kloudlite___api___pkg___repos__MatchType: model: github.com/kloudlite/api/pkg/repos.MatchType CursorPagination: &cursor-pagination-model diff --git a/apps/console/internal/app/graph/generated/generated.go b/apps/console/internal/app/graph/generated/generated.go index 6182ca581..a20617e0d 100644 --- a/apps/console/internal/app/graph/generated/generated.go +++ b/apps/console/internal/app/graph/generated/generated.go @@ -61,7 +61,6 @@ type ResolverRoot interface { ImagePullSecret() ImagePullSecretResolver K8s__io___api___core___v1__Secret() K8s__io___api___core___v1__SecretResolver ManagedResource() ManagedResourceResolver - MatchFilter() MatchFilterResolver Metadata() MetadataResolver Mutation() MutationResolver Query() QueryResolver @@ -75,7 +74,6 @@ type ResolverRoot interface { Github__com___kloudlite___operator___apis___crds___v1__AppInterceptPortMappingsIn() Github__com___kloudlite___operator___apis___crds___v1__AppInterceptPortMappingsInResolver ImagePullSecretIn() ImagePullSecretInResolver ManagedResourceIn() ManagedResourceInResolver - MatchFilterIn() MatchFilterInResolver MetadataIn() MetadataInResolver RouterIn() RouterInResolver SecretIn() SecretInResolver @@ -943,9 +941,6 @@ type ManagedResourceResolver interface { UpdateTime(ctx context.Context, obj *entities.ManagedResource) (string, error) } -type MatchFilterResolver interface { - MatchType(ctx context.Context, obj *repos.MatchFilter) (model.GithubComKloudliteAPIPkgReposMatchType, error) -} type MetadataResolver interface { Annotations(ctx context.Context, obj *v13.ObjectMeta) (map[string]interface{}, error) CreationTimestamp(ctx context.Context, obj *v13.ObjectMeta) (string, error) @@ -1080,9 +1075,6 @@ type ManagedResourceInResolver interface { Metadata(ctx context.Context, obj *entities.ManagedResource, data *v13.ObjectMeta) error Spec(ctx context.Context, obj *entities.ManagedResource, data *model.GithubComKloudliteOperatorApisCrdsV1ManagedResourceSpecIn) error } -type MatchFilterInResolver interface { - MatchType(ctx context.Context, obj *repos.MatchFilter, data model.GithubComKloudliteAPIPkgReposMatchType) error -} type MetadataInResolver interface { Annotations(ctx context.Context, obj *v13.ObjectMeta, data map[string]interface{}) error Labels(ctx context.Context, obj *v13.ObjectMeta, data map[string]interface{}) error @@ -25722,7 +25714,7 @@ func (ec *executionContext) _MatchFilter_matchType(ctx context.Context, field gr }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.MatchFilter().MatchType(rctx, obj) + return obj.MatchType, nil }) if err != nil { ec.Error(ctx, err) @@ -25734,17 +25726,17 @@ func (ec *executionContext) _MatchFilter_matchType(ctx context.Context, field gr } return graphql.Null } - res := resTmp.(model.GithubComKloudliteAPIPkgReposMatchType) + res := resTmp.(repos.MatchType) fc.Result = res - return ec.marshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋappsᚋconsoleᚋinternalᚋappᚋgraphᚋmodelᚐGithubComKloudliteAPIPkgReposMatchType(ctx, field.Selections, res) + return ec.marshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋreposᚐMatchType(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_MatchFilter_matchType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "MatchFilter", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Github__com___kloudlite___api___pkg___repos__MatchType does not have child fields") }, @@ -40335,13 +40327,11 @@ func (ec *executionContext) unmarshalInputMatchFilterIn(ctx context.Context, obj it.Exact = data case "matchType": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("matchType")) - data, err := ec.unmarshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋappsᚋconsoleᚋinternalᚋappᚋgraphᚋmodelᚐGithubComKloudliteAPIPkgReposMatchType(ctx, v) + data, err := ec.unmarshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋreposᚐMatchType(ctx, v) if err != nil { return it, err } - if err = ec.resolvers.MatchFilterIn().MatchType(ctx, &it, data); err != nil { - return it, err - } + it.MatchType = data case "notInArray": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("notInArray")) data, err := ec.unmarshalOAny2ᚕinterfaceᚄ(ctx, v) @@ -46023,41 +46013,10 @@ func (ec *executionContext) _MatchFilter(ctx context.Context, sel ast.SelectionS case "exact": out.Values[i] = ec._MatchFilter_exact(ctx, field, obj) case "matchType": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._MatchFilter_matchType(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - if field.Deferrable != nil { - dfs, ok := deferred[field.Deferrable.Label] - di := 0 - if ok { - dfs.AddField(field) - di = len(dfs.Values) - 1 - } else { - dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) - deferred[field.Deferrable.Label] = dfs - } - dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { - return innerFunc(ctx, dfs) - }) - - // don't run the out.Concurrently() call below - out.Values[i] = graphql.Null - continue + out.Values[i] = ec._MatchFilter_matchType(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "notInArray": out.Values[i] = ec._MatchFilter_notInArray(ctx, field, obj) case "regex": @@ -48942,14 +48901,20 @@ func (ec *executionContext) marshalNGithub__com___kloudlite___api___common__Crea return ec._Github__com___kloudlite___api___common__CreatedOrUpdatedBy(ctx, sel, &v) } -func (ec *executionContext) unmarshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋappsᚋconsoleᚋinternalᚋappᚋgraphᚋmodelᚐGithubComKloudliteAPIPkgReposMatchType(ctx context.Context, v interface{}) (model.GithubComKloudliteAPIPkgReposMatchType, error) { - var res model.GithubComKloudliteAPIPkgReposMatchType - err := res.UnmarshalGQL(v) +func (ec *executionContext) unmarshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋreposᚐMatchType(ctx context.Context, v interface{}) (repos.MatchType, error) { + tmp, err := graphql.UnmarshalString(v) + res := repos.MatchType(tmp) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋappsᚋconsoleᚋinternalᚋappᚋgraphᚋmodelᚐGithubComKloudliteAPIPkgReposMatchType(ctx context.Context, sel ast.SelectionSet, v model.GithubComKloudliteAPIPkgReposMatchType) graphql.Marshaler { - return v +func (ec *executionContext) marshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋreposᚐMatchType(ctx context.Context, sel ast.SelectionSet, v repos.MatchType) graphql.Marshaler { + res := graphql.MarshalString(string(v)) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res } func (ec *executionContext) unmarshalNGithub__com___kloudlite___api___pkg___types__SyncAction2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋtypesᚐSyncAction(ctx context.Context, v interface{}) (types.SyncAction, error) { diff --git a/apps/console/internal/app/graph/matchfilter.resolvers.go b/apps/console/internal/app/graph/matchfilter.resolvers.go deleted file mode 100644 index 6506351e9..000000000 --- a/apps/console/internal/app/graph/matchfilter.resolvers.go +++ /dev/null @@ -1,55 +0,0 @@ -package graph - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.45 - -import ( - "context" - "fmt" - - "github.com/kloudlite/api/apps/console/internal/app/graph/generated" - "github.com/kloudlite/api/apps/console/internal/app/graph/model" - "github.com/kloudlite/api/pkg/functions" - "github.com/kloudlite/api/pkg/repos" -) - -// MatchType is the resolver for the matchType field. -func (r *matchFilterResolver) MatchType(ctx context.Context, obj *repos.MatchFilter) (model.GithubComKloudliteAPIPkgReposMatchType, error) { - if obj == nil { - return "", fmt.Errorf("obj == nil") - } - - return functions.JsonConvert[model.GithubComKloudliteAPIPkgReposMatchType](obj.MatchType) -} - -// MatchType is the resolver for the matchType field. -func (r *matchFilterInResolver) MatchType(ctx context.Context, obj *repos.MatchFilter, data model.GithubComKloudliteAPIPkgReposMatchType) error { - if obj == nil { - return fmt.Errorf("obj == nil") - } - - switch data { - case "exact": - obj.MatchType = repos.MatchTypeExact - case "array": - obj.MatchType = repos.MatchTypeArray - case "not_in_array": - obj.MatchType = repos.MatchTypeNotInArray - case "regex": - obj.MatchType = repos.MatchTypeRegex - default: - return fmt.Errorf("unknown value for MatchType: %v", data) - } - - return nil -} - -// MatchFilter returns generated.MatchFilterResolver implementation. -func (r *Resolver) MatchFilter() generated.MatchFilterResolver { return &matchFilterResolver{r} } - -// MatchFilterIn returns generated.MatchFilterInResolver implementation. -func (r *Resolver) MatchFilterIn() generated.MatchFilterInResolver { return &matchFilterInResolver{r} } - -type matchFilterResolver struct{ *Resolver } -type matchFilterInResolver struct{ *Resolver } diff --git a/apps/console/internal/app/graph/model/models_gen.go b/apps/console/internal/app/graph/model/models_gen.go index 0bf4454d2..dfe3d4164 100644 --- a/apps/console/internal/app/graph/model/models_gen.go +++ b/apps/console/internal/app/graph/model/models_gen.go @@ -847,51 +847,6 @@ func (e GithubComKloudliteAPIAppsConsoleInternalEntitiesPullSecretFormat) Marsha fmt.Fprint(w, strconv.Quote(e.String())) } -type GithubComKloudliteAPIPkgReposMatchType string - -const ( - GithubComKloudliteAPIPkgReposMatchTypeArray GithubComKloudliteAPIPkgReposMatchType = "array" - GithubComKloudliteAPIPkgReposMatchTypeExact GithubComKloudliteAPIPkgReposMatchType = "exact" - GithubComKloudliteAPIPkgReposMatchTypeNotInArray GithubComKloudliteAPIPkgReposMatchType = "not_in_array" - GithubComKloudliteAPIPkgReposMatchTypeRegex GithubComKloudliteAPIPkgReposMatchType = "regex" -) - -var AllGithubComKloudliteAPIPkgReposMatchType = []GithubComKloudliteAPIPkgReposMatchType{ - GithubComKloudliteAPIPkgReposMatchTypeArray, - GithubComKloudliteAPIPkgReposMatchTypeExact, - GithubComKloudliteAPIPkgReposMatchTypeNotInArray, - GithubComKloudliteAPIPkgReposMatchTypeRegex, -} - -func (e GithubComKloudliteAPIPkgReposMatchType) IsValid() bool { - switch e { - case GithubComKloudliteAPIPkgReposMatchTypeArray, GithubComKloudliteAPIPkgReposMatchTypeExact, GithubComKloudliteAPIPkgReposMatchTypeNotInArray, GithubComKloudliteAPIPkgReposMatchTypeRegex: - return true - } - return false -} - -func (e GithubComKloudliteAPIPkgReposMatchType) String() string { - return string(e) -} - -func (e *GithubComKloudliteAPIPkgReposMatchType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = GithubComKloudliteAPIPkgReposMatchType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid Github__com___kloudlite___api___pkg___repos__MatchType", str) - } - return nil -} - -func (e GithubComKloudliteAPIPkgReposMatchType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - type GithubComKloudliteOperatorApisCrdsV1ConfigOrSecret string const ( diff --git a/apps/console/internal/app/graph/schema.resolvers.go b/apps/console/internal/app/graph/schema.resolvers.go index 5d6258fce..ad693cbda 100644 --- a/apps/console/internal/app/graph/schema.resolvers.go +++ b/apps/console/internal/app/graph/schema.resolvers.go @@ -874,6 +874,7 @@ func (r *queryResolver) CoreListManagedResources(ctx context.Context, search *mo if search != nil { if search.Text != nil { filter["metadata.name"] = *search.Text + filter[fc.MetadataName] = *search.Text } if search.IsReady != nil { filter["status.isReady"] = *search.IsReady diff --git a/apps/console/internal/domain/environment.go b/apps/console/internal/domain/environment.go index 547b1d7b4..59f095c6c 100644 --- a/apps/console/internal/domain/environment.go +++ b/apps/console/internal/domain/environment.go @@ -482,6 +482,10 @@ func (d *domain) DeleteEnvironment(ctx ConsoleContext, name string) error { d.resourceEventPublisher.PublishEnvironmentResourceEvent(ctx, uenv.Name, entities.ResourceTypeEnvironment, uenv.Name, PublishUpdate) + if uenv.IsArchived != nil && *uenv.IsArchived { + return d.environmentRepo.DeleteById(ctx, uenv.Id) + } + if err := d.deleteK8sResource(ctx, uenv.Name, &uenv.Environment); err != nil { if errors.Is(err, ErrNoClusterAttached) { return d.environmentRepo.DeleteById(ctx, uenv.Id) From 6e25a0bb51f60279ab4d7407042d7954eca36e02 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 20 Jun 2024 20:30:30 +0530 Subject: [PATCH 2/9] feat(accounts): gateway region for accounts - observability api, updates kloudlite gateway device URI --- apps/accounts/Taskfile.yml | 1 + apps/accounts/internal/app/gqlgen.yml | 3 + .../internal/app/graph/account.resolvers.go | 15 +- .../app/graph/accountmembership.resolvers.go | 2 +- .../app/graph/common-types.resolvers.go | 2 +- .../internal/app/graph/entity.resolvers.go | 2 +- .../internal/app/graph/generated/generated.go | 571 ++++++++++++++++-- .../app/graph/invitation.resolvers.go | 2 +- .../internal/app/graph/model/models_gen.go | 11 + .../internal/app/graph/schema.graphqls | 2 + .../internal/app/graph/schema.resolvers.go | 12 +- .../graph/struct-to-graphql/account.graphqls | 2 + .../availablekloudliteregion.graphqls | 10 + apps/accounts/internal/app/grpc-server.go | 8 +- apps/accounts/internal/domain/accounts.go | 18 + apps/accounts/internal/domain/domain.go | 9 + apps/accounts/internal/entities/account.go | 2 + apps/accounts/internal/env/env.go | 41 +- apps/accounts/main.go | 3 +- apps/observability/Taskfile.yml | 4 +- apps/observability/internal/app/app.go | 5 +- grpc-interfaces/accounts.proto | 1 + .../kloudlite.io/rpc/accounts/accounts.pb.go | 46 +- 23 files changed, 679 insertions(+), 93 deletions(-) create mode 100644 apps/accounts/internal/app/graph/struct-to-graphql/availablekloudliteregion.graphqls diff --git a/apps/accounts/Taskfile.yml b/apps/accounts/Taskfile.yml index 1a36382f3..f743a35fe 100644 --- a/apps/accounts/Taskfile.yml +++ b/apps/accounts/Taskfile.yml @@ -24,6 +24,7 @@ tasks: - mkdir -p "./internal/app/_struct-to-graphql" - go run ../../cmd/struct-to-graphql --struct github.com/kloudlite/api/apps/accounts/internal/entities.Account + --struct github.com/kloudlite/api/apps/accounts/internal/domain.AvailableKloudliteRegion --struct github.com/kloudlite/api/apps/accounts/internal/entities.Invitation --struct github.com/kloudlite/api/apps/accounts/internal/entities.AccountMembership > ./internal/app/_struct-to-graphql/main.go diff --git a/apps/accounts/internal/app/gqlgen.yml b/apps/accounts/internal/app/gqlgen.yml index 2a020560c..c9bcc4f19 100644 --- a/apps/accounts/internal/app/gqlgen.yml +++ b/apps/accounts/internal/app/gqlgen.yml @@ -82,6 +82,9 @@ models: user: resolver: true + AvailableKloudliteRegion: + model: github.com/kloudlite/api/apps/accounts/internal/domain.AvailableKloudliteRegion + Invitation: &invitation-model model: github.com/kloudlite/api/apps/accounts/internal/entities.Invitation InvitationIn: *invitation-model diff --git a/apps/accounts/internal/app/graph/account.resolvers.go b/apps/accounts/internal/app/graph/account.resolvers.go index a32ceafe8..47323dedf 100644 --- a/apps/accounts/internal/app/graph/account.resolvers.go +++ b/apps/accounts/internal/app/graph/account.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.39 +// Code generated by github.com/99designs/gqlgen version v0.17.45 import ( "context" @@ -47,16 +47,3 @@ func (r *Resolver) AccountIn() generated.AccountInResolver { return &accountInRe type accountResolver struct{ *Resolver } type accountInResolver struct{ *Resolver } - -// !!! WARNING !!! -// The code below was going to be deleted when updating resolvers. It has been copied here so you have -// one last chance to move it out of harms way if you want. There are two reasons this happens: -// - When renaming or deleting a resolver the old code will be put in here. You can safely delete -// it when you're done. -// - You have helper methods in this file. Move them out to keep these resolver files clean. -func (r *accountResolver) ID(ctx context.Context, obj *entities.Account) (string, error) { - if obj == nil { - return "", errors.Newf("resource is nil") - } - return string(obj.Id), nil -} diff --git a/apps/accounts/internal/app/graph/accountmembership.resolvers.go b/apps/accounts/internal/app/graph/accountmembership.resolvers.go index 4f70b2de9..7631ac532 100644 --- a/apps/accounts/internal/app/graph/accountmembership.resolvers.go +++ b/apps/accounts/internal/app/graph/accountmembership.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.39 +// Code generated by github.com/99designs/gqlgen version v0.17.45 import ( "context" diff --git a/apps/accounts/internal/app/graph/common-types.resolvers.go b/apps/accounts/internal/app/graph/common-types.resolvers.go index f9975c590..748abbff6 100644 --- a/apps/accounts/internal/app/graph/common-types.resolvers.go +++ b/apps/accounts/internal/app/graph/common-types.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.39 +// Code generated by github.com/99designs/gqlgen version v0.17.45 import ( "context" diff --git a/apps/accounts/internal/app/graph/entity.resolvers.go b/apps/accounts/internal/app/graph/entity.resolvers.go index 888b2fdd6..d00b1fe5b 100644 --- a/apps/accounts/internal/app/graph/entity.resolvers.go +++ b/apps/accounts/internal/app/graph/entity.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.39 +// Code generated by github.com/99designs/gqlgen version v0.17.45 import ( "context" diff --git a/apps/accounts/internal/app/graph/generated/generated.go b/apps/accounts/internal/app/graph/generated/generated.go index 28fbe048c..15abcb92e 100644 --- a/apps/accounts/internal/app/graph/generated/generated.go +++ b/apps/accounts/internal/app/graph/generated/generated.go @@ -65,19 +65,20 @@ type DirectiveRoot struct { type ComplexityRoot struct { Account struct { - ContactEmail func(childComplexity int) int - CreatedBy func(childComplexity int) int - CreationTime func(childComplexity int) int - DisplayName func(childComplexity int) int - Id func(childComplexity int) int - IsActive func(childComplexity int) int - LastUpdatedBy func(childComplexity int) int - Logo func(childComplexity int) int - MarkedForDeletion func(childComplexity int) int - ObjectMeta func(childComplexity int) int - RecordVersion func(childComplexity int) int - TargetNamespace func(childComplexity int) int - UpdateTime func(childComplexity int) int + ContactEmail func(childComplexity int) int + CreatedBy func(childComplexity int) int + CreationTime func(childComplexity int) int + DisplayName func(childComplexity int) int + Id func(childComplexity int) int + IsActive func(childComplexity int) int + KloudliteGatewayRegion func(childComplexity int) int + LastUpdatedBy func(childComplexity int) int + Logo func(childComplexity int) int + MarkedForDeletion func(childComplexity int) int + ObjectMeta func(childComplexity int) int + RecordVersion func(childComplexity int) int + TargetNamespace func(childComplexity int) int + UpdateTime func(childComplexity int) int } AccountMembership struct { @@ -92,6 +93,11 @@ type ComplexityRoot struct { SuggestedNames func(childComplexity int) int } + AvailableKloudliteRegion struct { + DisplayName func(childComplexity int) int + ID func(childComplexity int) int + } + Entity struct { FindUserByID func(childComplexity int, id repos.ID) int } @@ -151,6 +157,7 @@ type ComplexityRoot struct { } Query struct { + AccountsAvailableKloudliteRegions func(childComplexity int) int AccountsCheckNameAvailability func(childComplexity int, name string) int AccountsEnsureKloudliteRegistryPullSecrets func(childComplexity int, accountName string) int AccountsGetAccount func(childComplexity int, accountName string) int @@ -230,6 +237,7 @@ type QueryResolver interface { AccountsListMembershipsForAccount(ctx context.Context, accountName string, role *types.Role) ([]*entities.AccountMembership, error) AccountsGetAccountMembership(ctx context.Context, accountName string) (*entities.AccountMembership, error) AccountsEnsureKloudliteRegistryPullSecrets(ctx context.Context, accountName string) (bool, error) + AccountsAvailableKloudliteRegions(ctx context.Context) ([]*domain.AvailableKloudliteRegion, error) } type UserResolver interface { Accounts(ctx context.Context, obj *model.User) ([]*entities.AccountMembership, error) @@ -305,6 +313,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Account.IsActive(childComplexity), true + case "Account.kloudliteGatewayRegion": + if e.complexity.Account.KloudliteGatewayRegion == nil { + break + } + + return e.complexity.Account.KloudliteGatewayRegion(childComplexity), true + case "Account.lastUpdatedBy": if e.complexity.Account.LastUpdatedBy == nil { break @@ -396,6 +411,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.AccountsCheckNameAvailabilityOutput.SuggestedNames(childComplexity), true + case "AvailableKloudliteRegion.displayName": + if e.complexity.AvailableKloudliteRegion.DisplayName == nil { + break + } + + return e.complexity.AvailableKloudliteRegion.DisplayName(childComplexity), true + + case "AvailableKloudliteRegion.id": + if e.complexity.AvailableKloudliteRegion.ID == nil { + break + } + + return e.complexity.AvailableKloudliteRegion.ID(childComplexity), true + case "Entity.findUserByID": if e.complexity.Entity.FindUserByID == nil { break @@ -741,6 +770,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.PageInfo.StartCursor(childComplexity), true + case "Query.accounts_availableKloudliteRegions": + if e.complexity.Query.AccountsAvailableKloudliteRegions == nil { + break + } + + return e.complexity.Query.AccountsAvailableKloudliteRegions(childComplexity), true + case "Query.accounts_checkNameAvailability": if e.complexity.Query.AccountsCheckNameAvailability == nil { break @@ -925,6 +961,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { inputUnmarshalMap := graphql.BuildUnmarshalerMap( ec.unmarshalInputAccountIn, ec.unmarshalInputAccountMembershipIn, + ec.unmarshalInputAvailableKloudliteRegionIn, ec.unmarshalInputInvitationIn, ec.unmarshalInputMetadataIn, ) @@ -1052,6 +1089,8 @@ type Query { accounts_getAccountMembership(accountName: String!): AccountMembership @isLoggedInAndVerified accounts_ensureKloudliteRegistryPullSecrets(accountName: String!): Boolean! @isLoggedInAndVerified + + accounts_availableKloudliteRegions: [AvailableKloudliteRegion!] @isLoggedInAndVerified } type Mutation { @@ -1089,6 +1128,7 @@ extend type User @key(fields: "id") { displayName: String! id: ID! isActive: Boolean + kloudliteGatewayRegion: String! lastUpdatedBy: Github__com___kloudlite___api___common__CreatedOrUpdatedBy! logo: String markedForDeletion: Boolean @@ -1102,6 +1142,7 @@ input AccountIn { contactEmail: String displayName: String! isActive: Boolean + kloudliteGatewayRegion: String! logo: String metadata: MetadataIn } @@ -1119,6 +1160,17 @@ input AccountMembershipIn { userId: String! } +`, BuiltIn: false}, + {Name: "../struct-to-graphql/availablekloudliteregion.graphqls", Input: `type AvailableKloudliteRegion @shareable { + displayName: String! + id: String! +} + +input AvailableKloudliteRegionIn { + displayName: String! + id: String! +} + `, BuiltIn: false}, {Name: "../struct-to-graphql/common-types.graphqls", Input: `type Github__com___kloudlite___api___common__CreatedOrUpdatedBy @shareable { userEmail: String! @@ -1214,7 +1266,13 @@ scalar Date | UNION directive @interfaceObject on OBJECT directive @link(import: [String!], url: String!) repeatable on SCHEMA - directive @override(from: String!) on FIELD_DEFINITION + directive @override(from: String!, label: String) on FIELD_DEFINITION + directive @policy(policies: [[federation__Policy!]!]!) on + | FIELD_DEFINITION + | OBJECT + | INTERFACE + | SCALAR + | ENUM directive @provides(fields: FieldSet!) on FIELD_DEFINITION directive @requires(fields: FieldSet!) on FIELD_DEFINITION directive @requiresScopes(scopes: [[federation__Scope!]!]!) on @@ -1237,6 +1295,7 @@ scalar Date | UNION scalar _Any scalar FieldSet + scalar federation__Policy scalar federation__Scope `, BuiltIn: true}, {Name: "../../federation/entity.graphql", Input: ` @@ -2034,6 +2093,50 @@ func (ec *executionContext) fieldContext_Account_isActive(ctx context.Context, f return fc, nil } +func (ec *executionContext) _Account_kloudliteGatewayRegion(ctx context.Context, field graphql.CollectedField, obj *entities.Account) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Account_kloudliteGatewayRegion(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.KloudliteGatewayRegion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Account_kloudliteGatewayRegion(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Account", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Account_lastUpdatedBy(ctx context.Context, field graphql.CollectedField, obj *entities.Account) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Account_lastUpdatedBy(ctx, field) if err != nil { @@ -2623,6 +2726,94 @@ func (ec *executionContext) fieldContext_AccountsCheckNameAvailabilityOutput_sug return fc, nil } +func (ec *executionContext) _AvailableKloudliteRegion_displayName(ctx context.Context, field graphql.CollectedField, obj *domain.AvailableKloudliteRegion) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AvailableKloudliteRegion_displayName(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DisplayName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_AvailableKloudliteRegion_displayName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "AvailableKloudliteRegion", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _AvailableKloudliteRegion_id(ctx context.Context, field graphql.CollectedField, obj *domain.AvailableKloudliteRegion) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AvailableKloudliteRegion_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_AvailableKloudliteRegion_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "AvailableKloudliteRegion", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Entity_findUserByID(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Entity_findUserByID(ctx, field) if err != nil { @@ -3742,6 +3933,8 @@ func (ec *executionContext) fieldContext_Mutation_accounts_createAccount(ctx con return ec.fieldContext_Account_id(ctx, field) case "isActive": return ec.fieldContext_Account_isActive(ctx, field) + case "kloudliteGatewayRegion": + return ec.fieldContext_Account_kloudliteGatewayRegion(ctx, field) case "lastUpdatedBy": return ec.fieldContext_Account_lastUpdatedBy(ctx, field) case "logo": @@ -3845,6 +4038,8 @@ func (ec *executionContext) fieldContext_Mutation_accounts_updateAccount(ctx con return ec.fieldContext_Account_id(ctx, field) case "isActive": return ec.fieldContext_Account_isActive(ctx, field) + case "kloudliteGatewayRegion": + return ec.fieldContext_Account_kloudliteGatewayRegion(ctx, field) case "lastUpdatedBy": return ec.fieldContext_Account_lastUpdatedBy(ctx, field) case "logo": @@ -4884,6 +5079,8 @@ func (ec *executionContext) fieldContext_Query_accounts_listAccounts(ctx context return ec.fieldContext_Account_id(ctx, field) case "isActive": return ec.fieldContext_Account_isActive(ctx, field) + case "kloudliteGatewayRegion": + return ec.fieldContext_Account_kloudliteGatewayRegion(ctx, field) case "lastUpdatedBy": return ec.fieldContext_Account_lastUpdatedBy(ctx, field) case "logo": @@ -4973,6 +5170,8 @@ func (ec *executionContext) fieldContext_Query_accounts_getAccount(ctx context.C return ec.fieldContext_Account_id(ctx, field) case "isActive": return ec.fieldContext_Account_isActive(ctx, field) + case "kloudliteGatewayRegion": + return ec.fieldContext_Account_kloudliteGatewayRegion(ctx, field) case "lastUpdatedBy": return ec.fieldContext_Account_lastUpdatedBy(ctx, field) case "logo": @@ -5771,6 +5970,73 @@ func (ec *executionContext) fieldContext_Query_accounts_ensureKloudliteRegistryP return fc, nil } +func (ec *executionContext) _Query_accounts_availableKloudliteRegions(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_accounts_availableKloudliteRegions(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().AccountsAvailableKloudliteRegions(rctx) + } + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsLoggedInAndVerified == nil { + return nil, errors.New("directive isLoggedInAndVerified is not implemented") + } + return ec.directives.IsLoggedInAndVerified(ctx, nil, directive0) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.([]*domain.AvailableKloudliteRegion); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be []*github.com/kloudlite/api/apps/accounts/internal/domain.AvailableKloudliteRegion`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*domain.AvailableKloudliteRegion) + fc.Result = res + return ec.marshalOAvailableKloudliteRegion2ᚕᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋaccountsᚋinternalᚋdomainᚐAvailableKloudliteRegionᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_accounts_availableKloudliteRegions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "displayName": + return ec.fieldContext_AvailableKloudliteRegion_displayName(ctx, field) + case "id": + return ec.fieldContext_AvailableKloudliteRegion_id(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type AvailableKloudliteRegion", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Query__entities(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query__entities(ctx, field) if err != nil { @@ -7999,7 +8265,7 @@ func (ec *executionContext) unmarshalInputAccountIn(ctx context.Context, obj int asMap[k] = v } - fieldsInOrder := [...]string{"contactEmail", "displayName", "isActive", "logo", "metadata"} + fieldsInOrder := [...]string{"contactEmail", "displayName", "isActive", "kloudliteGatewayRegion", "logo", "metadata"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -8007,8 +8273,6 @@ func (ec *executionContext) unmarshalInputAccountIn(ctx context.Context, obj int } switch k { case "contactEmail": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("contactEmail")) data, err := ec.unmarshalOString2string(ctx, v) if err != nil { @@ -8016,8 +8280,6 @@ func (ec *executionContext) unmarshalInputAccountIn(ctx context.Context, obj int } it.ContactEmail = data case "displayName": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("displayName")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { @@ -8025,17 +8287,20 @@ func (ec *executionContext) unmarshalInputAccountIn(ctx context.Context, obj int } it.DisplayName = data case "isActive": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isActive")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.IsActive = data + case "kloudliteGatewayRegion": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("kloudliteGatewayRegion")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.KloudliteGatewayRegion = data case "logo": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("logo")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { @@ -8043,8 +8308,6 @@ func (ec *executionContext) unmarshalInputAccountIn(ctx context.Context, obj int } it.Logo = data case "metadata": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("metadata")) data, err := ec.unmarshalOMetadataIn2ᚖk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐObjectMeta(ctx, v) if err != nil { @@ -8074,8 +8337,6 @@ func (ec *executionContext) unmarshalInputAccountMembershipIn(ctx context.Contex } switch k { case "accountName": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("accountName")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { @@ -8083,8 +8344,6 @@ func (ec *executionContext) unmarshalInputAccountMembershipIn(ctx context.Contex } it.AccountName = data case "role": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("role")) data, err := ec.unmarshalNGithub__com___kloudlite___api___apps___iam___types__Role2githubᚗcomᚋkloudliteᚋapiᚋappsᚋiamᚋtypesᚐRole(ctx, v) if err != nil { @@ -8092,8 +8351,6 @@ func (ec *executionContext) unmarshalInputAccountMembershipIn(ctx context.Contex } it.Role = data case "userId": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userId")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { @@ -8106,6 +8363,40 @@ func (ec *executionContext) unmarshalInputAccountMembershipIn(ctx context.Contex return it, nil } +func (ec *executionContext) unmarshalInputAvailableKloudliteRegionIn(ctx context.Context, obj interface{}) (model.AvailableKloudliteRegionIn, error) { + var it model.AvailableKloudliteRegionIn + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"displayName", "id"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "displayName": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("displayName")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.DisplayName = data + case "id": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.ID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputInvitationIn(ctx context.Context, obj interface{}) (entities.Invitation, error) { var it entities.Invitation asMap := map[string]interface{}{} @@ -8121,8 +8412,6 @@ func (ec *executionContext) unmarshalInputInvitationIn(ctx context.Context, obj } switch k { case "userEmail": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userEmail")) data, err := ec.unmarshalOString2string(ctx, v) if err != nil { @@ -8130,8 +8419,6 @@ func (ec *executionContext) unmarshalInputInvitationIn(ctx context.Context, obj } it.UserEmail = data case "userName": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userName")) data, err := ec.unmarshalOString2string(ctx, v) if err != nil { @@ -8139,8 +8426,6 @@ func (ec *executionContext) unmarshalInputInvitationIn(ctx context.Context, obj } it.UserName = data case "userRole": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userRole")) data, err := ec.unmarshalNGithub__com___kloudlite___api___apps___iam___types__Role2githubᚗcomᚋkloudliteᚋapiᚋappsᚋiamᚋtypesᚐRole(ctx, v) if err != nil { @@ -8168,8 +8453,6 @@ func (ec *executionContext) unmarshalInputMetadataIn(ctx context.Context, obj in } switch k { case "annotations": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("annotations")) data, err := ec.unmarshalOMap2map(ctx, v) if err != nil { @@ -8179,8 +8462,6 @@ func (ec *executionContext) unmarshalInputMetadataIn(ctx context.Context, obj in return it, err } case "labels": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("labels")) data, err := ec.unmarshalOMap2map(ctx, v) if err != nil { @@ -8190,8 +8471,6 @@ func (ec *executionContext) unmarshalInputMetadataIn(ctx context.Context, obj in return it, err } case "name": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { @@ -8199,8 +8478,6 @@ func (ec *executionContext) unmarshalInputMetadataIn(ctx context.Context, obj in } it.Name = data case "namespace": - var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("namespace")) data, err := ec.unmarshalOString2string(ctx, v) if err != nil { @@ -8303,6 +8580,11 @@ func (ec *executionContext) _Account(ctx context.Context, sel ast.SelectionSet, } case "isActive": out.Values[i] = ec._Account_isActive(ctx, field, obj) + case "kloudliteGatewayRegion": + out.Values[i] = ec._Account_kloudliteGatewayRegion(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } case "lastUpdatedBy": out.Values[i] = ec._Account_lastUpdatedBy(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -8537,6 +8819,50 @@ func (ec *executionContext) _AccountsCheckNameAvailabilityOutput(ctx context.Con return out } +var availableKloudliteRegionImplementors = []string{"AvailableKloudliteRegion"} + +func (ec *executionContext) _AvailableKloudliteRegion(ctx context.Context, sel ast.SelectionSet, obj *domain.AvailableKloudliteRegion) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, availableKloudliteRegionImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("AvailableKloudliteRegion") + case "displayName": + out.Values[i] = ec._AvailableKloudliteRegion_displayName(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "id": + out.Values[i] = ec._AvailableKloudliteRegion_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var entityImplementors = []string{"Entity"} func (ec *executionContext) _Entity(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { @@ -9409,6 +9735,25 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "accounts_availableKloudliteRegions": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_accounts_availableKloudliteRegions(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "_entities": field := field @@ -9995,6 +10340,16 @@ func (ec *executionContext) marshalNAccountsCheckNameAvailabilityOutput2ᚖgithu return ec._AccountsCheckNameAvailabilityOutput(ctx, sel, v) } +func (ec *executionContext) marshalNAvailableKloudliteRegion2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋaccountsᚋinternalᚋdomainᚐAvailableKloudliteRegion(ctx context.Context, sel ast.SelectionSet, v *domain.AvailableKloudliteRegion) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._AvailableKloudliteRegion(ctx, sel, v) +} + func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { res, err := graphql.UnmarshalBoolean(v) return res, graphql.ErrorOnPath(ctx, err) @@ -10515,6 +10870,85 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a return res } +func (ec *executionContext) unmarshalNfederation__Policy2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNfederation__Policy2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) unmarshalNfederation__Policy2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]string, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNfederation__Policy2string(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalNfederation__Policy2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + for i := range v { + ret[i] = ec.marshalNfederation__Policy2string(ctx, sel, v[i]) + } + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalNfederation__Policy2ᚕᚕstringᚄ(ctx context.Context, v interface{}) ([][]string, error) { + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([][]string, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNfederation__Policy2ᚕstringᚄ(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalNfederation__Policy2ᚕᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v [][]string) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + for i := range v { + ret[i] = ec.marshalNfederation__Policy2ᚕstringᚄ(ctx, sel, v[i]) + } + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + func (ec *executionContext) unmarshalNfederation__Scope2string(ctx context.Context, v interface{}) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) @@ -10696,6 +11130,53 @@ func (ec *executionContext) marshalOAccountMembership2ᚖgithubᚗcomᚋkloudlit return ec._AccountMembership(ctx, sel, v) } +func (ec *executionContext) marshalOAvailableKloudliteRegion2ᚕᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋaccountsᚋinternalᚋdomainᚐAvailableKloudliteRegionᚄ(ctx context.Context, sel ast.SelectionSet, v []*domain.AvailableKloudliteRegion) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNAvailableKloudliteRegion2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋaccountsᚋinternalᚋdomainᚐAvailableKloudliteRegion(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { res, err := graphql.UnmarshalBoolean(v) return res, graphql.ErrorOnPath(ctx, err) diff --git a/apps/accounts/internal/app/graph/invitation.resolvers.go b/apps/accounts/internal/app/graph/invitation.resolvers.go index 6a3d9e625..b192ab99d 100644 --- a/apps/accounts/internal/app/graph/invitation.resolvers.go +++ b/apps/accounts/internal/app/graph/invitation.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.39 +// Code generated by github.com/99designs/gqlgen version v0.17.45 import ( "context" diff --git a/apps/accounts/internal/app/graph/model/models_gen.go b/apps/accounts/internal/app/graph/model/models_gen.go index 4e232711d..94cee05b9 100644 --- a/apps/accounts/internal/app/graph/model/models_gen.go +++ b/apps/accounts/internal/app/graph/model/models_gen.go @@ -14,6 +14,14 @@ type AccountMembershipIn struct { UserID string `json:"userId"` } +type AvailableKloudliteRegionIn struct { + DisplayName string `json:"displayName"` + ID string `json:"id"` +} + +type Mutation struct { +} + type PageInfo struct { EndCursor *string `json:"endCursor,omitempty"` HasNextPage *bool `json:"hasNextPage,omitempty"` @@ -21,6 +29,9 @@ type PageInfo struct { StartCursor *string `json:"startCursor,omitempty"` } +type Query struct { +} + type User struct { ID repos.ID `json:"id"` Accounts []*entities.AccountMembership `json:"accounts,omitempty"` diff --git a/apps/accounts/internal/app/graph/schema.graphqls b/apps/accounts/internal/app/graph/schema.graphqls index 5157bc45e..9f957e686 100644 --- a/apps/accounts/internal/app/graph/schema.graphqls +++ b/apps/accounts/internal/app/graph/schema.graphqls @@ -26,6 +26,8 @@ type Query { accounts_getAccountMembership(accountName: String!): AccountMembership @isLoggedInAndVerified accounts_ensureKloudliteRegistryPullSecrets(accountName: String!): Boolean! @isLoggedInAndVerified + + accounts_availableKloudliteRegions: [AvailableKloudliteRegion!] @isLoggedInAndVerified } type Mutation { diff --git a/apps/accounts/internal/app/graph/schema.resolvers.go b/apps/accounts/internal/app/graph/schema.resolvers.go index e96505c2d..e66c52648 100644 --- a/apps/accounts/internal/app/graph/schema.resolvers.go +++ b/apps/accounts/internal/app/graph/schema.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.39 +// Code generated by github.com/99designs/gqlgen version v0.17.45 import ( "context" @@ -263,6 +263,16 @@ func (r *queryResolver) AccountsEnsureKloudliteRegistryPullSecrets(ctx context.C return true, nil } +// AccountsAvailableKloudliteRegions is the resolver for the accounts_availableKloudliteRegions field. +func (r *queryResolver) AccountsAvailableKloudliteRegions(ctx context.Context) ([]*domain.AvailableKloudliteRegion, error) { + uc, err := toUserContext(ctx) + if err != nil { + return nil, errors.NewE(err) + } + + return r.domain.AvailableKloudliteRegions(uc) +} + // Accounts is the resolver for the accounts field. func (r *userResolver) Accounts(ctx context.Context, obj *model.User) ([]*entities.AccountMembership, error) { uc, err := toUserContext(ctx) diff --git a/apps/accounts/internal/app/graph/struct-to-graphql/account.graphqls b/apps/accounts/internal/app/graph/struct-to-graphql/account.graphqls index c7d6b3de2..365f3339b 100644 --- a/apps/accounts/internal/app/graph/struct-to-graphql/account.graphqls +++ b/apps/accounts/internal/app/graph/struct-to-graphql/account.graphqls @@ -5,6 +5,7 @@ type Account @shareable { displayName: String! id: ID! isActive: Boolean + kloudliteGatewayRegion: String! lastUpdatedBy: Github__com___kloudlite___api___common__CreatedOrUpdatedBy! logo: String markedForDeletion: Boolean @@ -18,6 +19,7 @@ input AccountIn { contactEmail: String displayName: String! isActive: Boolean + kloudliteGatewayRegion: String! logo: String metadata: MetadataIn } diff --git a/apps/accounts/internal/app/graph/struct-to-graphql/availablekloudliteregion.graphqls b/apps/accounts/internal/app/graph/struct-to-graphql/availablekloudliteregion.graphqls new file mode 100644 index 000000000..76507bec3 --- /dev/null +++ b/apps/accounts/internal/app/graph/struct-to-graphql/availablekloudliteregion.graphqls @@ -0,0 +1,10 @@ +type AvailableKloudliteRegion @shareable { + displayName: String! + id: String! +} + +input AvailableKloudliteRegionIn { + displayName: String! + id: String! +} + diff --git a/apps/accounts/internal/app/grpc-server.go b/apps/accounts/internal/app/grpc-server.go index 3aec3b311..359460684 100644 --- a/apps/accounts/internal/app/grpc-server.go +++ b/apps/accounts/internal/app/grpc-server.go @@ -2,6 +2,7 @@ package app import ( "context" + "github.com/kloudlite/api/pkg/errors" "github.com/kloudlite/api/apps/accounts/internal/domain" @@ -33,9 +34,10 @@ func (s *accountsGrpcServer) GetAccount(ctx context.Context, in *accounts.GetAcc } return &accounts.GetAccountOut{ - IsActive: isActive, - TargetNamespace: acc.TargetNamespace, - AccountId: string(acc.Id), + IsActive: isActive, + TargetNamespace: acc.TargetNamespace, + AccountId: string(acc.Id), + KloudliteGatewayRegion: acc.KloudliteGatewayRegion, }, nil } diff --git a/apps/accounts/internal/domain/accounts.go b/apps/accounts/internal/domain/accounts.go index 651b44799..d2d7cc675 100644 --- a/apps/accounts/internal/domain/accounts.go +++ b/apps/accounts/internal/domain/accounts.go @@ -303,3 +303,21 @@ func (d *domain) DeactivateAccount(ctx UserContext, name string) (bool, error) { return true, nil } + +type AvailableKloudliteRegion struct { + ID string `json:"id"` + DisplayName string `json:"displayName"` +} + +// AvailableKloudliteRegions implements Domain. +func (d *domain) AvailableKloudliteRegions(ctx UserContext) ([]*AvailableKloudliteRegion, error) { + regions := make([]*AvailableKloudliteRegion, 0, len(d.Env.AvailableKloudliteRegions)) + for i := range d.Env.AvailableKloudliteRegions { + regions = append(regions, &AvailableKloudliteRegion{ + ID: d.Env.AvailableKloudliteRegions[i].ID, + DisplayName: d.Env.AvailableKloudliteRegions[i].DisplayName, + }) + } + + return regions, nil +} diff --git a/apps/accounts/internal/domain/domain.go b/apps/accounts/internal/domain/domain.go index 8ea5da489..511368a95 100644 --- a/apps/accounts/internal/domain/domain.go +++ b/apps/accounts/internal/domain/domain.go @@ -2,6 +2,7 @@ package domain import ( "github.com/kloudlite/api/apps/accounts/internal/entities" + "github.com/kloudlite/api/apps/accounts/internal/env" iamT "github.com/kloudlite/api/apps/iam/types" "github.com/kloudlite/api/grpc-interfaces/container_registry" "github.com/kloudlite/api/grpc-interfaces/kloudlite.io/rpc/auth" @@ -36,6 +37,8 @@ type AccountService interface { DeactivateAccount(ctx UserContext, name string) (bool, error) EnsureKloudliteRegistryCredentials(ctx UserContext, accountName string) error + + AvailableKloudliteRegions(ctx UserContext) ([]*AvailableKloudliteRegion, error) } type InvitationService interface { @@ -82,6 +85,8 @@ type domain struct { k8sClient k8s.Client + Env *env.Env + logger logging.Logger } @@ -98,6 +103,8 @@ func NewDomain( invitationRepo repos.DbRepo[*entities.Invitation], // accountInviteTokenRepo cache.Repo[*entities.Invitation], + ev *env.Env, + logger logging.Logger, ) Domain { return &domain{ @@ -112,6 +119,8 @@ func NewDomain( accountRepo: accountRepo, invitationRepo: invitationRepo, + Env: ev, + logger: logger, } } diff --git a/apps/accounts/internal/entities/account.go b/apps/accounts/internal/entities/account.go index f9c6dda06..27b963139 100644 --- a/apps/accounts/internal/entities/account.go +++ b/apps/accounts/internal/entities/account.go @@ -16,6 +16,8 @@ type Account struct { Logo *string `json:"logo"` IsActive *bool `json:"isActive,omitempty"` ContactEmail string `json:"contactEmail,omitempty"` + + KloudliteGatewayRegion string `json:"kloudliteGatewayRegion"` } var AccountIndices = []repos.IndexField{ diff --git a/apps/accounts/internal/env/env.go b/apps/accounts/internal/env/env.go index f3c90dc06..f3d17bbf0 100644 --- a/apps/accounts/internal/env/env.go +++ b/apps/accounts/internal/env/env.go @@ -1,8 +1,12 @@ package env import ( + "io" + "os" + "github.com/codingconcepts/env" "github.com/kloudlite/api/pkg/errors" + "sigs.k8s.io/yaml" ) type Env struct { @@ -21,10 +25,23 @@ type Env struct { ConsoleGrpcAddr string `env:"CONSOLE_GRPC_ADDR" required:"true"` AuthGrpcAddr string `env:"AUTH_GRPC_ADDR" required:"true"` - SessionKVBucket string `env:"SESSION_KV_BUCKET" required:"true"` - NatsURL string `env:"NATS_URL" required:"true"` - IsDev bool - KubernetesApiProxy string `env:"KUBERNETES_API_PROXY"` + SessionKVBucket string `env:"SESSION_KV_BUCKET" required:"true"` + NatsURL string `env:"NATS_URL" required:"true"` + + IsDev bool + KubernetesApiProxy string `env:"KUBERNETES_API_PROXY"` + + AvailableKloudliteRegionsConfig string `env:"AVAILABLE_KLOUDLITE_REGIONS_CONFIG" required:"false"` + AvailableKloudliteRegions []AvailableKloudliteRegion +} + +type AvailableKloudliteRegion struct { + ID string `json:"id"` + DisplayName string `json:"displayName"` + Region string `json:"region"` + CloudProvider string `json:"cloudProvider"` + Kubeconfig string `json:"kubeconfig"` + PublicDNSHost string `json:"publicDNSHost"` } func LoadEnv() (*Env, error) { @@ -32,5 +49,21 @@ func LoadEnv() (*Env, error) { if err := env.Set(&ev); err != nil { return nil, errors.NewE(err) } + + if ev.AvailableKloudliteRegionsConfig != "" { + f, err := os.Open(ev.AvailableKloudliteRegionsConfig) + if err != nil { + return nil, err + } + b, err := io.ReadAll(f) + if err != nil { + return nil, err + } + + if err := yaml.Unmarshal(b, &ev.AvailableKloudliteRegions); err != nil { + return nil, err + } + } + return &ev, nil } diff --git a/apps/accounts/main.go b/apps/accounts/main.go index b127a7f01..52bd5ca19 100644 --- a/apps/accounts/main.go +++ b/apps/accounts/main.go @@ -65,13 +65,12 @@ func main() { if isDev { return context.WithTimeout(context.TODO(), 20*time.Second) } - return context.WithTimeout(context.TODO(), 5*time.Second) + return context.WithTimeout(context.TODO(), 10*time.Second) }() defer cancelFunc() if err := app.Start(ctx); err != nil { logger.Errorf(err, "error starting accounts app") - logger.Infof("EXITING as errors encountered during startup") os.Exit(1) } diff --git a/apps/observability/Taskfile.yml b/apps/observability/Taskfile.yml index 6462d4186..630484c79 100644 --- a/apps/observability/Taskfile.yml +++ b/apps/observability/Taskfile.yml @@ -19,7 +19,9 @@ tasks: env: CGO_ENABLED: 0 cmds: - - fwatcher --exec 'go run ./main.go --dev' --ext '.go' + # - fwatcher --exec 'go run ./main.go --dev' --ext '.go' + - go build -o ./bin/{{.app}} . + - ./bin/{{.app}} --dev build: cmds: diff --git a/apps/observability/internal/app/app.go b/apps/observability/internal/app/app.go index 996ade768..cce090f42 100644 --- a/apps/observability/internal/app/app.go +++ b/apps/observability/internal/app/app.go @@ -118,7 +118,7 @@ var Module = fx.Module( } return k8s.NewClient(&rest.Config{ - Host: fmt.Sprintf("http://kloudlite-device-proxy-%s.kl-account-%s.svc.cluster.local:8080/clusters/%s", "default", accountName, clusterName), + Host: fmt.Sprintf("http://kloudlite-device-%s.kl-account-%s.svc.cluster.local:8080/clusters/%s", "default", accountName, clusterName), WrapTransport: func(rt http.RoundTripper) http.RoundTripper { return httpServer.NewRoundTripperWithHeaders(rt, map[string][]string{ "X-Kloudlite-Authz": {fmt.Sprintf("Bearer %s", ev.GlobalVPNAuthzSecret)}, @@ -127,6 +127,7 @@ var Module = fx.Module( }, nil) }() if err != nil { + logger.Errorf(err, "failed to create k8s client") http.Error(w, fmt.Sprintf("failed to create k8s client: %v", err), http.StatusInternalServerError) return } @@ -180,7 +181,7 @@ var Module = fx.Module( } return k8s.NewClient(&rest.Config{ - Host: fmt.Sprintf("http://kloudlite-device-proxy-%s.kl-account-%s.svc.cluster.local:8080/clusters/%s", "default", accountName, clusterName), + Host: fmt.Sprintf("http://kloudlite-device-%s.kl-account-%s.svc.cluster.local:8080/clusters/%s", "default", accountName, clusterName), WrapTransport: func(rt http.RoundTripper) http.RoundTripper { return httpServer.NewRoundTripperWithHeaders(rt, map[string][]string{ "X-Kloudlite-Authz": {fmt.Sprintf("Bearer %s", ev.GlobalVPNAuthzSecret)}, diff --git a/grpc-interfaces/accounts.proto b/grpc-interfaces/accounts.proto index dd18f1343..fe1007365 100644 --- a/grpc-interfaces/accounts.proto +++ b/grpc-interfaces/accounts.proto @@ -15,4 +15,5 @@ message GetAccountOut { bool isActive = 1; string targetNamespace = 2; string accountId = 3; + string kloudliteGatewayRegion = 4; } diff --git a/grpc-interfaces/kloudlite.io/rpc/accounts/accounts.pb.go b/grpc-interfaces/kloudlite.io/rpc/accounts/accounts.pb.go index f56956db4..04ccb3a95 100644 --- a/grpc-interfaces/kloudlite.io/rpc/accounts/accounts.pb.go +++ b/grpc-interfaces/kloudlite.io/rpc/accounts/accounts.pb.go @@ -80,9 +80,10 @@ type GetAccountOut struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - IsActive bool `protobuf:"varint,1,opt,name=isActive,proto3" json:"isActive,omitempty"` - TargetNamespace string `protobuf:"bytes,2,opt,name=targetNamespace,proto3" json:"targetNamespace,omitempty"` - AccountId string `protobuf:"bytes,3,opt,name=accountId,proto3" json:"accountId,omitempty"` + IsActive bool `protobuf:"varint,1,opt,name=isActive,proto3" json:"isActive,omitempty"` + TargetNamespace string `protobuf:"bytes,2,opt,name=targetNamespace,proto3" json:"targetNamespace,omitempty"` + AccountId string `protobuf:"bytes,3,opt,name=accountId,proto3" json:"accountId,omitempty"` + KloudliteGatewayRegion string `protobuf:"bytes,4,opt,name=kloudliteGatewayRegion,proto3" json:"kloudliteGatewayRegion,omitempty"` } func (x *GetAccountOut) Reset() { @@ -138,6 +139,13 @@ func (x *GetAccountOut) GetAccountId() string { return "" } +func (x *GetAccountOut) GetKloudliteGatewayRegion() string { + if x != nil { + return x.KloudliteGatewayRegion + } + return "" +} + var File_accounts_proto protoreflect.FileDescriptor var file_accounts_proto_rawDesc = []byte{ @@ -146,20 +154,24 @@ var file_accounts_proto_rawDesc = []byte{ 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x73, 0x0a, 0x0d, 0x47, 0x65, - 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, - 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, - 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x32, - 0x37, 0x0a, 0x08, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x0a, 0x47, - 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0d, 0x2e, 0x47, 0x65, 0x74, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x1a, 0x0e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x42, 0x1b, 0x5a, 0x19, 0x6b, 0x6c, 0x6f, 0x75, - 0x64, 0x6c, 0x69, 0x74, 0x65, 0x2e, 0x69, 0x6f, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x61, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x0d, 0x47, + 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, + 0x12, 0x36, 0x0a, 0x16, 0x6b, 0x6c, 0x6f, 0x75, 0x64, 0x6c, 0x69, 0x74, 0x65, 0x47, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x16, 0x6b, 0x6c, 0x6f, 0x75, 0x64, 0x6c, 0x69, 0x74, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x32, 0x37, 0x0a, 0x08, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x0d, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, + 0x6e, 0x1a, 0x0e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x75, + 0x74, 0x42, 0x1b, 0x5a, 0x19, 0x6b, 0x6c, 0x6f, 0x75, 0x64, 0x6c, 0x69, 0x74, 0x65, 0x2e, 0x69, + 0x6f, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( From 23b04248294649e73e96366c5cd9586f2d1bdd58 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 20 Jun 2024 20:32:33 +0530 Subject: [PATCH 3/9] WIP: external gateway for vpn devices fixes: - cluster CIDR allocation, (already claimed errors) - device IP allocation, (already claimed errors) --- apps/infra/internal/app/gqlgen.yml | 2 +- .../internal/app/graph/generated/generated.go | 77 +++----- .../app/graph/matchfilter.resolvers.go | 33 ---- .../internal/app/graph/model/models_gen.go | 45 ----- apps/infra/internal/domain/clusters.go | 168 ++++++++++++++++++ .../domain/global-vpn-cluster-connection.go | 20 ++- .../internal/domain/global-vpn-devices.go | 35 +++- apps/infra/internal/domain/global-vpn.go | 2 +- apps/infra/internal/domain/templates/embed.go | 1 + .../global-vpn-kloudlite-device.yml.tpl | 5 +- .../templates/kloudlite-gateway-svc.yml.tpl | 22 +++ apps/infra/internal/domain/templates/types.go | 7 + apps/infra/internal/env/env.go | 35 ++++ go.mod | 1 + go.sum | 2 + pkg/wgutils/peer-config.go | 2 + 16 files changed, 314 insertions(+), 143 deletions(-) delete mode 100644 apps/infra/internal/app/graph/matchfilter.resolvers.go create mode 100644 apps/infra/internal/domain/templates/kloudlite-gateway-svc.yml.tpl diff --git a/apps/infra/internal/app/gqlgen.yml b/apps/infra/internal/app/gqlgen.yml index 7216f812b..db501a329 100644 --- a/apps/infra/internal/app/gqlgen.yml +++ b/apps/infra/internal/app/gqlgen.yml @@ -145,7 +145,7 @@ models: model: github.com/kloudlite/api/pkg/repos.MatchFilter MatchFilterIn: *match-filter-model - MatchFilterMatchType: + Github__com___kloudlite___api___pkg___repos__MatchType: model: github.com/kloudlite/api/pkg/repos.MatchType CursorPagination: &cursor-pagination-model diff --git a/apps/infra/internal/app/graph/generated/generated.go b/apps/infra/internal/app/graph/generated/generated.go index ad27f1e6d..b986a0202 100644 --- a/apps/infra/internal/app/graph/generated/generated.go +++ b/apps/infra/internal/app/graph/generated/generated.go @@ -59,7 +59,6 @@ type ResolverRoot interface { GlobalVPN() GlobalVPNResolver GlobalVPNDevice() GlobalVPNDeviceResolver HelmRelease() HelmReleaseResolver - MatchFilter() MatchFilterResolver Metadata() MetadataResolver Mutation() MutationResolver Namespace() NamespaceResolver @@ -76,7 +75,6 @@ type ResolverRoot interface { GlobalVPNDeviceIn() GlobalVPNDeviceInResolver GlobalVPNIn() GlobalVPNInResolver HelmReleaseIn() HelmReleaseInResolver - MatchFilterIn() MatchFilterInResolver MetadataIn() MetadataInResolver NamespaceIn() NamespaceInResolver NodePoolIn() NodePoolInResolver @@ -1511,9 +1509,6 @@ type HelmReleaseResolver interface { UpdateTime(ctx context.Context, obj *entities.HelmRelease) (string, error) } -type MatchFilterResolver interface { - MatchType(ctx context.Context, obj *repos.MatchFilter) (model.GithubComKloudliteAPIPkgReposMatchType, error) -} type MetadataResolver interface { Annotations(ctx context.Context, obj *v1.ObjectMeta) (map[string]interface{}, error) CreationTimestamp(ctx context.Context, obj *v1.ObjectMeta) (string, error) @@ -1674,9 +1669,6 @@ type HelmReleaseInResolver interface { Metadata(ctx context.Context, obj *entities.HelmRelease, data *v1.ObjectMeta) error Spec(ctx context.Context, obj *entities.HelmRelease, data *model.GithubComKloudliteOperatorApisCrdsV1HelmChartSpecIn) error } -type MatchFilterInResolver interface { - MatchType(ctx context.Context, obj *repos.MatchFilter, data model.GithubComKloudliteAPIPkgReposMatchType) error -} type MetadataInResolver interface { Annotations(ctx context.Context, obj *v1.ObjectMeta, data map[string]interface{}) error Labels(ctx context.Context, obj *v1.ObjectMeta, data map[string]interface{}) error @@ -41172,7 +41164,7 @@ func (ec *executionContext) _MatchFilter_matchType(ctx context.Context, field gr }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.MatchFilter().MatchType(rctx, obj) + return obj.MatchType, nil }) if err != nil { ec.Error(ctx, err) @@ -41184,17 +41176,17 @@ func (ec *executionContext) _MatchFilter_matchType(ctx context.Context, field gr } return graphql.Null } - res := resTmp.(model.GithubComKloudliteAPIPkgReposMatchType) + res := resTmp.(repos.MatchType) fc.Result = res - return ec.marshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGithubComKloudliteAPIPkgReposMatchType(ctx, field.Selections, res) + return ec.marshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋreposᚐMatchType(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_MatchFilter_matchType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "MatchFilter", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Github__com___kloudlite___api___pkg___repos__MatchType does not have child fields") }, @@ -60396,13 +60388,11 @@ func (ec *executionContext) unmarshalInputMatchFilterIn(ctx context.Context, obj it.Exact = data case "matchType": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("matchType")) - data, err := ec.unmarshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGithubComKloudliteAPIPkgReposMatchType(ctx, v) + data, err := ec.unmarshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋreposᚐMatchType(ctx, v) if err != nil { return it, err } - if err = ec.resolvers.MatchFilterIn().MatchType(ctx, &it, data); err != nil { - return it, err - } + it.MatchType = data case "notInArray": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("notInArray")) data, err := ec.unmarshalOAny2ᚕinterfaceᚄ(ctx, v) @@ -69494,41 +69484,10 @@ func (ec *executionContext) _MatchFilter(ctx context.Context, sel ast.SelectionS case "exact": out.Values[i] = ec._MatchFilter_exact(ctx, field, obj) case "matchType": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._MatchFilter_matchType(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - if field.Deferrable != nil { - dfs, ok := deferred[field.Deferrable.Label] - di := 0 - if ok { - dfs.AddField(field) - di = len(dfs.Values) - 1 - } else { - dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) - deferred[field.Deferrable.Label] = dfs - } - dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { - return innerFunc(ctx, dfs) - }) - - // don't run the out.Concurrently() call below - out.Values[i] = graphql.Null - continue + out.Values[i] = ec._MatchFilter_matchType(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "notInArray": out.Values[i] = ec._MatchFilter_notInArray(ctx, field, obj) case "regex": @@ -73745,14 +73704,20 @@ func (ec *executionContext) marshalNGithub__com___kloudlite___api___common__Crea return ec._Github__com___kloudlite___api___common__CreatedOrUpdatedBy(ctx, sel, &v) } -func (ec *executionContext) unmarshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGithubComKloudliteAPIPkgReposMatchType(ctx context.Context, v interface{}) (model.GithubComKloudliteAPIPkgReposMatchType, error) { - var res model.GithubComKloudliteAPIPkgReposMatchType - err := res.UnmarshalGQL(v) +func (ec *executionContext) unmarshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋreposᚐMatchType(ctx context.Context, v interface{}) (repos.MatchType, error) { + tmp, err := graphql.UnmarshalString(v) + res := repos.MatchType(tmp) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGithubComKloudliteAPIPkgReposMatchType(ctx context.Context, sel ast.SelectionSet, v model.GithubComKloudliteAPIPkgReposMatchType) graphql.Marshaler { - return v +func (ec *executionContext) marshalNGithub__com___kloudlite___api___pkg___repos__MatchType2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋreposᚐMatchType(ctx context.Context, sel ast.SelectionSet, v repos.MatchType) graphql.Marshaler { + res := graphql.MarshalString(string(v)) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res } func (ec *executionContext) unmarshalNGithub__com___kloudlite___api___pkg___types__SyncAction2githubᚗcomᚋkloudliteᚋapiᚋpkgᚋtypesᚐSyncAction(ctx context.Context, v interface{}) (types.SyncAction, error) { diff --git a/apps/infra/internal/app/graph/matchfilter.resolvers.go b/apps/infra/internal/app/graph/matchfilter.resolvers.go deleted file mode 100644 index bad0729e3..000000000 --- a/apps/infra/internal/app/graph/matchfilter.resolvers.go +++ /dev/null @@ -1,33 +0,0 @@ -package graph - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.45 - -import ( - "context" - "fmt" - - "github.com/kloudlite/api/apps/infra/internal/app/graph/generated" - "github.com/kloudlite/api/apps/infra/internal/app/graph/model" - "github.com/kloudlite/api/pkg/repos" -) - -// MatchType is the resolver for the matchType field. -func (r *matchFilterResolver) MatchType(ctx context.Context, obj *repos.MatchFilter) (model.GithubComKloudliteAPIPkgReposMatchType, error) { - panic(fmt.Errorf("not implemented: MatchType - matchType")) -} - -// MatchType is the resolver for the matchType field. -func (r *matchFilterInResolver) MatchType(ctx context.Context, obj *repos.MatchFilter, data model.GithubComKloudliteAPIPkgReposMatchType) error { - panic(fmt.Errorf("not implemented: MatchType - matchType")) -} - -// MatchFilter returns generated.MatchFilterResolver implementation. -func (r *Resolver) MatchFilter() generated.MatchFilterResolver { return &matchFilterResolver{r} } - -// MatchFilterIn returns generated.MatchFilterInResolver implementation. -func (r *Resolver) MatchFilterIn() generated.MatchFilterInResolver { return &matchFilterInResolver{r} } - -type matchFilterResolver struct{ *Resolver } -type matchFilterInResolver struct{ *Resolver } diff --git a/apps/infra/internal/app/graph/model/models_gen.go b/apps/infra/internal/app/graph/model/models_gen.go index c6e1ed247..60fdab6df 100644 --- a/apps/infra/internal/app/graph/model/models_gen.go +++ b/apps/infra/internal/app/graph/model/models_gen.go @@ -1581,51 +1581,6 @@ func (e GithubComKloudliteAPIAppsInfraInternalEntitiesClusterVisibilityMode) Mar fmt.Fprint(w, strconv.Quote(e.String())) } -type GithubComKloudliteAPIPkgReposMatchType string - -const ( - GithubComKloudliteAPIPkgReposMatchTypeArray GithubComKloudliteAPIPkgReposMatchType = "array" - GithubComKloudliteAPIPkgReposMatchTypeExact GithubComKloudliteAPIPkgReposMatchType = "exact" - GithubComKloudliteAPIPkgReposMatchTypeNotInArray GithubComKloudliteAPIPkgReposMatchType = "not_in_array" - GithubComKloudliteAPIPkgReposMatchTypeRegex GithubComKloudliteAPIPkgReposMatchType = "regex" -) - -var AllGithubComKloudliteAPIPkgReposMatchType = []GithubComKloudliteAPIPkgReposMatchType{ - GithubComKloudliteAPIPkgReposMatchTypeArray, - GithubComKloudliteAPIPkgReposMatchTypeExact, - GithubComKloudliteAPIPkgReposMatchTypeNotInArray, - GithubComKloudliteAPIPkgReposMatchTypeRegex, -} - -func (e GithubComKloudliteAPIPkgReposMatchType) IsValid() bool { - switch e { - case GithubComKloudliteAPIPkgReposMatchTypeArray, GithubComKloudliteAPIPkgReposMatchTypeExact, GithubComKloudliteAPIPkgReposMatchTypeNotInArray, GithubComKloudliteAPIPkgReposMatchTypeRegex: - return true - } - return false -} - -func (e GithubComKloudliteAPIPkgReposMatchType) String() string { - return string(e) -} - -func (e *GithubComKloudliteAPIPkgReposMatchType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = GithubComKloudliteAPIPkgReposMatchType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid Github__com___kloudlite___api___pkg___repos__MatchType", str) - } - return nil -} - -func (e GithubComKloudliteAPIPkgReposMatchType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - type GithubComKloudliteOperatorApisClustersV1AWSPoolType string const ( diff --git a/apps/infra/internal/domain/clusters.go b/apps/infra/internal/domain/clusters.go index 72365b9a3..eb32db73e 100644 --- a/apps/infra/internal/domain/clusters.go +++ b/apps/infra/internal/domain/clusters.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "os" "strings" "time" @@ -17,6 +18,7 @@ import ( message_office_internal "github.com/kloudlite/api/grpc-interfaces/kloudlite.io/rpc/message-office-internal" ct "github.com/kloudlite/operator/apis/common-types" "github.com/kloudlite/operator/operators/resource-watcher/types" + "github.com/kloudlite/operator/pkg/kubectl" "sigs.k8s.io/yaml" "github.com/kloudlite/api/apps/infra/internal/entities" @@ -24,6 +26,7 @@ import ( "github.com/kloudlite/api/pkg/errors" fn "github.com/kloudlite/api/pkg/functions" + "github.com/kloudlite/api/pkg/k8s" "github.com/kloudlite/api/pkg/repos" t "github.com/kloudlite/api/pkg/types" "github.com/kloudlite/api/pkg/wgutils" @@ -374,6 +377,171 @@ func (d *domain) CreateCluster(ctx InfraContext, cluster entities.Cluster) (*ent return nCluster, nil } +func (d *domain) syncKloudliteGateway(ctx InfraContext, gvpnName string) error { + // 1. parse deployment template + b, err := templates.Read(templates.GlobalVPNKloudliteDeviceTemplate) + if err != nil { + return errors.NewE(err) + } + + svcTemplate, err := templates.Read(templates.GatewayServiceTemplate) + if err != nil { + return errors.NewE(err) + } + + accNs, err := d.getAccNamespace(ctx) + if err != nil { + return errors.NewE(err) + } + + gv, err := d.findGlobalVPN(ctx, gvpnName) + if err != nil { + return err + } + + if gv.KloudliteDevice.Name == "" { + return nil + } + + gvpnConns, err := d.listGlobalVPNConnections(ctx, gvpnName) + if err != nil { + return err + } + + klDevice, err := d.findGlobalVPNDevice(ctx, gvpnName, gv.KloudliteDevice.Name) + if err != nil { + return err + } + + wgParams, deviceHosts, err := d.buildGlobalVPNDeviceWgBaseParams(ctx, gvpnConns, klDevice) + if err != nil { + return err + } + + deviceSvcHosts := make([]string, 0, len(deviceHosts)) + for k, v := range deviceHosts { + deviceSvcHosts = append(deviceSvcHosts, fmt.Sprintf("%s=%s", k, v)) + } + + wgParams.DNS = klDevice.IPAddr + wgParams.ListenPort = 31820 + + dnsServerArgs := make([]string, 0, len(gvpnConns)) + for _, gvpnConn := range gvpnConns { + if gvpnConn.Spec.GlobalIP != "" { + dnsServerArgs = append(dnsServerArgs, fmt.Sprintf("%s=%s:53", gvpnConn.Spec.DNSSuffix, gvpnConn.Spec.GlobalIP)) + } + } + + resourceName := fmt.Sprintf("kloudlite-device-%s", gv.Name) + resourceNamespace := accNs + selector := map[string]string{ + "app": resourceName, + } + + // wgEndpoint := d.env.KloudliteGlobalVPNDeviceHost + + gao, err := d.accountsSvc.GetAccount(ctx, string(ctx.UserId), ctx.AccountName) + if err != nil { + return errors.NewE(err) + } + + gwRegion, ok := d.env.AvailableKloudliteRegions[gao.KloudliteGatewayRegion] + if !ok { + return errors.Newf("invalid gateway region %q", gao.KloudliteGatewayRegion) + } + + wgEndpoint := gwRegion.PublicDNSHost + + c, err := k8s.RestConfigFromKubeConfig([]byte(gwRegion.Kubeconfig)) + if err != nil { + return errors.NewE(err) + } + + yc, err := kubectl.NewYAMLClient(c, kubectl.YAMLClientOpts{}) + if err != nil { + return errors.NewE(err) + } + + service := &corev1.Service{} + + wgSvcName := fmt.Sprintf("%s-wg", resourceName) + + svcBytes, err := templates.ParseBytes(svcTemplate, templates.GatewayServiceTemplateVars{ + Name: wgSvcName, + Namespace: resourceNamespace, + WireguardPort: wgParams.ListenPort, + Selector: selector, + }) + if err != nil { + return errors.NewE(err) + } + + if err := os.WriteFile("/tmp/svc.yml", svcBytes, 0o644); err != nil { + return errors.NewE(err) + } + + ctx2, cf := func() (context.Context, context.CancelFunc) { + if d.env.IsDev { + return context.WithCancel(ctx) + } + return context.WithTimeout(ctx, 5*time.Second) + }() + defer cf() + + for { + if ctx2.Err() != nil { + return ctx2.Err() + } + service, err = yc.Client().CoreV1().Services(resourceNamespace).Get(ctx, wgSvcName, metav1.GetOptions{}) + if err != nil { + if !apiErrors.IsNotFound(err) { + return err + } + if _, err := yc.ApplyYAML(ctx, svcBytes); err != nil { + return errors.NewE(err) + } + continue + } + + if service.Spec.Ports[0].NodePort != 0 { + wgEndpoint = fmt.Sprintf("%s:%d", wgEndpoint, service.Spec.Ports[0].NodePort) + break + } + } + + if _, err := d.gvpnDevicesRepo.PatchById(ctx, klDevice.Id, repos.Document{ + fc.GlobalVPNDevicePublicEndpoint: wgEndpoint, + }); err != nil { + return err + } + + wgConfig, err := wgutils.GenerateWireguardConfig(*wgParams) + if err != nil { + return err + } + + deploymentBytes, err := templates.ParseBytes(b, templates.GVPNKloudliteDeviceTemplateVars{ + Name: resourceName, + Namespace: accNs, + WgConfig: wgConfig, + KubeReverseProxyImage: d.env.GlobalVPNKubeReverseProxyImage, + AuthzToken: d.env.GlobalVPNKubeReverseProxyAuthzToken, + GatewayDNSServers: strings.Join(dnsServerArgs, ","), + GatewayServiceHosts: strings.Join(deviceSvcHosts, ","), + WireguardPort: wgParams.ListenPort, + }) + if err != nil { + return err + } + + if _, err := yc.ApplyYAML(ctx, deploymentBytes); err != nil { + return errors.NewE(err) + } + + return nil +} + /* syncKloudliteDeviceOnCluster: - creates a specific device for each global VPN reserved for kloudlite internal use diff --git a/apps/infra/internal/domain/global-vpn-cluster-connection.go b/apps/infra/internal/domain/global-vpn-cluster-connection.go index 9e90a31fe..9a2326fef 100644 --- a/apps/infra/internal/domain/global-vpn-cluster-connection.go +++ b/apps/infra/internal/domain/global-vpn-cluster-connection.go @@ -229,6 +229,19 @@ func (d *domain) claimNextClusterCIDR(ctx InfraContext, clusterName string, gvpn cidr := freeCIDR.ClusterSvcCIDR + claimed, err := d.claimClusterSvcCIDRRepo.FindOne(ctx, repos.Filter{ + fc.AccountName: ctx.AccountName, + fc.ClaimClusterSvcCIDRGlobalVPNName: gvpnName, + fc.ClaimClusterSvcCIDRClaimedByCluster: clusterName, + }) + if err != nil { + return "", err + } + + if claimed != nil { + return claimed.ClusterSvcCIDR, nil + } + if _, err := d.claimClusterSvcCIDRRepo.Create(ctx, &entities.ClaimClusterSvcCIDR{ AccountName: ctx.AccountName, GlobalVPNName: gvpnName, @@ -503,7 +516,12 @@ func (d *domain) OnGlobalVPNConnectionUpdateMessage(ctx InfraContext, clusterNam return errors.NewE(err) } - if err := d.syncKloudliteDeviceOnCluster(ctx, xconn.GlobalVPNName); err != nil { + // FIXME: move to sync kloudlite gateway + // if err := d.syncKloudliteDeviceOnCluster(ctx, xconn.GlobalVPNName); err != nil { + // return errors.NewE(err) + // } + + if err := d.syncKloudliteGateway(ctx, xconn.GlobalVPNName); err != nil { return errors.NewE(err) } diff --git a/apps/infra/internal/domain/global-vpn-devices.go b/apps/infra/internal/domain/global-vpn-devices.go index 33a2ec265..3299ec2e8 100644 --- a/apps/infra/internal/domain/global-vpn-devices.go +++ b/apps/infra/internal/domain/global-vpn-devices.go @@ -60,6 +60,19 @@ func (d *domain) claimNextFreeDeviceIP(ctx InfraContext, deviceName string, gvpn ipAddr := freeIp.IPAddr + claimed, err := d.claimDeviceIPRepo.FindOne(ctx, repos.Filter{ + fc.AccountName: ctx.AccountName, + fc.ClaimDeviceIPGlobalVPNName: gvpnName, + fc.ClaimDeviceIPClaimedBy: deviceName, + }) + if err != nil { + return "", err + } + + if claimed != nil { + return claimed.IPAddr, nil + } + if _, err := d.claimDeviceIPRepo.Create(ctx, &entities.ClaimDeviceIP{ AccountName: ctx.AccountName, GlobalVPNName: gvpnName, @@ -118,7 +131,11 @@ func (d *domain) deleteGlobalVPNDevice(ctx InfraContext, gvpn string, deviceName return err } - if err := d.syncKloudliteDeviceOnCluster(ctx, gvpn); err != nil { + // if err := d.syncKloudliteDeviceOnCluster(ctx, gvpn); err != nil { + // return err + // } + + if err := d.syncKloudliteGateway(ctx, gvpn); err != nil { return err } @@ -136,6 +153,10 @@ func (d *domain) ListGlobalVPNDevice(ctx InfraContext, gvpn string, search map[s fc.GlobalVPNDeviceGlobalVPNName: gvpn, }, map[string]repos.MatchFilter{ + fc.CreatedByUserId: { + MatchType: repos.MatchTypeExact, + Exact: ctx.UserId, + }, fc.GlobalVPNDeviceCreationMethod: { MatchType: repos.MatchTypeNotInArray, NotInArray: []any{gvpnConnectionDeviceMethod, kloudliteGlobalVPNDevice}, @@ -174,12 +195,20 @@ func (d *domain) createGlobalVPNDevice(ctx InfraContext, gvpnDevice entities.Glo gvpnDevice.IPAddr = ip - gv, err := d.gvpnDevicesRepo.Create(ctx, &gvpnDevice) + gv, err := d.gvpnDevicesRepo.Upsert(ctx, repos.Filter{ + fc.AccountName: ctx.AccountName, + fc.GlobalVPNDeviceGlobalVPNName: gvpnDevice.GlobalVPNName, + fc.MetadataName: gvpnDevice.Name, + }, &gvpnDevice) if err != nil { return nil, err } - if err := d.syncKloudliteDeviceOnCluster(ctx, gvpnDevice.GlobalVPNName); err != nil { + // if err := d.syncKloudliteDeviceOnCluster(ctx, gvpnDevice.GlobalVPNName); err != nil { + // return nil, err + // } + + if err := d.syncKloudliteGateway(ctx, gvpnDevice.GlobalVPNName); err != nil { return nil, err } diff --git a/apps/infra/internal/domain/global-vpn.go b/apps/infra/internal/domain/global-vpn.go index b7c4bee27..3222d8a53 100644 --- a/apps/infra/internal/domain/global-vpn.go +++ b/apps/infra/internal/domain/global-vpn.go @@ -39,7 +39,7 @@ func (d *domain) createGlobalVPN(ctx InfraContext, gvpn entities.GlobalVPN) (*en numIPsPerCluster := int(math.Pow(2, float64(32-gvpn.AllocatableCIDRSuffix))) ipv4StartingAddr, err := iputils.GenIPAddr(gvpn.CIDR, i*numIPsPerCluster) if err != nil { - return nil, err + break } gvpn.NonClusterUseAllowedIPs = append(gvpn.NonClusterUseAllowedIPs, fmt.Sprintf("%s/%d", ipv4StartingAddr, gvpn.AllocatableCIDRSuffix)) } diff --git a/apps/infra/internal/domain/templates/embed.go b/apps/infra/internal/domain/templates/embed.go index 1f520eeec..1f846663a 100644 --- a/apps/infra/internal/domain/templates/embed.go +++ b/apps/infra/internal/domain/templates/embed.go @@ -15,6 +15,7 @@ type templateFile string const ( HelmKloudliteAgent templateFile = "./helm-charts-kloudlite-agent.yml.tpl" GlobalVPNKloudliteDeviceTemplate templateFile = "./global-vpn-kloudlite-device.yml.tpl" + GatewayServiceTemplate templateFile = "./kloudlite-gateway-svc.yml.tpl" ) func Read(t templateFile) ([]byte, error) { diff --git a/apps/infra/internal/domain/templates/global-vpn-kloudlite-device.yml.tpl b/apps/infra/internal/domain/templates/global-vpn-kloudlite-device.yml.tpl index 43ff48e2e..2414dcd41 100644 --- a/apps/infra/internal/domain/templates/global-vpn-kloudlite-device.yml.tpl +++ b/apps/infra/internal/domain/templates/global-vpn-kloudlite-device.yml.tpl @@ -77,21 +77,20 @@ spec: containers: - name: kube-reverse-proxy image: {{.KubeReverseProxyImage}} + imagePullPolicy: "Always" args: - --addr - ":8080" - --proxy-addr - - {{ printf "kubectl-proxy.kloudlite.svc.{{.CLUSTER_NAME}}.local:8080" }} + - {{ printf "pod-logs-proxy.kl-gateway.svc.{{.CLUSTER_NAME}}.local:8383" }} - "--authz" - {{.AuthzToken}} - imagePullPolicy: "IfNotPresent" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 100m - memory: 100Mi {{- if $isDebug }} diff --git a/apps/infra/internal/domain/templates/kloudlite-gateway-svc.yml.tpl b/apps/infra/internal/domain/templates/kloudlite-gateway-svc.yml.tpl new file mode 100644 index 000000000..3961e08f0 --- /dev/null +++ b/apps/infra/internal/domain/templates/kloudlite-gateway-svc.yml.tpl @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{.Namespace |squote}} + labels: + kloudlite.io/description: "kl-gateway-namespace" +--- +apiVersion: v1 +kind: Service +metadata: + name: "{{.Name}}" + namespace: "{{.Namespace}}" + labels: + app: {{.Name}} +spec: + type: NodePort + ports: + - name: wireguard + protocol: UDP + port: {{.WireguardPort}} + targetPort: {{.WireguardPort}} + selector: {{.Selector | toYAML | nindent 4 }} diff --git a/apps/infra/internal/domain/templates/types.go b/apps/infra/internal/domain/templates/types.go index 230cee202..fabd09be4 100644 --- a/apps/infra/internal/domain/templates/types.go +++ b/apps/infra/internal/domain/templates/types.go @@ -12,3 +12,10 @@ type GVPNKloudliteDeviceTemplateVars struct { GatewayDNSServers string GatewayServiceHosts string } + +type GatewayServiceTemplateVars struct { + Name string + Namespace string + WireguardPort uint16 + Selector map[string]string +} diff --git a/apps/infra/internal/env/env.go b/apps/infra/internal/env/env.go index 5ca3c1b60..c4cd01060 100644 --- a/apps/infra/internal/env/env.go +++ b/apps/infra/internal/env/env.go @@ -1,8 +1,12 @@ package env import ( + "io" + "os" + "github.com/codingconcepts/env" "github.com/kloudlite/api/pkg/errors" + "sigs.k8s.io/yaml" ) type Env struct { @@ -59,6 +63,18 @@ type Env struct { GlobalVPNKubeReverseProxyAuthzToken string `env:"GLOBAL_VPN_KUBE_REVERSE_PROXY_AUTHZ_TOKEN" required:"true"` KloudliteGlobalVPNDeviceHost string `env:"KLOUDLITE_GLOBAL_VPN_DEVICE_HOST" required:"true"` + + AvailableKloudliteRegionsConfig string `env:"AVAILABLE_KLOUDLITE_REGIONS_CONFIG" required:"false"` + AvailableKloudliteRegions map[string]AvailableKloudliteRegion +} + +type AvailableKloudliteRegion struct { + ID string `json:"id"` + DisplayName string `json:"displayName"` + Region string `json:"region"` + CloudProvider string `json:"cloudProvider"` + Kubeconfig string `json:"kubeconfig"` + PublicDNSHost string `json:"publicDNSHost"` } func LoadEnv() (*Env, error) { @@ -66,5 +82,24 @@ func LoadEnv() (*Env, error) { if err := env.Set(&ev); err != nil { return nil, errors.NewE(err) } + if ev.AvailableKloudliteRegionsConfig != "" { + f, err := os.Open(ev.AvailableKloudliteRegionsConfig) + if err != nil { + return nil, err + } + b, err := io.ReadAll(f) + if err != nil { + return nil, err + } + + var regions []AvailableKloudliteRegion + if err := yaml.Unmarshal(b, ®ions); err != nil { + return nil, err + } + ev.AvailableKloudliteRegions = make(map[string]AvailableKloudliteRegion, len(regions)) + for i := range regions { + ev.AvailableKloudliteRegions[regions[i].ID] = regions[i] + } + } return &ev, nil } diff --git a/go.mod b/go.mod index 484dba6ce..113437762 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,7 @@ require ( ) require ( + github.com/go-chi/chi/v5 v5.0.10 github.com/kloudlite/container-registry-authorizer v0.0.0-20231021122509-161dc30fde55 github.com/nats-io/nats.go v1.31.0 github.com/onsi/ginkgo/v2 v2.12.0 diff --git a/go.sum b/go.sum index 7d895aa44..50cdd4b80 100644 --- a/go.sum +++ b/go.sum @@ -63,6 +63,8 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3 github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= diff --git a/pkg/wgutils/peer-config.go b/pkg/wgutils/peer-config.go index 27e21ad40..c9263778d 100644 --- a/pkg/wgutils/peer-config.go +++ b/pkg/wgutils/peer-config.go @@ -67,7 +67,9 @@ PostDown = {{.}} {{- end }} PublicKey = {{.PublicKey}} AllowedIPs = {{.AllowedIPs | join ", " }} +{{- if .Endpoint }} Endpoint = {{.Endpoint}} +{{- end }} PersistentKeepalive = 25 {{- end }} {{- end }} From dcbf88fcccaa7f6168cf0450eed3e83c2542f81f Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Sat, 22 Jun 2024 13:57:17 +0530 Subject: [PATCH 4/9] feat(infra): external gateway for vpn devices - we also have an internal gateway for vpn devices, which we use to stream logs from the vpn devices - also adds a local DNS query `account.kloudlite.local` to allow cli tool to get the account for the current gateway --- apps/infra/internal/domain/clusters.go | 102 +++++++++++------- .../domain/global-vpn-cluster-connection.go | 24 +++-- .../internal/domain/global-vpn-devices.go | 29 ++--- apps/infra/internal/domain/global-vpn.go | 28 ++++- .../global-vpn-kloudlite-device.yml.tpl | 21 ++-- apps/infra/internal/domain/templates/types.go | 3 + .../field-constants/generated_constants.go | 25 +++-- apps/infra/internal/entities/global-vpn.go | 10 +- cmd/gateway-kube-proxy/main.go | 2 +- 9 files changed, 164 insertions(+), 80 deletions(-) diff --git a/apps/infra/internal/domain/clusters.go b/apps/infra/internal/domain/clusters.go index eb32db73e..c136a4b27 100644 --- a/apps/infra/internal/domain/clusters.go +++ b/apps/infra/internal/domain/clusters.go @@ -5,7 +5,6 @@ import ( "encoding/base64" "encoding/json" "fmt" - "os" "strings" "time" @@ -34,7 +33,6 @@ import ( corev1 "k8s.io/api/core/v1" apiErrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" ) const ( @@ -377,7 +375,7 @@ func (d *domain) CreateCluster(ctx InfraContext, cluster entities.Cluster) (*ent return nCluster, nil } -func (d *domain) syncKloudliteGateway(ctx InfraContext, gvpnName string) error { +func (d *domain) syncKloudliteGatewayDevice(ctx InfraContext, gvpnName string) error { // 1. parse deployment template b, err := templates.Read(templates.GlobalVPNKloudliteDeviceTemplate) if err != nil { @@ -399,7 +397,7 @@ func (d *domain) syncKloudliteGateway(ctx InfraContext, gvpnName string) error { return err } - if gv.KloudliteDevice.Name == "" { + if gv.KloudliteGatewayDevice.Name == "" { return nil } @@ -408,7 +406,12 @@ func (d *domain) syncKloudliteGateway(ctx InfraContext, gvpnName string) error { return err } - klDevice, err := d.findGlobalVPNDevice(ctx, gvpnName, gv.KloudliteDevice.Name) + klDevice, err := d.findGlobalVPNDevice(ctx, gvpnName, gv.KloudliteGatewayDevice.Name) + if err != nil { + return err + } + + clDevice, err := d.findGlobalVPNDevice(ctx, gvpnName, gv.KloudliteClusterLocalDevice.Name) if err != nil { return err } @@ -418,11 +421,20 @@ func (d *domain) syncKloudliteGateway(ctx InfraContext, gvpnName string) error { return err } + publicPeers := make([]wgutils.PublicPeer, 0, len(wgParams.PublicPeers)) + for _, p := range wgParams.PublicPeers { + if p.PublicKey != clDevice.PublicKey { + publicPeers = append(publicPeers, p) + } + } + + deviceSvcHosts := make([]string, 0, len(deviceHosts)) for k, v := range deviceHosts { deviceSvcHosts = append(deviceSvcHosts, fmt.Sprintf("%s=%s", k, v)) } + wgParams.PublicPeers = publicPeers wgParams.DNS = klDevice.IPAddr wgParams.ListenPort = 31820 @@ -477,10 +489,6 @@ func (d *domain) syncKloudliteGateway(ctx InfraContext, gvpnName string) error { return errors.NewE(err) } - if err := os.WriteFile("/tmp/svc.yml", svcBytes, 0o644); err != nil { - return errors.NewE(err) - } - ctx2, cf := func() (context.Context, context.CancelFunc) { if d.env.IsDev { return context.WithCancel(ctx) @@ -525,11 +533,14 @@ func (d *domain) syncKloudliteGateway(ctx InfraContext, gvpnName string) error { Name: resourceName, Namespace: accNs, WgConfig: wgConfig, + EnableKubeReverseProxy: false, KubeReverseProxyImage: d.env.GlobalVPNKubeReverseProxyImage, AuthzToken: d.env.GlobalVPNKubeReverseProxyAuthzToken, GatewayDNSServers: strings.Join(dnsServerArgs, ","), GatewayServiceHosts: strings.Join(deviceSvcHosts, ","), WireguardPort: wgParams.ListenPort, + + KloudliteAccount: gv.AccountName, }) if err != nil { return err @@ -543,17 +554,23 @@ func (d *domain) syncKloudliteGateway(ctx InfraContext, gvpnName string) error { } /* -syncKloudliteDeviceOnCluster: +syncKloudliteDeviceOnPlatform: - creates a specific device for each global VPN reserved for kloudlite internal use - need to use that device as a kube-proxy to all the clusters - we can read their logs, and everything on demand */ -func (d *domain) syncKloudliteDeviceOnCluster(ctx InfraContext, gvpnName string) error { +func (d *domain) syncKloudliteDeviceOnPlatform(ctx InfraContext, gvpnName string) error { // 1. parse deployment template b, err := templates.Read(templates.GlobalVPNKloudliteDeviceTemplate) if err != nil { return errors.NewE(err) } + + svcTemplate, err := templates.Read(templates.GatewayServiceTemplate) + if err != nil { + return errors.NewE(err) + } + accNs, err := d.getAccNamespace(ctx) if err != nil { return errors.NewE(err) @@ -564,7 +581,7 @@ func (d *domain) syncKloudliteDeviceOnCluster(ctx InfraContext, gvpnName string) return err } - if gv.KloudliteDevice.Name == "" { + if gv.KloudliteClusterLocalDevice.Name == "" { return nil } @@ -573,22 +590,36 @@ func (d *domain) syncKloudliteDeviceOnCluster(ctx InfraContext, gvpnName string) return err } - klDevice, err := d.findGlobalVPNDevice(ctx, gvpnName, gv.KloudliteDevice.Name) + clDevice, err := d.findGlobalVPNDevice(ctx, gvpnName, gv.KloudliteClusterLocalDevice.Name) if err != nil { return err } - wgParams, deviceHosts, err := d.buildGlobalVPNDeviceWgBaseParams(ctx, gvpnConns, klDevice) + + wgParams, deviceHosts, err := d.buildGlobalVPNDeviceWgBaseParams(ctx, gvpnConns, clDevice) + if err != nil { + return err + } + + klDevice, err := d.findGlobalVPNDevice(ctx, gvpnName, gv.KloudliteGatewayDevice.Name) if err != nil { return err } + publicPeers := make([]wgutils.PublicPeer, 0, len(wgParams.PublicPeers)) + for _, p := range wgParams.PublicPeers { + if p.PublicKey != klDevice.PublicKey { + publicPeers = append(publicPeers, p) + } + } + deviceSvcHosts := make([]string, 0, len(deviceHosts)) for k, v := range deviceHosts { deviceSvcHosts = append(deviceSvcHosts, fmt.Sprintf("%s=%s", k, v)) } - wgParams.DNS = klDevice.IPAddr + wgParams.PublicPeers = publicPeers + wgParams.DNS = clDevice.IPAddr wgParams.ListenPort = 31820 dnsServerArgs := make([]string, 0, len(gvpnConns)) @@ -610,34 +641,30 @@ func (d *domain) syncKloudliteDeviceOnCluster(ctx InfraContext, gvpnName string) wgEndpoint := d.env.KloudliteGlobalVPNDeviceHost + wgSvcName := fmt.Sprintf("%s-wg", resourceName) + svcBytes, err := templates.ParseBytes(svcTemplate, templates.GatewayServiceTemplateVars{ + Name: wgSvcName, + Namespace: resourceNamespace, + WireguardPort: wgParams.ListenPort, + Selector: selector, + }) + if err != nil { + return errors.NewE(err) + } + for { if ctx2.Err() != nil { return ctx2.Err() } - if err := d.k8sClient.Get(ctx, fn.NN(resourceNamespace, fmt.Sprintf("%s-wg", resourceName)), service); err != nil { + if err := d.k8sClient.Get(ctx, fn.NN(resourceNamespace, wgSvcName), service); err != nil { if !apiErrors.IsNotFound(err) { return err } - if err := d.k8sClient.Create(ctx, &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-wg", resourceName), - Namespace: resourceNamespace, - }, - Spec: corev1.ServiceSpec{ - Type: corev1.ServiceTypeNodePort, - Ports: []corev1.ServicePort{ - { - Name: "wireguard", - Protocol: corev1.ProtocolUDP, - Port: int32(wgParams.ListenPort), - TargetPort: intstr.FromInt(int(wgParams.ListenPort)), - }, - }, - Selector: selector, - }, - }); err != nil { - return err + + if err := d.k8sClient.ApplyYAML(ctx, svcBytes); err != nil { + return errors.NewE(err) } + continue } @@ -647,7 +674,7 @@ func (d *domain) syncKloudliteDeviceOnCluster(ctx InfraContext, gvpnName string) } } - if _, err := d.gvpnDevicesRepo.PatchById(ctx, klDevice.Id, repos.Document{ + if _, err := d.gvpnDevicesRepo.PatchById(ctx, clDevice.Id, repos.Document{ fc.GlobalVPNDevicePublicEndpoint: wgEndpoint, }); err != nil { return err @@ -662,11 +689,14 @@ func (d *domain) syncKloudliteDeviceOnCluster(ctx InfraContext, gvpnName string) Name: resourceName, Namespace: accNs, WgConfig: wgConfig, + EnableKubeReverseProxy: true, KubeReverseProxyImage: d.env.GlobalVPNKubeReverseProxyImage, AuthzToken: d.env.GlobalVPNKubeReverseProxyAuthzToken, GatewayDNSServers: strings.Join(dnsServerArgs, ","), GatewayServiceHosts: strings.Join(deviceSvcHosts, ","), WireguardPort: wgParams.ListenPort, + + KloudliteAccount: gv.AccountName, }) if err != nil { return err diff --git a/apps/infra/internal/domain/global-vpn-cluster-connection.go b/apps/infra/internal/domain/global-vpn-cluster-connection.go index 9a2326fef..b45c20b48 100644 --- a/apps/infra/internal/domain/global-vpn-cluster-connection.go +++ b/apps/infra/internal/domain/global-vpn-cluster-connection.go @@ -118,13 +118,20 @@ func (d *domain) reconGlobalVPNConnections(ctx InfraContext, vpnName string) err return errors.NewE(err) } - klDevice, err := d.findGlobalVPNDevice(ctx, gvpn.Name, gvpn.KloudliteDevice.Name) + klDevice, err := d.findGlobalVPNDevice(ctx, gvpn.Name, gvpn.KloudliteGatewayDevice.Name) if err != nil { - return errors.NewEf(err, "failed to find kloudlite device %s", gvpn.KloudliteDevice.Name) + return errors.NewEf(err, "failed to find kloudlite device %s", gvpn.KloudliteGatewayDevice.Name) } klDevicePeer := d.buildPeerFromGlobalVPNDevice(ctx, gvpn, klDevice) + clDevice, err := d.findGlobalVPNDevice(ctx, gvpn.Name, gvpn.KloudliteClusterLocalDevice.Name) + if err != nil { + return errors.NewEf(err, "failed to find kloudlite device %s", gvpn.KloudliteClusterLocalDevice.Name) + } + + clDevicePeer := d.buildPeerFromGlobalVPNDevice(ctx, gvpn, clDevice) + // INFO: all private cluster gateway peers, are supposed to be routed via kloudlite gateway for _, c := range gvpnConns { if c.Visibility.Mode == entities.ClusterVisibilityModePrivate { @@ -149,9 +156,9 @@ func (d *domain) reconGlobalVPNConnections(ctx InfraContext, vpnName string) err OnlyPublicClusters: true, }) - peers = append(peers, *klDevicePeer) + peers = append(peers, *klDevicePeer, *clDevicePeer) if xcc.Visibility.Mode == entities.ClusterVisibilityModePrivate { - peers = []networkingv1.Peer{*klDevicePeer} + peers = []networkingv1.Peer{*klDevicePeer, *clDevicePeer} peers[0].AllowedIPs = append(peers[0].AllowedIPs, publicAllowedIPs...) } @@ -516,12 +523,11 @@ func (d *domain) OnGlobalVPNConnectionUpdateMessage(ctx InfraContext, clusterNam return errors.NewE(err) } - // FIXME: move to sync kloudlite gateway - // if err := d.syncKloudliteDeviceOnCluster(ctx, xconn.GlobalVPNName); err != nil { - // return errors.NewE(err) - // } + if err := d.syncKloudliteDeviceOnPlatform(ctx, xconn.GlobalVPNName); err != nil { + return errors.NewE(err) + } - if err := d.syncKloudliteGateway(ctx, xconn.GlobalVPNName); err != nil { + if err := d.syncKloudliteGatewayDevice(ctx, xconn.GlobalVPNName); err != nil { return errors.NewE(err) } diff --git a/apps/infra/internal/domain/global-vpn-devices.go b/apps/infra/internal/domain/global-vpn-devices.go index 3299ec2e8..817f40ba9 100644 --- a/apps/infra/internal/domain/global-vpn-devices.go +++ b/apps/infra/internal/domain/global-vpn-devices.go @@ -19,6 +19,7 @@ import ( func (d *domain) claimNextFreeDeviceIP(ctx InfraContext, deviceName string, gvpnName string) (string, error) { var ipAddrFilter *repos.MatchFilter + offsetIdx := 0 for { filter := repos.Filter{ fields.AccountName: ctx.AccountName, @@ -38,7 +39,7 @@ func (d *domain) claimNextFreeDeviceIP(ctx InfraContext, deviceName string, gvpn return "", err } - ip, err := iputils.GetIPAddrInARange(gvpn.CIDR, gvpn.NumAllocatedDevices+1, gvpn.NumReservedIPsForNonClusterUse) + ip, err := iputils.GetIPAddrInARange(gvpn.CIDR, gvpn.NumAllocatedDevices+1+offsetIdx, gvpn.NumReservedIPsForNonClusterUse) if err != nil { return "", err } @@ -48,6 +49,7 @@ func (d *domain) claimNextFreeDeviceIP(ctx InfraContext, deviceName string, gvpn GlobalVPNName: gvpnName, IPAddr: ip, }); err != nil { + offsetIdx += 1 continue } @@ -131,11 +133,11 @@ func (d *domain) deleteGlobalVPNDevice(ctx InfraContext, gvpn string, deviceName return err } - // if err := d.syncKloudliteDeviceOnCluster(ctx, gvpn); err != nil { - // return err - // } + if err := d.syncKloudliteDeviceOnPlatform(ctx, gvpn); err != nil { + return err + } - if err := d.syncKloudliteGateway(ctx, gvpn); err != nil { + if err := d.syncKloudliteGatewayDevice(ctx, gvpn); err != nil { return err } @@ -204,11 +206,11 @@ func (d *domain) createGlobalVPNDevice(ctx InfraContext, gvpnDevice entities.Glo return nil, err } - // if err := d.syncKloudliteDeviceOnCluster(ctx, gvpnDevice.GlobalVPNName); err != nil { - // return nil, err - // } + if err := d.syncKloudliteDeviceOnPlatform(ctx, gvpnDevice.GlobalVPNName); err != nil { + return nil, err + } - if err := d.syncKloudliteGateway(ctx, gvpnDevice.GlobalVPNName); err != nil { + if err := d.syncKloudliteGatewayDevice(ctx, gvpnDevice.GlobalVPNName); err != nil { return nil, err } @@ -218,7 +220,7 @@ func (d *domain) createGlobalVPNDevice(ctx InfraContext, gvpnDevice entities.Glo func (d *domain) buildPeerFromGlobalVPNDevice(ctx InfraContext, gvpn *entities.GlobalVPN, device *entities.GlobalVPNDevice) *networkingv1.Peer { allowedIPs := []string{fmt.Sprintf("%s/32", device.IPAddr)} - if device.CreationMethod == kloudliteGlobalVPNDevice { + if device.IPAddr == gvpn.KloudliteGatewayDevice.IPAddr { allowedIPs = append(allowedIPs, gvpn.NonClusterUseAllowedIPs...) } @@ -258,7 +260,8 @@ func (d *domain) buildPeersFromGlobalVPNDevices(ctx InfraContext, gvpn string) ( allowedIPs := []string{fmt.Sprintf("%s/32", devices[i].IPAddr)} if devices[i].PublicEndpoint != nil { allowedIPs := []string{fmt.Sprintf("%s/32", devices[i].IPAddr)} - if devices[i].CreationMethod == kloudliteGlobalVPNDevice { + + if devices[i].Name == gv.KloudliteGatewayDevice.Name { allowedIPs = append(allowedIPs, gv.NonClusterUseAllowedIPs...) } @@ -363,7 +366,7 @@ func (d *domain) getGlobalVPNDeviceWgConfig(ctx InfraContext, gvpn string, gvpnD return "", err } - klDevice, err := d.findGlobalVPNDevice(ctx, gvpn, gv.KloudliteDevice.Name) + klDevice, err := d.findGlobalVPNDevice(ctx, gvpn, gv.KloudliteGatewayDevice.Name) if err != nil { return "", err } @@ -375,7 +378,7 @@ func (d *domain) getGlobalVPNDeviceWgConfig(ctx InfraContext, gvpn string, gvpnD config, err := wgutils.GenerateWireguardConfig(wgutils.WgConfigParams{ IPAddr: device.IPAddr, PrivateKey: device.PrivateKey, - DNS: gv.KloudliteDevice.IPAddr, + DNS: gv.KloudliteGatewayDevice.IPAddr, PostUp: postUp, PublicPeers: []wgutils.PublicPeer{ { diff --git a/apps/infra/internal/domain/global-vpn.go b/apps/infra/internal/domain/global-vpn.go index 3222d8a53..d5b9e0b8b 100644 --- a/apps/infra/internal/domain/global-vpn.go +++ b/apps/infra/internal/domain/global-vpn.go @@ -20,7 +20,8 @@ func (d *domain) CreateGlobalVPN(ctx InfraContext, gvpn entities.GlobalVPN) (*en } const ( - kloudliteGlobalVPNDevice = "kloudlite-global-vpn-device" + kloudliteGlobalVPNDevice = "kloudlite-global-vpn-device" + kloudliteClusterLocalGlobalVPNDevice = "kloudlite-cluster-local-device" ) func (d *domain) createGlobalVPN(ctx InfraContext, gvpn entities.GlobalVPN) (*entities.GlobalVPN, error) { @@ -72,7 +73,30 @@ func (d *domain) createGlobalVPN(ctx InfraContext, gvpn entities.GlobalVPN) (*en return nil, err } - return d.gvpnRepo.PatchById(ctx, gv.Id, repos.Document{fc.GlobalVPNKloudliteDeviceName: device.Name, fc.GlobalVPNKloudliteDeviceIpAddr: device.IPAddr}) + clDevice, err := d.createGlobalVPNDevice(ctx, entities.GlobalVPNDevice{ + ObjectMeta: metav1.ObjectMeta{ + Name: kloudliteClusterLocalGlobalVPNDevice, + }, + ResourceMetadata: common.ResourceMetadata{ + DisplayName: kloudliteGlobalVPNDevice, + CreatedBy: common.CreatedOrUpdatedByKloudlite, + LastUpdatedBy: common.CreatedOrUpdatedByKloudlite, + }, + AccountName: ctx.AccountName, + GlobalVPNName: gv.Name, + PublicEndpoint: nil, + CreationMethod: kloudliteGlobalVPNDevice, + }) + if err != nil { + return nil, err + } + + return d.gvpnRepo.PatchById(ctx, gv.Id, repos.Document{ + fc.GlobalVPNKloudliteGatewayDeviceName: device.Name, + fc.GlobalVPNKloudliteGatewayDeviceIpAddr: device.IPAddr, + fc.GlobalVPNKloudliteClusterLocalDeviceName: clDevice.Name, + fc.GlobalVPNKloudliteClusterLocalDeviceIpAddr: clDevice.IPAddr, + }) } func (d *domain) ensureGlobalVPN(ctx InfraContext, gvpnName string) (*entities.GlobalVPN, error) { diff --git a/apps/infra/internal/domain/templates/global-vpn-kloudlite-device.yml.tpl b/apps/infra/internal/domain/templates/global-vpn-kloudlite-device.yml.tpl index 2414dcd41..9ec4fc615 100644 --- a/apps/infra/internal/domain/templates/global-vpn-kloudlite-device.yml.tpl +++ b/apps/infra/internal/domain/templates/global-vpn-kloudlite-device.yml.tpl @@ -66,6 +66,8 @@ spec: - |+ wg-quick down wg0 || echo "[starting] wg-quick down wg0" wg-quick up wg0 + echo "allowing time for ip addr to become available" + sleep 0.25 volumeMounts: - mountPath: /config/wg_confs/wg0.conf name: wg-config @@ -75,6 +77,7 @@ spec: {{- end }} containers: + {{- if .EnableKubeReverseProxy }} - name: kube-reverse-proxy image: {{.KubeReverseProxyImage}} imagePullPolicy: "Always" @@ -92,6 +95,7 @@ spec: requests: cpu: 100m memory: 100Mi + {{- end }} {{- if $isDebug }} - image: ghcr.io/kloudlite/hub/wireguard:latest @@ -139,6 +143,9 @@ spec: - --service-hosts - {{.GatewayServiceHosts}} + - --account + - {{.KloudliteAccount}} + - --debug imagePullPolicy: Always resources: @@ -149,13 +156,13 @@ spec: cpu: 100m memory: 100Mi - {{- /* securityContext: */}} - {{- /* capabilities: */}} - {{- /* add: */}} - {{- /* - NET_BIND_SERVICE */}} - {{- /* - SETGID */}} - {{- /* drop: */}} - {{- /* - all */}} + securityContext: + capabilities: + add: + - NET_BIND_SERVICE + - SETGID + drop: + - all dnsPolicy: ClusterFirst volumes: diff --git a/apps/infra/internal/domain/templates/types.go b/apps/infra/internal/domain/templates/types.go index fabd09be4..0bb89f946 100644 --- a/apps/infra/internal/domain/templates/types.go +++ b/apps/infra/internal/domain/templates/types.go @@ -6,6 +6,9 @@ type GVPNKloudliteDeviceTemplateVars struct { WgConfig string WireguardPort uint16 + KloudliteAccount string + + EnableKubeReverseProxy bool KubeReverseProxyImage string AuthzToken string diff --git a/apps/infra/internal/entities/field-constants/generated_constants.go b/apps/infra/internal/entities/field-constants/generated_constants.go index 25a960a60..9667bc8c9 100644 --- a/apps/infra/internal/entities/field-constants/generated_constants.go +++ b/apps/infra/internal/entities/field-constants/generated_constants.go @@ -222,16 +222,19 @@ const ( // constant vars generated for struct GlobalVPN const ( - GlobalVPNCIDR = "CIDR" - GlobalVPNAllocatableCIDRSuffix = "allocatableCIDRSuffix" - GlobalVPNKloudliteDevice = "kloudliteDevice" - GlobalVPNKloudliteDeviceIpAddr = "kloudliteDevice.ipAddr" - GlobalVPNKloudliteDeviceName = "kloudliteDevice.name" - GlobalVPNNonClusterUseAllowedIPs = "nonClusterUseAllowedIPs" - GlobalVPNNumAllocatedClusterCIDRs = "numAllocatedClusterCIDRs" - GlobalVPNNumAllocatedDevices = "numAllocatedDevices" - GlobalVPNNumReservedIPsForNonClusterUse = "numReservedIPsForNonClusterUse" - GlobalVPNWgInterface = "wgInterface" + GlobalVPNCIDR = "CIDR" + GlobalVPNAllocatableCIDRSuffix = "allocatableCIDRSuffix" + GlobalVPNKloudliteClusterLocalDevice = "kloudliteClusterLocalDevice" + GlobalVPNKloudliteClusterLocalDeviceIpAddr = "kloudliteClusterLocalDevice.ipAddr" + GlobalVPNKloudliteClusterLocalDeviceName = "kloudliteClusterLocalDevice.name" + GlobalVPNKloudliteGatewayDevice = "kloudliteGatewayDevice" + GlobalVPNKloudliteGatewayDeviceIpAddr = "kloudliteGatewayDevice.ipAddr" + GlobalVPNKloudliteGatewayDeviceName = "kloudliteGatewayDevice.name" + GlobalVPNNonClusterUseAllowedIPs = "nonClusterUseAllowedIPs" + GlobalVPNNumAllocatedClusterCIDRs = "numAllocatedClusterCIDRs" + GlobalVPNNumAllocatedDevices = "numAllocatedDevices" + GlobalVPNNumReservedIPsForNonClusterUse = "numReservedIPsForNonClusterUse" + GlobalVPNWgInterface = "wgInterface" ) // constant vars generated for struct GlobalVPNConnDeviceRef @@ -258,7 +261,9 @@ const ( GlobalVPNConnectionSpecLoadBalancer = "spec.loadBalancer" GlobalVPNConnectionSpecLoadBalancerHosts = "spec.loadBalancer.hosts" GlobalVPNConnectionSpecLoadBalancerPort = "spec.loadBalancer.port" + GlobalVPNConnectionSpecNodePort = "spec.nodePort" GlobalVPNConnectionSpecPeers = "spec.peers" + GlobalVPNConnectionSpecServiceType = "spec.serviceType" GlobalVPNConnectionSpecSvcCIDR = "spec.svcCIDR" GlobalVPNConnectionSpecWireguardKeysRef = "spec.wireguardKeysRef" GlobalVPNConnectionSpecWireguardKeysRefName = "spec.wireguardKeysRef.name" diff --git a/apps/infra/internal/entities/global-vpn.go b/apps/infra/internal/entities/global-vpn.go index aa6570015..66ce8031c 100644 --- a/apps/infra/internal/entities/global-vpn.go +++ b/apps/infra/internal/entities/global-vpn.go @@ -22,6 +22,7 @@ type GlobalVPN struct { // like 10.0.0.0/8 CIDR string `json:"CIDR"` + // to allocate 8K IPs for each GlobalVPNConnection // i.e. pow(2, 13) Ips, it means 13 Host bits, // which leaves us with (32 - 13) 19 Network Bits. It is our AllocatableCIDRSuffix @@ -41,10 +42,15 @@ type GlobalVPN struct { // Peers []Peer `json:"peers" graphql:"noinput"` AccountName string `json:"accountName" graphql:"noinput"` - KloudliteDevice struct { + KloudliteGatewayDevice struct { + Name string `json:"name"` + IPAddr string `json:"ipAddr"` + } `json:"kloudliteGatewayDevice"` + + KloudliteClusterLocalDevice struct { Name string `json:"name"` IPAddr string `json:"ipAddr"` - } `json:"kloudliteDevice"` + } `json:"kloudliteClusterLocalDevice"` } func (c *GlobalVPN) GetDisplayName() string { diff --git a/cmd/gateway-kube-proxy/main.go b/cmd/gateway-kube-proxy/main.go index 62bba92de..b325672ac 100644 --- a/cmd/gateway-kube-proxy/main.go +++ b/cmd/gateway-kube-proxy/main.go @@ -25,7 +25,7 @@ func main() { flag.Parse() if authz == "" { - panic("authz token is required") + panic("authz token is required, use --authz ") } logger := slog.Default() From 7abd22d46cde976e6e7ba6449c33be474bf3ae76 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Sun, 23 Jun 2024 19:19:13 +0530 Subject: [PATCH 5/9] ci: github actions with nix, and taskfile updates --- .github/actions/build-api-images/action.yml | 436 ++++++++++++++++++ .github/actions/setup-docker/action.yml | 28 ++ .github/actions/setup-nix-cachix/action.yml | 41 ++ .github/actions/setup-nix-github/action.yml | 28 ++ .tools/taskfiles/container-image-builder.yml | 15 - .tools/taskfiles/docker-builder.yml | 12 - .tools/taskfiles/docker.Taskfile.yml | 23 + .tools/taskfiles/go-build.Taskfile.yml | 26 ++ .tools/taskfiles/go-build.yml | 21 - apps/accounts/{Containerfile => Dockerfile} | 4 +- apps/accounts/Taskfile.yml | 28 +- apps/auth/{Containerfile => Dockerfile} | 4 +- apps/auth/Taskfile.yml | 26 +- apps/comms/{Containerfile => Dockerfile} | 4 +- apps/comms/Taskfile.yml | 28 +- apps/console/{Containerfile => Dockerfile} | 4 +- apps/console/Taskfile.yml | 40 +- .../{Containerfile => Dockerfile} | 4 +- apps/container-registry/Taskfile.yml | 31 +- apps/gateway/Dockerfile | 2 +- apps/gateway/Taskfile.yml | 27 +- apps/iam/Containerfile | 5 - apps/iam/Dockerfile | 28 +- apps/iam/Taskfile.yml | 26 +- apps/infra/{Containerfile => Dockerfile} | 4 +- apps/infra/Taskfile.yml | 31 +- .../iot-console/{Containerfile => Dockerfile} | 4 +- apps/iot-console/Taskfile.yml | 30 +- .../{Containerfile => Dockerfile} | 4 +- apps/message-office/Taskfile.yml | 28 +- apps/observability/Dockerfile | 4 +- apps/observability/Taskfile.yml | 41 +- apps/tenant-agent/Containerfile | 5 - apps/tenant-agent/Dockerfile | 31 +- apps/tenant-agent/Taskfile.yml | 50 +- apps/webhook/{Containerfile => Dockerfile} | 4 +- apps/webhook/Taskfile.yml | 28 +- .../{Containerfile => Dockerfile} | 4 +- apps/websocket-server/Taskfile.yml | 29 +- .../{Containerfile => Dockerfile} | 0 apps/worker-audit-logging/Taskfile.yml | 34 +- 41 files changed, 921 insertions(+), 301 deletions(-) create mode 100644 .github/actions/build-api-images/action.yml create mode 100644 .github/actions/setup-docker/action.yml create mode 100644 .github/actions/setup-nix-cachix/action.yml create mode 100644 .github/actions/setup-nix-github/action.yml delete mode 100644 .tools/taskfiles/container-image-builder.yml delete mode 100644 .tools/taskfiles/docker-builder.yml create mode 100644 .tools/taskfiles/docker.Taskfile.yml create mode 100644 .tools/taskfiles/go-build.Taskfile.yml delete mode 100644 .tools/taskfiles/go-build.yml rename apps/accounts/{Containerfile => Dockerfile} (62%) rename apps/auth/{Containerfile => Dockerfile} (59%) rename apps/comms/{Containerfile => Dockerfile} (62%) rename apps/console/{Containerfile => Dockerfile} (58%) rename apps/container-registry/{Containerfile => Dockerfile} (61%) delete mode 100644 apps/iam/Containerfile rename apps/infra/{Containerfile => Dockerfile} (57%) rename apps/iot-console/{Containerfile => Dockerfile} (57%) rename apps/message-office/{Containerfile => Dockerfile} (58%) delete mode 100644 apps/tenant-agent/Containerfile rename apps/webhook/{Containerfile => Dockerfile} (58%) rename apps/websocket-server/{Containerfile => Dockerfile} (61%) rename apps/worker-audit-logging/{Containerfile => Dockerfile} (100%) diff --git a/.github/actions/build-api-images/action.yml b/.github/actions/build-api-images/action.yml new file mode 100644 index 000000000..4a4f3a309 --- /dev/null +++ b/.github/actions/build-api-images/action.yml @@ -0,0 +1,436 @@ +name: 'build kloudlite api action' +description: 'builds kloudlite APIs' + +inputs: + github_token: + description: 'GitHub Token' + required: true + + cachix_enabled: + description: "cachix enabled" + default: "false" + + cachix_cache_name: + description: "cachix cache name" + default: "kloudlite" + + cachix_auth_token: + description: "cachix auth token" + + docker_enabled: + description: "dokcer enabled" + default: "false" + + git_directory: + description: 'git directory' + default: "." + + cache_prefix: + description: 'cache prefix' + default: "" + + go_mod_download: + description: 'go mod download' + default: false + + # APIs + accounts-api: + description: 'build accounts api' + default: false + + auth-api: + description: 'build auth api' + default: false + + comms-api: + description: 'build comms api' + default: false + + console-api: + description: 'build console api' + default: false + + container-registry-api: + description: 'build container-registry api' + default: false + + gateway-api: + description: 'build gateway api' + default: false + + iam-api: + description: 'build iam api' + default: false + + infra-api: + description: 'build infra api' + default: false + + iot-console-api: + description: 'build iot-console api' + default: false + + message-office-api: + description: 'build message-office api' + default: false + + observability-api: + description: 'build observability api' + default: false + + tenant-agent: + description: 'build tenant-agent' + default: false + + webhook-api: + description: 'build webhook api' + default: false + + websocket-server-api: + description: 'build websocket-server api' + default: false + +runs: + using: 'composite' + steps: + - name: setup ENV Variables + shell: bash + id: env-vars + working-directory: ${{ inputs.git_directory }} + run: |+ + GOMODCACHE=${{github.workspace}}/actions/go-mod-cache + GOCACHE=${{github.workspace}}/actions/go-cache + echo "GOMODCACHE=$GOMODCACHE" >> $GITHUB_OUTPUT + echo "GOCACHE=$GOCACHE" >> $GITHUB_OUTPUT + + echo "GOMODCACHE=$GOMODCACHE" >> $GITHUB_ENV + echo "GOCACHE=$GOCACHE" >> $GITHUB_ENV + echo "GOPKG_HASH=${{ hashFiles(format('{0}/go.mod', inputs.git_directory), format('{0}/go.sum', inputs.git_directory)) }}" >> $GITHUB_OUTPUT + + - name: ensures path to setup action exists + shell: bash + run: |+ + mkdir -p $GOMODCACHE + ln -sf ${{ inputs.git_directory }}/.github/actions ./github-actions + + # - name: Setup Caches + # uses: actions/cache@v4 + # with: + # path: |+ + # ${{ env.GOMODCACHE }} + # ${{ env.GOCACHE }} + # key: go-${{ runner.os }}-${{github.repository_id}}-${{ steps.env-vars.outputs.GOPKG_HASH }}-${{ inputs.cache_prefix }} + # save-always: true + # restore-keys: go-${{ runner.os }}-${{github.repository_id}}-${{ steps.env-vars.outputs.GOPKG_HASH }}- + + - name: setup nix cache + if: ${{ inputs.cachix_enabled == 'true' }} + uses: ./github-actions/setup-nix-cachix/ + with: + flake_lock: ${{ inputs.git_directory }}/flake.lock + nix_develop_arguments: "${{ inputs.git_directory }}#default" + + cachix_cache_name: ${{ inputs.cachix_cache_name }} + cachix_auth_token: ${{ inputs.cachix_auth_token }} + + - name: setup nix cache + if: ${{ inputs.cachix_enabled == 'false' }} + uses: ./github-actions/setup-nix-github/ + with: + flake_lock: ${{ inputs.git_directory }}/flake.lock + nix_develop_arguments: "${{ inputs.git_directory }}#default" + + - name: setup docker + if: ${{ inputs.docker_enabled == 'true' }} + uses: ./github-actions/setup-docker + with: + docker_username: ${{ github.actor }} + docker_password: ${{ inputs.github_token }} + + - name: Create Image Tag from branch name + if: startsWith(github.ref, 'refs/heads/release') + shell: bash + run: | + set +e + IMAGE_TAG=$(echo ${GITHUB_REF#refs/heads/} | sed 's/release-//g') + echo "$IMAGE_TAG" | grep -i '\-nightly$' + if [ $? -ne 0 ]; then + IMAGE_TAG="$IMAGE_TAG-nightly" + fi + set -e + + echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV + echo "OVERRIDE_PUSHED_IMAGE=true" >> $GITHUB_ENV + + - name: Create Image Tag from tag + if: startsWith(github.ref, 'refs/tags/') + shell: bash + run: | + IMAGE_TAG=$(echo ${GITHUB_REF#refs/tags/}) + + echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV + echo "OVERRIDE_PUSHED_IMAGE=false" >> $GITHUB_ENV + + - name: go mod download + if: ${{ inputs.go_mod_download == 'true' }} + working-directory: ${{ inputs.git_directory }} + shell: bash + run: |+ + echo "### STARTING go mod download ###" + go mod download -x + echo "### FINSIHED go mod download ###" + + ls -al ${{ env.GOMODCACHE }} + + - name: accounts api go build cache + if: ${{ inputs.accounts-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-accounts-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-accounts-api- + + - name: accounts api + if: ${{ inputs.accounts-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/accounts + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/accounts:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: auth api go build cache + if: ${{ inputs.auth-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-auth-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-auth-api- + + - name: auth api + if: ${{ inputs.auth-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/auth + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/auth:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: comms api go build cache + if: ${{ inputs.comms-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-comms-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-comms-api- + + - name: comms api + if: ${{ inputs.comms-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/comms + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/comms:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: console api go build cache + if: ${{ inputs.console-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-console-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-console-api- + + - name: console api + if: ${{ inputs.console-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/console + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/console:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: container-registry api go build cache + if: ${{ inputs.container-registry-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-container-registry-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-container-registry-api- + + - name: container-registry api + if: ${{ inputs.container-registry-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/container-registry + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/container-registry:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: gateway api go build cache + if: ${{ inputs.gateway-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-gateway-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-gateway-api- + + - name: gateway api + if: ${{ inputs.gateway-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/gateway + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/gateway:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: iam api go build cache + if: ${{ inputs.iam-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-iam-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-iam-api- + + - name: iam api + if: ${{ inputs.iam-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/iam + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/iam:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: infra api go build cache + if: ${{ inputs.infra-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-infra-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-infra-api- + + - name: infra api + if: ${{ inputs.infra-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/infra + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/infra:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: iot-console api go build cache + if: ${{ inputs.iot-console-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-iot-console-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-iot-console-api- + + - name: iot-console api + if: ${{ inputs.iot-console-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/iot-console + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/iot-console:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: message-office api go build cache + if: ${{ inputs.message-office-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-message-office-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-message-office-api- + + - name: message-office api + if: ${{ inputs.message-office-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/message-office + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/message-office:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: observability api go build cache + if: ${{ inputs.observability-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-observability-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-observability-api- + + - name: observability api + if: ${{ inputs.observability-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/observability + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/observability:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: tenant-agent go build cache + if: ${{ inputs.tenant-agent == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-tenant-agent-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-tenant-agent- + + - name: tenant-agent + if: ${{ inputs.tenant-agent == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/tenant-agent + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/tenant-agent:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: webhook api go build cache + if: ${{ inputs.webhook-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-webhook-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-webhook-api- + + - name: webhook api + if: ${{ inputs.webhook-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/webhook + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/webhook:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + + - name: websocket-server api go build cache + if: ${{ inputs.websocket-server-api == 'true' }} + uses: actions/cache@v4 + with: + path: |+ + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + key: go-${{ runner.os }}-websocket-server-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + save-always: true + restore-keys: go-${{ runner.os }}-websocket-server-api- + + - name: websocket-server api + if: ${{ inputs.websocket-server-api == 'true' }} + working-directory: ${{ inputs.git_directory }}/apps/websocket-server + shell: bash + run: | + task container:build-and-push image=ghcr.io/${{ github.repository }}/websocket-server:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + diff --git a/.github/actions/setup-docker/action.yml b/.github/actions/setup-docker/action.yml new file mode 100644 index 000000000..4d35b7ae7 --- /dev/null +++ b/.github/actions/setup-docker/action.yml @@ -0,0 +1,28 @@ +inputs: + docker_registry: + description: "Docker registry" + default: "ghcr.io" + + docker_username: + description: "Docker username" + required: true + + docker_password: + description: "Docker username" + required: true + +runs: + using: 'composite' + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ inputs.docker_username }} + password: ${{ inputs.docker_password }} diff --git a/.github/actions/setup-nix-cachix/action.yml b/.github/actions/setup-nix-cachix/action.yml new file mode 100644 index 000000000..19536f5f2 --- /dev/null +++ b/.github/actions/setup-nix-cachix/action.yml @@ -0,0 +1,41 @@ +inputs: + flake_lock: + description: "Path to flake.lock" + required: true + + nix_develop_arguments: + description: 'nix develop arguments' + type: string + default: "" + + cachix_cache_name: + description: "cachix cache name" + required: true + + cachix_auth_token: + description: "cachix auth token" + required: true + +runs: + using: 'composite' + steps: + - uses: cachix/install-nix-action@v25 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: nix cache with cachix + uses: cachix/cachix-action@v14 + with: + name: '${{ inputs.cachix_cache_name }}' + # If you chose API tokens for write access OR if you have a private cache + authToken: '${{ inputs.cachix_auth_token }}' + + - name: nix flake check + uses: DeterminateSystems/flake-checker-action@main + with: + flake-lock-path: "${{ inputs.flake_lock }}" + + - name: Nix Develop Action + uses: nicknovitski/nix-develop@v1.1.0 + with: + arguments: "${{ inputs.nix_develop_arguments }}" diff --git a/.github/actions/setup-nix-github/action.yml b/.github/actions/setup-nix-github/action.yml new file mode 100644 index 000000000..9e030f0be --- /dev/null +++ b/.github/actions/setup-nix-github/action.yml @@ -0,0 +1,28 @@ +inputs: + flake_lock: + description: "Path to flake.lock" + required: true + + nix_develop_arguments: + description: 'nix develop arguments' + type: string + default: "" + +runs: + using: 'composite' + steps: + - name: Install NIX + uses: DeterminateSystems/nix-installer-action@main + + - name: nix cache + uses: DeterminateSystems/magic-nix-cache-action@main + + - name: nix flake check + uses: DeterminateSystems/flake-checker-action@main + with: + flake-lock-path: "${{ inputs.flake_lock }}" + + - name: Nix Develop Action + uses: nicknovitski/nix-develop@v1.1.0 + with: + arguments: "${{ inputs.nix-develop-arguments }}" diff --git a/.tools/taskfiles/container-image-builder.yml b/.tools/taskfiles/container-image-builder.yml deleted file mode 100644 index 2e91ce4e6..000000000 --- a/.tools/taskfiles/container-image-builder.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: 3 - -tasks: - docker: - env: - CGO_ENABLED: 0 - vars: - BuiltAt: - sh: date | sed 's/\s/_/g' - preconditions: - - sh: '[ -n "{{.Out}}" ]' - msg: var Out must have a value - cmds: - - go build -v -ldflags="-s -w -X github.com/kloudlite/api/common.BuiltAt=\"{{.BuiltAt}}\"" -o {{.Out}} - - upx {{.Out}} diff --git a/.tools/taskfiles/docker-builder.yml b/.tools/taskfiles/docker-builder.yml deleted file mode 100644 index 7ec48ebd3..000000000 --- a/.tools/taskfiles/docker-builder.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: 3 - -tasks: - build: - vars: - Containerfile: ./Containerfile - Dir: ./ - preconditions: - - sh: '[ -n "{{.Image}}" ]' - msg: var Image must have a value - cmds: - - echo docker buildx build -f {{.Containerfile}} -t {{.Image}} {{.Dir}} {{.BuildArgs}} --push diff --git a/.tools/taskfiles/docker.Taskfile.yml b/.tools/taskfiles/docker.Taskfile.yml new file mode 100644 index 000000000..2b492e8c1 --- /dev/null +++ b/.tools/taskfiles/docker.Taskfile.yml @@ -0,0 +1,23 @@ +version: 3 + +tasks: + build-and-push: + summary: |+ + task build-and-push image="sample:latest" args="-f ./Dockerfile ." [platforms="linux/amd64,linux/arm64"] + env: + CGO_ENABLED: 0 + GOARCH: "{{.GOARCH | default .PlatformArch}}" + requires: + vars: + - "image" + - "args" + silent: true + cmds: + - cmd: |+ + echo $(docker manifest inspect "{{.image}}" || echo "not-found") >/tmp/manifest-inspect-status 2>/dev/null + if [ "$(cat /tmp/manifest-inspect-status)" != "not-found" ]; then + [ "{{.override}}" != "true" ] && echo "image '{{.image}}' already exists, skipping, use 'override=true' to override" && exit 0 + echo "image exists, but overridden" + fi + + docker buildx build -t {{.image}} --output=type=image,compression=zstd,force-compression=true,compression-level=12,push=true {{.args}} diff --git a/.tools/taskfiles/go-build.Taskfile.yml b/.tools/taskfiles/go-build.Taskfile.yml new file mode 100644 index 000000000..e9c92c7fb --- /dev/null +++ b/.tools/taskfiles/go-build.Taskfile.yml @@ -0,0 +1,26 @@ +version: 3 + +tasks: + build: + summary: |+ + task build Out="sample" [Dir="."] [ldflags=""] [upx=] + vars: + PlatformArch: + sh: go env GOARCH + BuiltAt: + sh: date | sed 's/\s/_/g' + dir: "." + ldflags: '{{.ldflags | default (printf "-s -w -X github.com/kloudlite/api/common.BuiltAt=%s" .BuiltAt) }}' + env: + CGO_ENABLED: 0 + GOARCH: "{{.GOARCH | default .PlatformArch}}" + requires: + vars: + - out + cmds: + - echo "building for GOARCH=${GOARCH}" + - go build -v -ldflags="{{.ldflags}}" -o {{.out}} {{.dir}} + - |+ + if [ "{{.upx}}" == "true" ]; then + upx {{.out}} + fi diff --git a/.tools/taskfiles/go-build.yml b/.tools/taskfiles/go-build.yml deleted file mode 100644 index 38b68cac7..000000000 --- a/.tools/taskfiles/go-build.yml +++ /dev/null @@ -1,21 +0,0 @@ -version: 3 - -tasks: - build: - env: - CGO_ENABLED: 0 - vars: - BuiltAt: - sh: date | sed 's/\s/_/g' - Dir: "." - upx: '{{.upx | default "true" }}' - preconditions: - - sh: '[ -n "{{.Out}}" ]' - msg: var Out must have a value - cmds: - - go build -v -ldflags="-s -w -X github.com/kloudlite/api/common.BuiltAt=\"{{.BuiltAt}}\"" -o {{.Out}} {{.Dir}} - # - upx --best --lzma {{.Out}} - - |+ - if [ "{{.upx}}" == "true" ]; then - upx {{.Out}} - fi diff --git a/apps/accounts/Containerfile b/apps/accounts/Dockerfile similarity index 62% rename from apps/accounts/Containerfile rename to apps/accounts/Dockerfile index 74ee10b4f..94203ed5e 100644 --- a/apps/accounts/Containerfile +++ b/apps/accounts/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.4 FROM gcr.io/distroless/static:nonroot -ARG BINARY -COPY ./bin/$BINARY ./accounts +ARG BINARY TARGETARCH +COPY $BINARY-$TARGETARCH ./accounts ENTRYPOINT [ "./accounts" ] diff --git a/apps/accounts/Taskfile.yml b/apps/accounts/Taskfile.yml index f743a35fe..c7c12e012 100644 --- a/apps/accounts/Taskfile.yml +++ b/apps/accounts/Taskfile.yml @@ -1,10 +1,12 @@ version: "3" +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: accounts - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: ./bin/{{.app}} tasks: gql: @@ -38,13 +40,23 @@ tasks: cmds: - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" diff --git a/apps/auth/Containerfile b/apps/auth/Dockerfile similarity index 59% rename from apps/auth/Containerfile rename to apps/auth/Dockerfile index d97aa02b0..32219986c 100644 --- a/apps/auth/Containerfile +++ b/apps/auth/Dockerfile @@ -1,5 +1,5 @@ #syntax=docker/dockerfile:1 FROM gcr.io/distroless/static-debian11:nonroot -ARG BINARY -COPY --chown=1001 ./bin/$BINARY ./auth +ARG BINARY TARGETARCH +COPY --chown=1001 $BINARY-$TARGETARCH ./auth ENTRYPOINT ["./auth"] diff --git a/apps/auth/Taskfile.yml b/apps/auth/Taskfile.yml index e2121a5e9..b5f7d1c54 100644 --- a/apps/auth/Taskfile.yml +++ b/apps/auth/Taskfile.yml @@ -1,10 +1,12 @@ version: '3' includes: - go: ../../.tools/taskfiles/go-build.yml + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml vars: app: auth + binary: "./bin/{{.app}}" tasks: run: @@ -22,12 +24,24 @@ tasks: cmds: - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag' " + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" + diff --git a/apps/comms/Containerfile b/apps/comms/Dockerfile similarity index 62% rename from apps/comms/Containerfile rename to apps/comms/Dockerfile index 86ee22dd3..2d41d46a7 100644 --- a/apps/comms/Containerfile +++ b/apps/comms/Dockerfile @@ -1,5 +1,5 @@ #syntax=docker/dockerfile:1.4 FROM gcr.io/distroless/static:nonroot -ARG BINARY -COPY ./bin/$BINARY ./comms +ARG BINARY TARGETARCH +COPY $BINARY-$TARGETARCH ./comms ENTRYPOINT ["./comms"] diff --git a/apps/comms/Taskfile.yml b/apps/comms/Taskfile.yml index 82e65c375..bcc3ccb18 100644 --- a/apps/comms/Taskfile.yml +++ b/apps/comms/Taskfile.yml @@ -1,10 +1,12 @@ version: "3" includes: - go: ../../.tools/taskfiles/go-build.yml + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml vars: app: comms + binary: "./bin/{{.app}}" tasks: gql: @@ -41,14 +43,26 @@ tasks: build: cmds: + - task: gen:constants - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - - task build upx={{.upx}} - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + - task: build + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" diff --git a/apps/console/Containerfile b/apps/console/Dockerfile similarity index 58% rename from apps/console/Containerfile rename to apps/console/Dockerfile index fd35b0c8e..b2c067c35 100644 --- a/apps/console/Containerfile +++ b/apps/console/Dockerfile @@ -1,5 +1,5 @@ #syntax=docker/dockerfile:1 FROM gcr.io/distroless/static-debian11:nonroot -ARG BINARY -COPY --chown=1001 ./bin/$BINARY ./console +ARG BINARY TARGETARCH +COPY --chown=1001 $BINARY-$TARGETARCH ./console ENTRYPOINT ["./console"] diff --git a/apps/console/Taskfile.yml b/apps/console/Taskfile.yml index e2e27db34..64504f43c 100644 --- a/apps/console/Taskfile.yml +++ b/apps/console/Taskfile.yml @@ -1,10 +1,12 @@ version: "3" +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: console - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: "./bin/{{.app}}" tasks: gql: @@ -60,26 +62,24 @@ tasks: - task: gen:constants - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" - local:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" - vars: - push: "{{.push | default false}}" + container:build-and-push: + requires: + vars: + - image cmds: - task: build - - nerdctl build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} - - |+ - [ {{.push}} = "true" ] && nerdctl push {{.Image}} - + vars: + GOARCH: amd64 - container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" - cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} --build-arg BINARY={{.app}} --output=type=image,compression=zstd,force-compression=true,compression-level=12 . --push + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "-t {{.image}} . --build-arg BINARY={{.binary}}" + image: "{{.image}}" diff --git a/apps/container-registry/Containerfile b/apps/container-registry/Dockerfile similarity index 61% rename from apps/container-registry/Containerfile rename to apps/container-registry/Dockerfile index 753dd24ea..7e1881220 100644 --- a/apps/container-registry/Containerfile +++ b/apps/container-registry/Dockerfile @@ -1,5 +1,5 @@ # FROM gcr.io/distroless/static-debian12:nonroot FROM cgr.dev/chainguard/static -ARG BINARY -COPY ./bin/${BINARY} ./container-registry +ARG BINARY TARGETARCH +COPY ${BINARY}-${TARGETARCH} ./container-registry ENTRYPOINT ["./container-registry"] diff --git a/apps/container-registry/Taskfile.yml b/apps/container-registry/Taskfile.yml index 5c41f5949..229c62fd9 100644 --- a/apps/container-registry/Taskfile.yml +++ b/apps/container-registry/Taskfile.yml @@ -1,10 +1,12 @@ version: "3" +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: container-registry - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: "./bin/{{.app}}" tasks: gql: @@ -52,15 +54,26 @@ tasks: build: cmds: - - task: go:build + - task: gen:constants + - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" diff --git a/apps/gateway/Dockerfile b/apps/gateway/Dockerfile index 6dcbd9249..3a34c63d9 100644 --- a/apps/gateway/Dockerfile +++ b/apps/gateway/Dockerfile @@ -1,4 +1,4 @@ -FROM node:current-alpine +FROM --platform=$TARGETPLATFORM node:current-alpine RUN npm i -g pnpm WORKDIR /home/node RUN --mount=type=bind,source=package.json,target=package.json \ diff --git a/apps/gateway/Taskfile.yml b/apps/gateway/Taskfile.yml index dd5a5e70f..59b9efbd0 100644 --- a/apps/gateway/Taskfile.yml +++ b/apps/gateway/Taskfile.yml @@ -1,5 +1,8 @@ version: 3 +includes: + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: gateway @@ -7,6 +10,7 @@ tasks: generate-schema: cmds: - bash ./generate-schema.sh {{.Output}} + dev: dotenv: - "./.secrets/env" @@ -14,26 +18,19 @@ tasks: cmds: - npm start - local:build: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" - vars: - push: "{{.push | default false}}" - SupergraphSchemaFile: "./supergraph.graphqls" - cmds: - - task: generate-schema - - podman build -t {{.Image}} . --cache-from=type=local,src=/tmp/buildx-cache --cache-to=type=local,dest=/tmp/buildx-cache - container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image vars: SupergraphSchemaFile: "./supergraph.graphqls" cmds: - task: generate-schema vars: Output: "{{.SupergraphSchemaFile}}" - - docker buildx build --build-arg SUPERGRAPH_FILE="{{.SupergraphSchemaFile}}" -t {{.Image}} . --push + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg SUPERGRAPH_FILE={{.SupergraphSchemaFile}} ." + image: "{{.image}}" diff --git a/apps/iam/Containerfile b/apps/iam/Containerfile deleted file mode 100644 index 8dd8b0e5e..000000000 --- a/apps/iam/Containerfile +++ /dev/null @@ -1,5 +0,0 @@ -# syntax=docker/dockerfile:1 -FROM gcr.io/distroless/static-debian11:nonroot -ARG BINARY -COPY --chown=1001 ./bin/$BINARY ./iam -ENTRYPOINT ["./iam"] diff --git a/apps/iam/Dockerfile b/apps/iam/Dockerfile index 5ea307ecb..089b1dede 100644 --- a/apps/iam/Dockerfile +++ b/apps/iam/Dockerfile @@ -1,23 +1,5 @@ -# syntax=docker/dockerfile:1.4 -FROM golang:1.18.3-alpine3.16 AS base -USER 1001 -ENV GOPATH=/tmp/go -ENV GOCACHE=/tmp/go-cache -WORKDIR /tmp/app -COPY --chown=1001 --from=project-root ./go.mod ./go.sum ./tools.go ./ -RUN go mod download -x -COPY --chown=1001 --from=project-root common ./common -COPY --chown=1001 --from=project-root grpc-interfaces ./grpc-interfaces -COPY --chown=1001 --from=project-root pkg ./pkg -ARG APP -RUN mkdir -p ./apps/$APP -WORKDIR /tmp/app/apps/$APP -COPY --chown=1001 ./ ./ -RUN CGO_ENABLED=0 go build -tags musl -o /tmp/bin/$APP ./main.go -RUN chmod +x /tmp/bin/$APP - -FROM gcr.io/distroless/static-debian11 -USER 1001 -WORKDIR /tmp/app -COPY --from=base --chown=1001 /tmp/bin/iam ./iam -CMD ["./iam"] +# syntax=docker/dockerfile:1 +FROM gcr.io/distroless/static-debian11:nonroot +ARG BINARY TARGETARCH +COPY --chown=1001 $BINARY-$TARGETARCH ./iam +ENTRYPOINT ["./iam"] diff --git a/apps/iam/Taskfile.yml b/apps/iam/Taskfile.yml index c2f9e4fd4..4e330fd69 100644 --- a/apps/iam/Taskfile.yml +++ b/apps/iam/Taskfile.yml @@ -4,10 +4,12 @@ includes: grpc: taskfile: ../../grpc-interfaces/Taskfile.yml dir: ../../grpc-interfaces/ - go: ../../.tools/taskfiles/go-build.yml + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml vars: app: iam + binary: "./bin/{{.app}}" tasks: proto: @@ -24,13 +26,25 @@ tasks: cmds: - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" + diff --git a/apps/infra/Containerfile b/apps/infra/Dockerfile similarity index 57% rename from apps/infra/Containerfile rename to apps/infra/Dockerfile index 99ccca23a..0ee4cf6d3 100644 --- a/apps/infra/Containerfile +++ b/apps/infra/Dockerfile @@ -1,5 +1,5 @@ #syntax=docker/dockerfile:1 FROM gcr.io/distroless/static-debian11:nonroot -ARG BINARY -COPY --chown=1001 ./bin/${BINARY} ./infra +ARG BINARY TARGETARCH +COPY --chown=1001 ${BINARY}-${TARGETARCH} ./infra ENTRYPOINT ["./infra"] diff --git a/apps/infra/Taskfile.yml b/apps/infra/Taskfile.yml index 792a5f44e..548a4116c 100644 --- a/apps/infra/Taskfile.yml +++ b/apps/infra/Taskfile.yml @@ -1,10 +1,12 @@ version: "3" +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: infra - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: "./bin/{{.app}}" tasks: gql: @@ -56,17 +58,28 @@ tasks: build: cmds: - task: gen:constants - - task: go:build + - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" test: cmds: diff --git a/apps/iot-console/Containerfile b/apps/iot-console/Dockerfile similarity index 57% rename from apps/iot-console/Containerfile rename to apps/iot-console/Dockerfile index ec0f5bc98..84cb86c7b 100644 --- a/apps/iot-console/Containerfile +++ b/apps/iot-console/Dockerfile @@ -1,5 +1,5 @@ #syntax=docker/dockerfile:1 FROM gcr.io/distroless/static-debian11:nonroot -ARG BINARY -COPY --chown=1001 ./bin/$BINARY ./iot-console-api +ARG BINARY TARGETARCH +COPY --chown=1001 $BINARY-$TARGETARCH ./iot-console-api ENTRYPOINT ["./iot-console-api"] diff --git a/apps/iot-console/Taskfile.yml b/apps/iot-console/Taskfile.yml index 282180d79..269beef8f 100644 --- a/apps/iot-console/Taskfile.yml +++ b/apps/iot-console/Taskfile.yml @@ -1,10 +1,12 @@ version: "3" +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: iot-console-api - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: ./bin/{{.app}} tasks: gql: @@ -43,12 +45,24 @@ tasks: cmds: - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" + diff --git a/apps/message-office/Containerfile b/apps/message-office/Dockerfile similarity index 58% rename from apps/message-office/Containerfile rename to apps/message-office/Dockerfile index 1dea0fb32..1e022cf9a 100644 --- a/apps/message-office/Containerfile +++ b/apps/message-office/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.4 FROM gcr.io/distroless/static-debian11:nonroot -ARG BINARY -COPY --chown=1001 ./bin/$BINARY ./message-office +ARG BINARY TARGETARCH +COPY --chown=1001 $BINARY-$TARGETARCH ./message-office ENTRYPOINT ["./message-office"] diff --git a/apps/message-office/Taskfile.yml b/apps/message-office/Taskfile.yml index 69d65b02f..1ec38087d 100644 --- a/apps/message-office/Taskfile.yml +++ b/apps/message-office/Taskfile.yml @@ -1,10 +1,12 @@ version: 3 +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: message-office - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: ./bin/{{.app}} tasks: run: @@ -28,13 +30,23 @@ tasks: cmds: - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" diff --git a/apps/observability/Dockerfile b/apps/observability/Dockerfile index 1346f2185..b9db16550 100644 --- a/apps/observability/Dockerfile +++ b/apps/observability/Dockerfile @@ -1,5 +1,5 @@ #syntax=docker/dockerfile:1 FROM gcr.io/distroless/static-debian11:nonroot -ARG BINARY -COPY --chown=1001 ./bin/$BINARY ./observability +ARG BINARY TARGETARCH +COPY --chown=1001 $BINARY-$TARGETARCH ./observability ENTRYPOINT ["./observability"] diff --git a/apps/observability/Taskfile.yml b/apps/observability/Taskfile.yml index 630484c79..c8ef87228 100644 --- a/apps/observability/Taskfile.yml +++ b/apps/observability/Taskfile.yml @@ -1,10 +1,12 @@ version: "3" +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: observability - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: "./bin/{{.app}}" tasks: gql: @@ -27,25 +29,24 @@ tasks: cmds: - task: go:build vars: - Out: ./bin/{{.app}} - - local:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" - vars: - push: "{{.push |default false}}" - cmds: - - task: build - - nerdctl build -t {{.Image}} . --build-arg BINARY={{.app}} - - |+ - [ {{.push}} = "true" ] && nerdctl push {{.Image}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Dockerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" diff --git a/apps/tenant-agent/Containerfile b/apps/tenant-agent/Containerfile deleted file mode 100644 index 8714aed6b..000000000 --- a/apps/tenant-agent/Containerfile +++ /dev/null @@ -1,5 +0,0 @@ -# syntax=docker/dockerfile:1.4 -FROM gcr.io/distroless/static:nonroot -ARG BINARY TARGETARCH -COPY ./bin/${BINARY}-${TARGETARCH} ./kloudlite-agent -ENTRYPOINT ["./kloudlite-agent"] diff --git a/apps/tenant-agent/Dockerfile b/apps/tenant-agent/Dockerfile index c399d4bde..21b0a6969 100644 --- a/apps/tenant-agent/Dockerfile +++ b/apps/tenant-agent/Dockerfile @@ -1,28 +1,5 @@ # syntax=docker/dockerfile:1.4 -FROM golang:1.18-alpine as builder -RUN apk add curl -WORKDIR /workspace -COPY --from=project ./go.mod ./go.mod -COPY --from=project ./go.sum ./go.sum -RUN ls -al -RUN go mod download -x - -COPY --from=project ./pkg/errors ./pkg/errors -COPY --from=project ./pkg/logging ./pkg/logging -COPY --from=project ./pkg/redpanda ./pkg/redpanda -COPY --from=project ./pkg/functions ./pkg/functions -COPY --from=project ./pkg/kubectl ./pkg/kubectl -WORKDIR ./agent -COPY ./main.go ./main.go -COPY ./internal ./internal - -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o /workspace/kloudlite-agent main.go -RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" > \ - ./kubectl && chmod +x ./kubectl - -# FROM gcr.io/distroless/static:nonroot -FROM alpine:latest -COPY --from=builder /workspace/kubectl /usr/local/bin/kubectl -COPY --from=builder /workspace/kloudlite-agent /kloudlite-agent -USER 65532:65532 -ENTRYPOINT ["/kloudlite-agent"] +FROM gcr.io/distroless/static:nonroot +ARG BINARY TARGETARCH +COPY ${BINARY}-${TARGETARCH} ./kloudlite-agent +ENTRYPOINT ["./kloudlite-agent"] diff --git a/apps/tenant-agent/Taskfile.yml b/apps/tenant-agent/Taskfile.yml index e41cf8803..4790b029a 100644 --- a/apps/tenant-agent/Taskfile.yml +++ b/apps/tenant-agent/Taskfile.yml @@ -1,10 +1,12 @@ version: 3 +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: tenant-agent - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: "./bin/{{.app}}" tasks: vector:proto: @@ -21,31 +23,23 @@ tasks: cmds: - task: go:build vars: - Out: ./bin/{{.app}} - - local:build: - vars: - GOARCH: - sh: go env GOARCH - cmds: - - task: go:build - vars: - Out: ./bin/{{.app}}-${GOARCH:-$(go env GOARCH)} - - local:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" - cmds: - - GOARCH=amd64 task local:build - - GOARCH=arm64 task local:build - - docker buildx build -f ./Containerfile --platform linux/amd64,linux/arm64 -t {{.Image}} . --build-arg BINARY={{.app}} --push + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - - task: local:build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push - + - task: build + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" diff --git a/apps/webhook/Containerfile b/apps/webhook/Dockerfile similarity index 58% rename from apps/webhook/Containerfile rename to apps/webhook/Dockerfile index 449115d4b..50f0f1f66 100644 --- a/apps/webhook/Containerfile +++ b/apps/webhook/Dockerfile @@ -1,5 +1,5 @@ #syntax=docker/dockerfile:1 FROM gcr.io/distroless/static-debian11:nonroot -ARG BINARY -COPY --chown=1001 ./bin/$BINARY ./webhook +ARG BINARY TARGETARCH +COPY --chown=1001 $BINARY-$TARGETARCH ./webhook ENTRYPOINT ["./webhook"] diff --git a/apps/webhook/Taskfile.yml b/apps/webhook/Taskfile.yml index 38c46d5f9..ff19ddbd8 100644 --- a/apps/webhook/Taskfile.yml +++ b/apps/webhook/Taskfile.yml @@ -1,10 +1,12 @@ version: "3" +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: webhook - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: "./bin/{{.app}}" tasks: run: @@ -19,13 +21,23 @@ tasks: cmds: - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" diff --git a/apps/websocket-server/Containerfile b/apps/websocket-server/Dockerfile similarity index 61% rename from apps/websocket-server/Containerfile rename to apps/websocket-server/Dockerfile index 238f6688d..9f1f555bb 100644 --- a/apps/websocket-server/Containerfile +++ b/apps/websocket-server/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.4 FROM gcr.io/distroless/static:nonroot -ARG BINARY -COPY ./bin/$BINARY ./websocket-server +ARG BINARY TARGETARCH +COPY $BINARY-$TARGETARCH ./websocket-server ENTRYPOINT [ "./websocket-server" ] diff --git a/apps/websocket-server/Taskfile.yml b/apps/websocket-server/Taskfile.yml index 2ecdbd9b0..0f9d6a68d 100644 --- a/apps/websocket-server/Taskfile.yml +++ b/apps/websocket-server/Taskfile.yml @@ -1,10 +1,12 @@ version: "3" +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: websocket-server - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: "./bin/{{.app}}" tasks: run: @@ -17,13 +19,24 @@ tasks: cmds: - task: go:build vars: - Out: ./bin/{{.app}} + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" diff --git a/apps/worker-audit-logging/Containerfile b/apps/worker-audit-logging/Dockerfile similarity index 100% rename from apps/worker-audit-logging/Containerfile rename to apps/worker-audit-logging/Dockerfile diff --git a/apps/worker-audit-logging/Taskfile.yml b/apps/worker-audit-logging/Taskfile.yml index d159bc602..9d9646799 100644 --- a/apps/worker-audit-logging/Taskfile.yml +++ b/apps/worker-audit-logging/Taskfile.yml @@ -1,22 +1,36 @@ version: 3 +includes: + go: ../../.tools/taskfiles/go-build.Taskfile.yml + docker: ../../.tools/taskfiles/docker.Taskfile.yml + vars: app: worker-audit-logging - -includes: - go: ../../.tools/taskfiles/go-build.yml + binary: "./bin/{{.app}}" tasks: build: cmds: - - task: go:build - vars: - Out: ./bin/{{.app}} + - task: go:build + vars: + out: "{{.binary}}-{{.GOARCH}}" + GOARCH: "{{.GOARCH}}" container:build-and-push: - preconditions: - - sh: '[[ -n "{{.Image}}" ]]' - msg: "var Image must have a value, of format 'image_repository:image_tag'" + requires: + vars: + - image cmds: - task: build - - docker buildx build -f ./Containerfile -t {{.Image}} . --build-arg BINARY={{.app}} --push + vars: + GOARCH: amd64 + + - task: build + vars: + GOARCH: arm64 + + - task: docker:build-and-push + vars: + args: "--platform linux/amd64,linux/arm64 --build-arg BINARY={{.binary}} ." + image: "{{.image}}" + From 42ee98a33c5782143f5602666aec11c23328dff9 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Tue, 25 Jun 2024 19:28:02 +0530 Subject: [PATCH 6/9] feat: global vpn graphql schema updates - environment cloning namespace will now be gateway enabled by default --- .github/actions/build-api-images/action.yml | 81 ++-- .github/workflows/build-and-test-binaries.yml | 132 ------ .github/workflows/build-gateway.yml | 94 ---- .github/workflows/building-with-nix.yml | 82 ++++ apps/console/internal/domain/environment.go | 4 + .../internal/app/graph/generated/generated.go | 435 +++++++++++++----- .../internal/app/graph/globalvpn.resolvers.go | 17 +- .../internal/app/graph/model/models_gen.go | 4 +- .../struct-to-graphql/globalvpn.graphqls | 16 +- apps/infra/internal/entities/global-vpn.go | 4 +- .../internal/domain/resource-update.go | 2 + pkg/repos/mongo.go | 2 + 12 files changed, 466 insertions(+), 407 deletions(-) delete mode 100644 .github/workflows/build-and-test-binaries.yml delete mode 100644 .github/workflows/build-gateway.yml create mode 100644 .github/workflows/building-with-nix.yml diff --git a/.github/actions/build-api-images/action.yml b/.github/actions/build-api-images/action.yml index 4a4f3a309..5d09e2d56 100644 --- a/.github/actions/build-api-images/action.yml +++ b/.github/actions/build-api-images/action.yml @@ -6,6 +6,10 @@ inputs: description: 'GitHub Token' required: true + image_tag: + description: 'image tag, if empty, will be generated from branch or tag' + default: '' + cachix_enabled: description: "cachix enabled" default: "false" @@ -25,14 +29,6 @@ inputs: description: 'git directory' default: "." - cache_prefix: - description: 'cache prefix' - default: "" - - go_mod_download: - description: 'go mod download' - default: false - # APIs accounts-api: description: 'build accounts api' @@ -105,25 +101,14 @@ runs: echo "GOMODCACHE=$GOMODCACHE" >> $GITHUB_ENV echo "GOCACHE=$GOCACHE" >> $GITHUB_ENV - echo "GOPKG_HASH=${{ hashFiles(format('{0}/go.mod', inputs.git_directory), format('{0}/go.sum', inputs.git_directory)) }}" >> $GITHUB_OUTPUT + echo "FILES_HASH=${{ hashFiles('**/*.go', '**/go.mod', '**/go.sum')}}" >> $GITHUB_OUTPUT - name: ensures path to setup action exists shell: bash run: |+ - mkdir -p $GOMODCACHE ln -sf ${{ inputs.git_directory }}/.github/actions ./github-actions - # - name: Setup Caches - # uses: actions/cache@v4 - # with: - # path: |+ - # ${{ env.GOMODCACHE }} - # ${{ env.GOCACHE }} - # key: go-${{ runner.os }}-${{github.repository_id}}-${{ steps.env-vars.outputs.GOPKG_HASH }}-${{ inputs.cache_prefix }} - # save-always: true - # restore-keys: go-${{ runner.os }}-${{github.repository_id}}-${{ steps.env-vars.outputs.GOPKG_HASH }}- - - - name: setup nix cache + - name: setup nix (with cachix) if: ${{ inputs.cachix_enabled == 'true' }} uses: ./github-actions/setup-nix-cachix/ with: @@ -133,7 +118,7 @@ runs: cachix_cache_name: ${{ inputs.cachix_cache_name }} cachix_auth_token: ${{ inputs.cachix_auth_token }} - - name: setup nix cache + - name: setup nix cache (with github cache) if: ${{ inputs.cachix_enabled == 'false' }} uses: ./github-actions/setup-nix-github/ with: @@ -147,8 +132,14 @@ runs: docker_username: ${{ github.actor }} docker_password: ${{ inputs.github_token }} + - name: Create Image Tag + if: ${{ inputs.image_tag != '' }} + shell: bash + run: |+ + echo "IMAGE_TAG=${{ inputs.image_tag }}" >> $GITHUB_ENV + - name: Create Image Tag from branch name - if: startsWith(github.ref, 'refs/heads/release') + if: ${{ inputs.image_tag == '' && startsWith(github.ref, 'refs/heads/release-') }} shell: bash run: | set +e @@ -160,27 +151,19 @@ runs: set -e echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV - echo "OVERRIDE_PUSHED_IMAGE=true" >> $GITHUB_ENV - name: Create Image Tag from tag - if: startsWith(github.ref, 'refs/tags/') + if: ${{ inputs.image_tag == '' && startsWith(github.ref, 'refs/tags/') }} shell: bash run: | IMAGE_TAG=$(echo ${GITHUB_REF#refs/tags/}) - echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV - echo "OVERRIDE_PUSHED_IMAGE=false" >> $GITHUB_ENV - - name: go mod download - if: ${{ inputs.go_mod_download == 'true' }} - working-directory: ${{ inputs.git_directory }} + - name: override image if image_tag is nightly + if: "${{ endsWith(env.IMAGE_TAG, '-nightly') }}" shell: bash run: |+ - echo "### STARTING go mod download ###" - go mod download -x - echo "### FINSIHED go mod download ###" - - ls -al ${{ env.GOMODCACHE }} + echo "OVERRIDE_PUSHED_IMAGE=true" >> $GITHUB_ENV - name: accounts api go build cache if: ${{ inputs.accounts-api == 'true' }} @@ -189,7 +172,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-accounts-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-accounts-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-accounts-api- @@ -207,7 +190,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-auth-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-auth-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-auth-api- @@ -225,7 +208,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-comms-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-comms-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-comms-api- @@ -243,7 +226,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-console-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-console-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-console-api- @@ -261,7 +244,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-container-registry-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-container-registry-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-container-registry-api- @@ -279,7 +262,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-gateway-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-gateway-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-gateway-api- @@ -297,7 +280,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-iam-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-iam-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-iam-api- @@ -315,7 +298,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-infra-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-infra-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-infra-api- @@ -333,7 +316,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-iot-console-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-iot-console-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-iot-console-api- @@ -351,7 +334,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-message-office-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-message-office-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-message-office-api- @@ -369,7 +352,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-observability-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-observability-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-observability-api- @@ -387,7 +370,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-tenant-agent-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-tenant-agent-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-tenant-agent- @@ -405,7 +388,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-webhook-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-webhook-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-webhook-api- @@ -423,7 +406,7 @@ runs: path: |+ ${{ env.GOMODCACHE }} ${{ env.GOCACHE }} - key: go-${{ runner.os }}-websocket-server-api-${{ steps.env-vars.outputs.GOPKG_HASH }} + key: go-${{ runner.os }}-websocket-server-api-${{ steps.env-vars.outputs.FILES_HASH }} save-always: true restore-keys: go-${{ runner.os }}-websocket-server-api- diff --git a/.github/workflows/build-and-test-binaries.yml b/.github/workflows/build-and-test-binaries.yml deleted file mode 100644 index e2dbf9759..000000000 --- a/.github/workflows/build-and-test-binaries.yml +++ /dev/null @@ -1,132 +0,0 @@ -name: build-docker-images - -on: - workflow_dispatch: - - repository_dispatch: - types: - - webhook - - push: - paths: - - "apps/**/**" - - "pkg/**" - - "grpc-interfaces/**" - - "common/**" - - "go.*" - - ".github/workflows/**" - -permissions: - contents: read - packages: write - -jobs: - docker-builds: - strategy: - matrix: - app: - - accounts - - auth - - comms - - console - - container-registry - - iam - - infra - - worker-audit-logging - - webhook - - websocket-server - - message-office - - tenant-agent - - observability - runs-on: ubuntu-latest - name: Deploy to Docker Image - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Setup Golang caches - uses: actions/cache@v4 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-golang-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-golang- - - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: 1.21.6 - - - name: Install Task - uses: arduino/setup-task@v1 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Install UPX - run: | - curl -L0 https://github.com/upx/upx/releases/download/v4.2.1/upx-4.2.1-amd64_linux.tar.xz > upx.tar.xz - tar -xf upx.tar.xz - sudo mv upx-4.2.1-amd64_linux/upx /usr/local/bin - - - name: Build Binary - run: | - pushd apps/${{matrix.app}} - task build - popd - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Log in to the Container registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Create Image Tag from branch name - if: startsWith(github.ref, 'refs/heads/release') - run: | - set +e - IMAGE_TAG=$(echo ${GITHUB_REF#refs/heads/} | sed 's/release-//g') - echo "$IMAGE_TAG" | grep -i '\-nightly$' - if [ $? -ne 0 ]; then - IMAGE_TAG="$IMAGE_TAG-nightly" - fi - set -e - - echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV - echo "OVERRIDE_PUSHED_IMAGE=true" >> $GITHUB_ENV - - - name: Create Image Tag from tag - if: startsWith(github.ref, 'refs/tags/') - run: | - IMAGE_TAG=$(echo ${GITHUB_REF#refs/tags/}) - - echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV - echo "OVERRIDE_PUSHED_IMAGE=false" >> $GITHUB_ENV - - - name: Build & Push Image - if: startsWith(github.ref, 'refs/heads/release') || startsWith(github.ref, 'refs/tags/') - run: | - set +e - image_name="ghcr.io/${{ github.repository }}/${{matrix.app}}" - - docker manifest inspect $image_name:$IMAGE_TAG - exit_status=$? - if [ $exit_status -eq 0 ]; then - [ "$OVERRIDE_PUSHED_IMAGE" = "false" ] && echo "image ($image_name:$IMAGE_TAG) already exists, and override image is disable, exiting" && exit 0 - echo "image exists, but override pushed image is set to true. proceeding with building image" - fi - - set -e - - pushd apps/${{ matrix.app }} - task container:build-and-push Image=$image_name:$IMAGE_TAG - popd diff --git a/.github/workflows/build-gateway.yml b/.github/workflows/build-gateway.yml deleted file mode 100644 index e0f9e29eb..000000000 --- a/.github/workflows/build-gateway.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: build-gateway-images - -on: - workflow_dispatch: - - repository_dispatch: - types: - - webhook - - push: - paths: - - "apps/**/graph/*.graphqls" - - "apps/**/graph/struct-to-graphql/*.graphqls" - - "apps/gateway/**" - - ".github/workflows/build-gateway.yml" - -permissions: - contents: read - packages: write - -jobs: - docker-builds: - runs-on: ubuntu-latest - name: Deploy to Docker Image - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Install Task - uses: arduino/setup-task@v1 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Install Rover - run: | - curl -sSL https://rover.apollo.dev/nix/v0.23.0-rc.3 | sh - - # Add Rover to the $GITHUB_PATH so it can be used in another step - # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#adding-a-system-path - echo "$HOME/.rover/bin" >> $GITHUB_PATH - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Log in to the Container registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Create Image Tag from branch name - if: startsWith(github.ref, 'refs/heads/release') - run: | - set +e - IMAGE_TAG=$(echo ${GITHUB_REF#refs/heads/} | sed 's/release-//g') - echo "$IMAGE_TAG" | grep -i '\-nightly$' - if [ $? -ne 0 ]; then - IMAGE_TAG="$IMAGE_TAG-nightly" - fi - set -e - - echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV - echo "OVERRIDE_PUSHED_IMAGE=true" >> $GITHUB_ENV - - - name: Create Image Tag from tag - if: startsWith(github.ref, 'refs/tags/') - run: | - IMAGE_TAG=$(echo ${GITHUB_REF#refs/tags/}) - - echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV - echo "OVERRIDE_PUSHED_IMAGE=false" >> $GITHUB_ENV - - - name: Build & Push Image - if: startsWith(github.ref, 'refs/heads/release') || startsWith(github.ref, 'refs/tags/') - run: | - set +e - image_name="ghcr.io/${{ github.repository }}/gateway" - - docker manifest inspect $image_name:$IMAGE_TAG - exit_status=$? - if [ $exit_status -eq 0 ]; then - [ "$OVERRIDE_PUSHED_IMAGE" = "false" ] && echo "image ($image_name:$IMAGE_TAG) already exists, and override image is disable, exiting" && exit 0 - echo "image exists, but override pushed image is set to true. proceeding with building image" - fi - - set -e - - cd apps/gateway - task container:build-and-push Image=$image_name:$IMAGE_TAG diff --git a/.github/workflows/building-with-nix.yml b/.github/workflows/building-with-nix.yml new file mode 100644 index 000000000..1fdc31721 --- /dev/null +++ b/.github/workflows/building-with-nix.yml @@ -0,0 +1,82 @@ +name: building api with nix + +on: + workflow_dispatch: + inputs: + image_tag: + type: string + description: "image_tag" + required: true + default: "" + + + repository_dispatch: + types: + - webhook + + push: + paths: + - "apps/**/**" + - "pkg/**" + - "grpc-interfaces/**" + - "common/**" + - "go.*" + - ".github/workflows/**" + +permissions: + contents: read + packages: write + +jobs: + build-images: + strategy: + fail-fast: false + matrix: + images: + - name: accounts-api + - name: auth-api + - name: comms-api + - name: console-api + - name: container-registry-api + - name: gateway-api + - name: iam-api + - name: infra-api + - name: message-office-api + - name: observability-api + - name: tenant-agent + - name: webhook-api + - name: websocket-server-api + + runs-on: ubuntu-latest + name: ${{ matrix.images.name }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: build-and-push + uses: ./.github/actions/build-api-images/ + with: + image_tag: ${{ inputs.image_tag }} + + cachix_enabled: true + cachix_auth_token: ${{ secrets.CACHIX_AUTH_TOKEN }} + + docker_enabled: true + + github_token: ${{ secrets.GITHUB_TOKEN }} + git_directory: "." + + accounts-api: ${{ matrix.images.name == 'accounts-api' }} + auth-api: ${{ matrix.images.name == 'auth-api' }} + comms-api: ${{ matrix.images.name == 'comms-api' }} + console-api: ${{ matrix.images.name == 'console-api' }} + container-registry-api: ${{ matrix.images.name == 'container-registry-api' }} + gateway-api: ${{ matrix.images.name == 'gateway-api' }} + iam-api: ${{ matrix.images.name == 'iam-api' }} + infra-api: ${{ matrix.images.name == 'infra-api' }} + message-office-api: ${{ matrix.images.name == 'message-office-api' }} + observability-api: ${{ matrix.images.name == 'observability-api' }} + tenant-agent: ${{ matrix.images.name == 'tenant-agent' }} + webhook-api: ${{ matrix.images.name == 'webhook-api' }} + websocket-server-api: ${{ matrix.images.name == 'websocket-server-api' }} + diff --git a/apps/console/internal/domain/environment.go b/apps/console/internal/domain/environment.go index 59f095c6c..1649d987d 100644 --- a/apps/console/internal/domain/environment.go +++ b/apps/console/internal/domain/environment.go @@ -6,6 +6,7 @@ import ( "github.com/kloudlite/api/common/fields" crdsv1 "github.com/kloudlite/operator/apis/crds/v1" + opConstants "github.com/kloudlite/operator/pkg/constants" iamT "github.com/kloudlite/api/apps/iam/types" "github.com/kloudlite/api/common" @@ -246,6 +247,9 @@ func (d *domain) CloneEnvironment(ctx ConsoleContext, args CloneEnvironmentArgs) TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Namespace"}, ObjectMeta: metav1.ObjectMeta{ Name: destEnv.Spec.TargetNamespace, + Labels: map[string]string{ + opConstants.KloudliteGatewayEnabledLabel: "true", + }, }, }, destEnv.RecordVersion); err != nil { return nil, errors.NewE(err) diff --git a/apps/infra/internal/app/graph/generated/generated.go b/apps/infra/internal/app/graph/generated/generated.go index b986a0202..a0d7aa895 100644 --- a/apps/infra/internal/app/graph/generated/generated.go +++ b/apps/infra/internal/app/graph/generated/generated.go @@ -627,7 +627,8 @@ type ComplexityRoot struct { CreationTime func(childComplexity int) int DisplayName func(childComplexity int) int ID func(childComplexity int) int - KloudliteDevice func(childComplexity int) int + KloudliteClusterLocalDevice func(childComplexity int) int + KloudliteGatewayDevice func(childComplexity int) int LastUpdatedBy func(childComplexity int) int MarkedForDeletion func(childComplexity int) int NonClusterUseAllowedIPs func(childComplexity int) int @@ -676,7 +677,12 @@ type ComplexityRoot struct { Node func(childComplexity int) int } - GlobalVPNKloudliteDevice struct { + GlobalVPNKloudliteClusterLocalDevice struct { + IPAddr func(childComplexity int) int + Name func(childComplexity int) int + } + + GlobalVPNKloudliteGatewayDevice struct { IPAddr func(childComplexity int) int Name func(childComplexity int) int } @@ -1487,7 +1493,8 @@ type GlobalVPNResolver interface { CreationTime(ctx context.Context, obj *entities.GlobalVPN) (string, error) ID(ctx context.Context, obj *entities.GlobalVPN) (repos.ID, error) - KloudliteDevice(ctx context.Context, obj *entities.GlobalVPN) (*model.GlobalVPNKloudliteDevice, error) + KloudliteClusterLocalDevice(ctx context.Context, obj *entities.GlobalVPN) (*model.GlobalVPNKloudliteClusterLocalDevice, error) + KloudliteGatewayDevice(ctx context.Context, obj *entities.GlobalVPN) (*model.GlobalVPNKloudliteGatewayDevice, error) UpdateTime(ctx context.Context, obj *entities.GlobalVPN) (string, error) } @@ -1662,7 +1669,6 @@ type GlobalVPNDeviceInResolver interface { Metadata(ctx context.Context, obj *entities.GlobalVPNDevice, data *v1.ObjectMeta) error } type GlobalVPNInResolver interface { - KloudliteDevice(ctx context.Context, obj *entities.GlobalVPN, data *model.GlobalVPNKloudliteDeviceIn) error Metadata(ctx context.Context, obj *entities.GlobalVPN, data *v1.ObjectMeta) error } type HelmReleaseInResolver interface { @@ -4085,12 +4091,19 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.GlobalVPN.ID(childComplexity), true - case "GlobalVPN.kloudliteDevice": - if e.complexity.GlobalVPN.KloudliteDevice == nil { + case "GlobalVPN.kloudliteClusterLocalDevice": + if e.complexity.GlobalVPN.KloudliteClusterLocalDevice == nil { break } - return e.complexity.GlobalVPN.KloudliteDevice(childComplexity), true + return e.complexity.GlobalVPN.KloudliteClusterLocalDevice(childComplexity), true + + case "GlobalVPN.kloudliteGatewayDevice": + if e.complexity.GlobalVPN.KloudliteGatewayDevice == nil { + break + } + + return e.complexity.GlobalVPN.KloudliteGatewayDevice(childComplexity), true case "GlobalVPN.lastUpdatedBy": if e.complexity.GlobalVPN.LastUpdatedBy == nil { @@ -4330,19 +4343,33 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.GlobalVPNEdge.Node(childComplexity), true - case "GlobalVPNKloudliteDevice.ipAddr": - if e.complexity.GlobalVPNKloudliteDevice.IPAddr == nil { + case "GlobalVPNKloudliteClusterLocalDevice.ipAddr": + if e.complexity.GlobalVPNKloudliteClusterLocalDevice.IPAddr == nil { break } - return e.complexity.GlobalVPNKloudliteDevice.IPAddr(childComplexity), true + return e.complexity.GlobalVPNKloudliteClusterLocalDevice.IPAddr(childComplexity), true - case "GlobalVPNKloudliteDevice.name": - if e.complexity.GlobalVPNKloudliteDevice.Name == nil { + case "GlobalVPNKloudliteClusterLocalDevice.name": + if e.complexity.GlobalVPNKloudliteClusterLocalDevice.Name == nil { break } - return e.complexity.GlobalVPNKloudliteDevice.Name(childComplexity), true + return e.complexity.GlobalVPNKloudliteClusterLocalDevice.Name(childComplexity), true + + case "GlobalVPNKloudliteGatewayDevice.ipAddr": + if e.complexity.GlobalVPNKloudliteGatewayDevice.IPAddr == nil { + break + } + + return e.complexity.GlobalVPNKloudliteGatewayDevice.IPAddr(childComplexity), true + + case "GlobalVPNKloudliteGatewayDevice.name": + if e.complexity.GlobalVPNKloudliteGatewayDevice.Name == nil { + break + } + + return e.complexity.GlobalVPNKloudliteGatewayDevice.Name(childComplexity), true case "GlobalVPNPaginatedRecords.edges": if e.complexity.GlobalVPNPaginatedRecords.Edges == nil { @@ -7984,7 +8011,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputGithub__com___kloudlite___operator___apis___crds___v1__ServiceTemplateIn, ec.unmarshalInputGlobalVPNDeviceIn, ec.unmarshalInputGlobalVPNIn, - ec.unmarshalInputGlobalVPNKloudliteDeviceIn, ec.unmarshalInputHelmReleaseIn, ec.unmarshalInputK8s__io___api___core___v1__AWSElasticBlockStoreVolumeSourceIn, ec.unmarshalInputK8s__io___api___core___v1__AffinityIn, @@ -10084,7 +10110,8 @@ input DomainEntryIn { creationTime: Date! displayName: String! id: ID! - kloudliteDevice: GlobalVPNKloudliteDevice! + kloudliteClusterLocalDevice: GlobalVPNKloudliteClusterLocalDevice! + kloudliteGatewayDevice: GlobalVPNKloudliteGatewayDevice! lastUpdatedBy: Github__com___kloudlite___api___common__CreatedOrUpdatedBy! markedForDeletion: Boolean metadata: Metadata! @goField(name: "objectMeta") @@ -10102,7 +10129,12 @@ type GlobalVPNEdge @shareable { node: GlobalVPN! } -type GlobalVPNKloudliteDevice @shareable { +type GlobalVPNKloudliteClusterLocalDevice @shareable { + ipAddr: String! + name: String! +} + +type GlobalVPNKloudliteGatewayDevice @shareable { ipAddr: String! name: String! } @@ -10117,7 +10149,6 @@ input GlobalVPNIn { allocatableCIDRSuffix: Int! CIDR: String! displayName: String! - kloudliteDevice: GlobalVPNKloudliteDeviceIn! metadata: MetadataIn! nonClusterUseAllowedIPs: [String!]! numAllocatedClusterCIDRs: Int! @@ -10126,11 +10157,6 @@ input GlobalVPNIn { wgInterface: String! } -input GlobalVPNKloudliteDeviceIn { - ipAddr: String! - name: String! -} - `, BuiltIn: false}, {Name: "../struct-to-graphql/globalvpndevice.graphqls", Input: `type GlobalVPNDevice @shareable { accountName: String! @@ -27388,8 +27414,58 @@ func (ec *executionContext) fieldContext_GlobalVPN_id(ctx context.Context, field return fc, nil } -func (ec *executionContext) _GlobalVPN_kloudliteDevice(ctx context.Context, field graphql.CollectedField, obj *entities.GlobalVPN) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GlobalVPN_kloudliteDevice(ctx, field) +func (ec *executionContext) _GlobalVPN_kloudliteClusterLocalDevice(ctx context.Context, field graphql.CollectedField, obj *entities.GlobalVPN) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GlobalVPN_kloudliteClusterLocalDevice(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.GlobalVPN().KloudliteClusterLocalDevice(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.GlobalVPNKloudliteClusterLocalDevice) + fc.Result = res + return ec.marshalNGlobalVPNKloudliteClusterLocalDevice2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteClusterLocalDevice(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_GlobalVPN_kloudliteClusterLocalDevice(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "GlobalVPN", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "ipAddr": + return ec.fieldContext_GlobalVPNKloudliteClusterLocalDevice_ipAddr(ctx, field) + case "name": + return ec.fieldContext_GlobalVPNKloudliteClusterLocalDevice_name(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type GlobalVPNKloudliteClusterLocalDevice", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _GlobalVPN_kloudliteGatewayDevice(ctx context.Context, field graphql.CollectedField, obj *entities.GlobalVPN) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GlobalVPN_kloudliteGatewayDevice(ctx, field) if err != nil { return graphql.Null } @@ -27402,7 +27478,7 @@ func (ec *executionContext) _GlobalVPN_kloudliteDevice(ctx context.Context, fiel }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.GlobalVPN().KloudliteDevice(rctx, obj) + return ec.resolvers.GlobalVPN().KloudliteGatewayDevice(rctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -27414,12 +27490,12 @@ func (ec *executionContext) _GlobalVPN_kloudliteDevice(ctx context.Context, fiel } return graphql.Null } - res := resTmp.(*model.GlobalVPNKloudliteDevice) + res := resTmp.(*model.GlobalVPNKloudliteGatewayDevice) fc.Result = res - return ec.marshalNGlobalVPNKloudliteDevice2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteDevice(ctx, field.Selections, res) + return ec.marshalNGlobalVPNKloudliteGatewayDevice2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteGatewayDevice(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GlobalVPN_kloudliteDevice(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GlobalVPN_kloudliteGatewayDevice(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GlobalVPN", Field: field, @@ -27428,11 +27504,11 @@ func (ec *executionContext) fieldContext_GlobalVPN_kloudliteDevice(ctx context.C Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "ipAddr": - return ec.fieldContext_GlobalVPNKloudliteDevice_ipAddr(ctx, field) + return ec.fieldContext_GlobalVPNKloudliteGatewayDevice_ipAddr(ctx, field) case "name": - return ec.fieldContext_GlobalVPNKloudliteDevice_name(ctx, field) + return ec.fieldContext_GlobalVPNKloudliteGatewayDevice_name(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type GlobalVPNKloudliteDevice", field.Name) + return nil, fmt.Errorf("no field named %q was found under type GlobalVPNKloudliteGatewayDevice", field.Name) }, } return fc, nil @@ -29042,8 +29118,10 @@ func (ec *executionContext) fieldContext_GlobalVPNEdge_node(ctx context.Context, return ec.fieldContext_GlobalVPN_displayName(ctx, field) case "id": return ec.fieldContext_GlobalVPN_id(ctx, field) - case "kloudliteDevice": - return ec.fieldContext_GlobalVPN_kloudliteDevice(ctx, field) + case "kloudliteClusterLocalDevice": + return ec.fieldContext_GlobalVPN_kloudliteClusterLocalDevice(ctx, field) + case "kloudliteGatewayDevice": + return ec.fieldContext_GlobalVPN_kloudliteGatewayDevice(ctx, field) case "lastUpdatedBy": return ec.fieldContext_GlobalVPN_lastUpdatedBy(ctx, field) case "markedForDeletion": @@ -29071,8 +29149,8 @@ func (ec *executionContext) fieldContext_GlobalVPNEdge_node(ctx context.Context, return fc, nil } -func (ec *executionContext) _GlobalVPNKloudliteDevice_ipAddr(ctx context.Context, field graphql.CollectedField, obj *model.GlobalVPNKloudliteDevice) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GlobalVPNKloudliteDevice_ipAddr(ctx, field) +func (ec *executionContext) _GlobalVPNKloudliteClusterLocalDevice_ipAddr(ctx context.Context, field graphql.CollectedField, obj *model.GlobalVPNKloudliteClusterLocalDevice) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GlobalVPNKloudliteClusterLocalDevice_ipAddr(ctx, field) if err != nil { return graphql.Null } @@ -29102,9 +29180,9 @@ func (ec *executionContext) _GlobalVPNKloudliteDevice_ipAddr(ctx context.Context return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GlobalVPNKloudliteDevice_ipAddr(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GlobalVPNKloudliteClusterLocalDevice_ipAddr(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "GlobalVPNKloudliteDevice", + Object: "GlobalVPNKloudliteClusterLocalDevice", Field: field, IsMethod: false, IsResolver: false, @@ -29115,8 +29193,8 @@ func (ec *executionContext) fieldContext_GlobalVPNKloudliteDevice_ipAddr(ctx con return fc, nil } -func (ec *executionContext) _GlobalVPNKloudliteDevice_name(ctx context.Context, field graphql.CollectedField, obj *model.GlobalVPNKloudliteDevice) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GlobalVPNKloudliteDevice_name(ctx, field) +func (ec *executionContext) _GlobalVPNKloudliteClusterLocalDevice_name(ctx context.Context, field graphql.CollectedField, obj *model.GlobalVPNKloudliteClusterLocalDevice) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GlobalVPNKloudliteClusterLocalDevice_name(ctx, field) if err != nil { return graphql.Null } @@ -29146,9 +29224,97 @@ func (ec *executionContext) _GlobalVPNKloudliteDevice_name(ctx context.Context, return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GlobalVPNKloudliteDevice_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GlobalVPNKloudliteClusterLocalDevice_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "GlobalVPNKloudliteDevice", + Object: "GlobalVPNKloudliteClusterLocalDevice", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _GlobalVPNKloudliteGatewayDevice_ipAddr(ctx context.Context, field graphql.CollectedField, obj *model.GlobalVPNKloudliteGatewayDevice) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GlobalVPNKloudliteGatewayDevice_ipAddr(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IPAddr, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_GlobalVPNKloudliteGatewayDevice_ipAddr(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "GlobalVPNKloudliteGatewayDevice", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _GlobalVPNKloudliteGatewayDevice_name(ctx context.Context, field graphql.CollectedField, obj *model.GlobalVPNKloudliteGatewayDevice) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GlobalVPNKloudliteGatewayDevice_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_GlobalVPNKloudliteGatewayDevice_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "GlobalVPNKloudliteGatewayDevice", Field: field, IsMethod: false, IsResolver: false, @@ -42119,8 +42285,10 @@ func (ec *executionContext) fieldContext_Mutation_infra_createGlobalVPN(ctx cont return ec.fieldContext_GlobalVPN_displayName(ctx, field) case "id": return ec.fieldContext_GlobalVPN_id(ctx, field) - case "kloudliteDevice": - return ec.fieldContext_GlobalVPN_kloudliteDevice(ctx, field) + case "kloudliteClusterLocalDevice": + return ec.fieldContext_GlobalVPN_kloudliteClusterLocalDevice(ctx, field) + case "kloudliteGatewayDevice": + return ec.fieldContext_GlobalVPN_kloudliteGatewayDevice(ctx, field) case "lastUpdatedBy": return ec.fieldContext_GlobalVPN_lastUpdatedBy(ctx, field) case "markedForDeletion": @@ -42235,8 +42403,10 @@ func (ec *executionContext) fieldContext_Mutation_infra_updateGlobalVPN(ctx cont return ec.fieldContext_GlobalVPN_displayName(ctx, field) case "id": return ec.fieldContext_GlobalVPN_id(ctx, field) - case "kloudliteDevice": - return ec.fieldContext_GlobalVPN_kloudliteDevice(ctx, field) + case "kloudliteClusterLocalDevice": + return ec.fieldContext_GlobalVPN_kloudliteClusterLocalDevice(ctx, field) + case "kloudliteGatewayDevice": + return ec.fieldContext_GlobalVPN_kloudliteGatewayDevice(ctx, field) case "lastUpdatedBy": return ec.fieldContext_GlobalVPN_lastUpdatedBy(ctx, field) case "markedForDeletion": @@ -50676,8 +50846,10 @@ func (ec *executionContext) fieldContext_Query_infra_getGlobalVPN(ctx context.Co return ec.fieldContext_GlobalVPN_displayName(ctx, field) case "id": return ec.fieldContext_GlobalVPN_id(ctx, field) - case "kloudliteDevice": - return ec.fieldContext_GlobalVPN_kloudliteDevice(ctx, field) + case "kloudliteClusterLocalDevice": + return ec.fieldContext_GlobalVPN_kloudliteClusterLocalDevice(ctx, field) + case "kloudliteGatewayDevice": + return ec.fieldContext_GlobalVPN_kloudliteGatewayDevice(ctx, field) case "lastUpdatedBy": return ec.fieldContext_GlobalVPN_lastUpdatedBy(ctx, field) case "markedForDeletion": @@ -57364,7 +57536,7 @@ func (ec *executionContext) unmarshalInputGlobalVPNIn(ctx context.Context, obj i asMap[k] = v } - fieldsInOrder := [...]string{"allocatableCIDRSuffix", "CIDR", "displayName", "kloudliteDevice", "metadata", "nonClusterUseAllowedIPs", "numAllocatedClusterCIDRs", "numAllocatedDevices", "numReservedIPsForNonClusterUse", "wgInterface"} + fieldsInOrder := [...]string{"allocatableCIDRSuffix", "CIDR", "displayName", "metadata", "nonClusterUseAllowedIPs", "numAllocatedClusterCIDRs", "numAllocatedDevices", "numReservedIPsForNonClusterUse", "wgInterface"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -57392,15 +57564,6 @@ func (ec *executionContext) unmarshalInputGlobalVPNIn(ctx context.Context, obj i return it, err } it.DisplayName = data - case "kloudliteDevice": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("kloudliteDevice")) - data, err := ec.unmarshalNGlobalVPNKloudliteDeviceIn2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteDeviceIn(ctx, v) - if err != nil { - return it, err - } - if err = ec.resolvers.GlobalVPNIn().KloudliteDevice(ctx, &it, data); err != nil { - return it, err - } case "metadata": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("metadata")) data, err := ec.unmarshalNMetadataIn2ᚖk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐObjectMeta(ctx, v) @@ -57451,40 +57614,6 @@ func (ec *executionContext) unmarshalInputGlobalVPNIn(ctx context.Context, obj i return it, nil } -func (ec *executionContext) unmarshalInputGlobalVPNKloudliteDeviceIn(ctx context.Context, obj interface{}) (model.GlobalVPNKloudliteDeviceIn, error) { - var it model.GlobalVPNKloudliteDeviceIn - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"ipAddr", "name"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "ipAddr": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ipAddr")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.IPAddr = data - case "name": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Name = data - } - } - - return it, nil -} - func (ec *executionContext) unmarshalInputHelmReleaseIn(ctx context.Context, obj interface{}) (entities.HelmRelease, error) { var it entities.HelmRelease asMap := map[string]interface{}{} @@ -65973,7 +66102,7 @@ func (ec *executionContext) _GlobalVPN(ctx context.Context, sel ast.SelectionSet } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - case "kloudliteDevice": + case "kloudliteClusterLocalDevice": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { @@ -65982,7 +66111,43 @@ func (ec *executionContext) _GlobalVPN(ctx context.Context, sel ast.SelectionSet ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._GlobalVPN_kloudliteDevice(ctx, field, obj) + res = ec._GlobalVPN_kloudliteClusterLocalDevice(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "kloudliteGatewayDevice": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._GlobalVPN_kloudliteGatewayDevice(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } @@ -66478,24 +66643,68 @@ func (ec *executionContext) _GlobalVPNEdge(ctx context.Context, sel ast.Selectio return out } -var globalVPNKloudliteDeviceImplementors = []string{"GlobalVPNKloudliteDevice"} +var globalVPNKloudliteClusterLocalDeviceImplementors = []string{"GlobalVPNKloudliteClusterLocalDevice"} + +func (ec *executionContext) _GlobalVPNKloudliteClusterLocalDevice(ctx context.Context, sel ast.SelectionSet, obj *model.GlobalVPNKloudliteClusterLocalDevice) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, globalVPNKloudliteClusterLocalDeviceImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("GlobalVPNKloudliteClusterLocalDevice") + case "ipAddr": + out.Values[i] = ec._GlobalVPNKloudliteClusterLocalDevice_ipAddr(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._GlobalVPNKloudliteClusterLocalDevice_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var globalVPNKloudliteGatewayDeviceImplementors = []string{"GlobalVPNKloudliteGatewayDevice"} -func (ec *executionContext) _GlobalVPNKloudliteDevice(ctx context.Context, sel ast.SelectionSet, obj *model.GlobalVPNKloudliteDevice) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, globalVPNKloudliteDeviceImplementors) +func (ec *executionContext) _GlobalVPNKloudliteGatewayDevice(ctx context.Context, sel ast.SelectionSet, obj *model.GlobalVPNKloudliteGatewayDevice) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, globalVPNKloudliteGatewayDeviceImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("GlobalVPNKloudliteDevice") + out.Values[i] = graphql.MarshalString("GlobalVPNKloudliteGatewayDevice") case "ipAddr": - out.Values[i] = ec._GlobalVPNKloudliteDevice_ipAddr(ctx, field, obj) + out.Values[i] = ec._GlobalVPNKloudliteGatewayDevice_ipAddr(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "name": - out.Values[i] = ec._GlobalVPNKloudliteDevice_name(ctx, field, obj) + out.Values[i] = ec._GlobalVPNKloudliteGatewayDevice_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -74174,28 +74383,32 @@ func (ec *executionContext) unmarshalNGlobalVPNIn2githubᚗcomᚋkloudliteᚋapi return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNGlobalVPNKloudliteDevice2githubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteDevice(ctx context.Context, sel ast.SelectionSet, v model.GlobalVPNKloudliteDevice) graphql.Marshaler { - return ec._GlobalVPNKloudliteDevice(ctx, sel, &v) +func (ec *executionContext) marshalNGlobalVPNKloudliteClusterLocalDevice2githubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteClusterLocalDevice(ctx context.Context, sel ast.SelectionSet, v model.GlobalVPNKloudliteClusterLocalDevice) graphql.Marshaler { + return ec._GlobalVPNKloudliteClusterLocalDevice(ctx, sel, &v) } -func (ec *executionContext) marshalNGlobalVPNKloudliteDevice2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteDevice(ctx context.Context, sel ast.SelectionSet, v *model.GlobalVPNKloudliteDevice) graphql.Marshaler { +func (ec *executionContext) marshalNGlobalVPNKloudliteClusterLocalDevice2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteClusterLocalDevice(ctx context.Context, sel ast.SelectionSet, v *model.GlobalVPNKloudliteClusterLocalDevice) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } - return ec._GlobalVPNKloudliteDevice(ctx, sel, v) + return ec._GlobalVPNKloudliteClusterLocalDevice(ctx, sel, v) } -func (ec *executionContext) unmarshalNGlobalVPNKloudliteDeviceIn2githubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteDeviceIn(ctx context.Context, v interface{}) (model.GlobalVPNKloudliteDeviceIn, error) { - res, err := ec.unmarshalInputGlobalVPNKloudliteDeviceIn(ctx, v) - return res, graphql.ErrorOnPath(ctx, err) +func (ec *executionContext) marshalNGlobalVPNKloudliteGatewayDevice2githubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteGatewayDevice(ctx context.Context, sel ast.SelectionSet, v model.GlobalVPNKloudliteGatewayDevice) graphql.Marshaler { + return ec._GlobalVPNKloudliteGatewayDevice(ctx, sel, &v) } -func (ec *executionContext) unmarshalNGlobalVPNKloudliteDeviceIn2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteDeviceIn(ctx context.Context, v interface{}) (*model.GlobalVPNKloudliteDeviceIn, error) { - res, err := ec.unmarshalInputGlobalVPNKloudliteDeviceIn(ctx, v) - return &res, graphql.ErrorOnPath(ctx, err) +func (ec *executionContext) marshalNGlobalVPNKloudliteGatewayDevice2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋappᚋgraphᚋmodelᚐGlobalVPNKloudliteGatewayDevice(ctx context.Context, sel ast.SelectionSet, v *model.GlobalVPNKloudliteGatewayDevice) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._GlobalVPNKloudliteGatewayDevice(ctx, sel, v) } func (ec *executionContext) marshalNHelmRelease2ᚖgithubᚗcomᚋkloudliteᚋapiᚋappsᚋinfraᚋinternalᚋentitiesᚐHelmRelease(ctx context.Context, sel ast.SelectionSet, v *entities.HelmRelease) graphql.Marshaler { @@ -75570,7 +75783,7 @@ func (ec *executionContext) marshalNfederation__Scope2ᚕᚕstringᚄ(ctx contex return ret } -func (ec *executionContext) unmarshalOAny2interface(ctx context.Context, v interface{}) (interface{}, error) { +func (ec *executionContext) unmarshalOAny2interface(ctx context.Context, v interface{}) (any, error) { if v == nil { return nil, nil } @@ -75578,7 +75791,7 @@ func (ec *executionContext) unmarshalOAny2interface(ctx context.Context, v inter return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalOAny2interface(ctx context.Context, sel ast.SelectionSet, v interface{}) graphql.Marshaler { +func (ec *executionContext) marshalOAny2interface(ctx context.Context, sel ast.SelectionSet, v any) graphql.Marshaler { if v == nil { return graphql.Null } diff --git a/apps/infra/internal/app/graph/globalvpn.resolvers.go b/apps/infra/internal/app/graph/globalvpn.resolvers.go index 41882f72a..9d75386b9 100644 --- a/apps/infra/internal/app/graph/globalvpn.resolvers.go +++ b/apps/infra/internal/app/graph/globalvpn.resolvers.go @@ -6,7 +6,6 @@ package graph import ( "context" - "fmt" "github.com/kloudlite/api/pkg/errors" "time" @@ -34,9 +33,14 @@ func (r *globalVPNResolver) ID(ctx context.Context, obj *entities.GlobalVPN) (re return obj.Id, nil } -// KloudliteDevice is the resolver for the kloudliteDevice field. -func (r *globalVPNResolver) KloudliteDevice(ctx context.Context, obj *entities.GlobalVPN) (*model.GlobalVPNKloudliteDevice, error) { - panic(fmt.Errorf("not implemented: KloudliteDevice - kloudliteDevice")) +// KloudliteClusterLocalDevice is the resolver for the kloudliteClusterLocalDevice field. +func (r *globalVPNResolver) KloudliteClusterLocalDevice(ctx context.Context, obj *entities.GlobalVPN) (*model.GlobalVPNKloudliteClusterLocalDevice, error) { + return fn.JsonConvertP[model.GlobalVPNKloudliteClusterLocalDevice](obj.KloudliteClusterLocalDevice) +} + +// KloudliteGatewayDevice is the resolver for the kloudliteGatewayDevice field. +func (r *globalVPNResolver) KloudliteGatewayDevice(ctx context.Context, obj *entities.GlobalVPN) (*model.GlobalVPNKloudliteGatewayDevice, error) { + return fn.JsonConvertP[model.GlobalVPNKloudliteGatewayDevice](obj.KloudliteGatewayDevice) } // UpdateTime is the resolver for the updateTime field. @@ -47,11 +51,6 @@ func (r *globalVPNResolver) UpdateTime(ctx context.Context, obj *entities.Global return obj.UpdateTime.Format(time.RFC3339), nil } -// KloudliteDevice is the resolver for the kloudliteDevice field. -func (r *globalVPNInResolver) KloudliteDevice(ctx context.Context, obj *entities.GlobalVPN, data *model.GlobalVPNKloudliteDeviceIn) error { - panic(fmt.Errorf("not implemented: KloudliteDevice - kloudliteDevice")) -} - // Metadata is the resolver for the metadata field. func (r *globalVPNInResolver) Metadata(ctx context.Context, obj *entities.GlobalVPN, data *v1.ObjectMeta) error { if obj == nil { diff --git a/apps/infra/internal/app/graph/model/models_gen.go b/apps/infra/internal/app/graph/model/models_gen.go index 60fdab6df..d69bd2c4c 100644 --- a/apps/infra/internal/app/graph/model/models_gen.go +++ b/apps/infra/internal/app/graph/model/models_gen.go @@ -551,12 +551,12 @@ type GlobalVPNEdge struct { Node *entities.GlobalVPN `json:"node"` } -type GlobalVPNKloudliteDevice struct { +type GlobalVPNKloudliteClusterLocalDevice struct { IPAddr string `json:"ipAddr"` Name string `json:"name"` } -type GlobalVPNKloudliteDeviceIn struct { +type GlobalVPNKloudliteGatewayDevice struct { IPAddr string `json:"ipAddr"` Name string `json:"name"` } diff --git a/apps/infra/internal/app/graph/struct-to-graphql/globalvpn.graphqls b/apps/infra/internal/app/graph/struct-to-graphql/globalvpn.graphqls index 2e4aac61f..c31056714 100644 --- a/apps/infra/internal/app/graph/struct-to-graphql/globalvpn.graphqls +++ b/apps/infra/internal/app/graph/struct-to-graphql/globalvpn.graphqls @@ -6,7 +6,8 @@ type GlobalVPN @shareable { creationTime: Date! displayName: String! id: ID! - kloudliteDevice: GlobalVPNKloudliteDevice! + kloudliteClusterLocalDevice: GlobalVPNKloudliteClusterLocalDevice! + kloudliteGatewayDevice: GlobalVPNKloudliteGatewayDevice! lastUpdatedBy: Github__com___kloudlite___api___common__CreatedOrUpdatedBy! markedForDeletion: Boolean metadata: Metadata! @goField(name: "objectMeta") @@ -24,7 +25,12 @@ type GlobalVPNEdge @shareable { node: GlobalVPN! } -type GlobalVPNKloudliteDevice @shareable { +type GlobalVPNKloudliteClusterLocalDevice @shareable { + ipAddr: String! + name: String! +} + +type GlobalVPNKloudliteGatewayDevice @shareable { ipAddr: String! name: String! } @@ -39,7 +45,6 @@ input GlobalVPNIn { allocatableCIDRSuffix: Int! CIDR: String! displayName: String! - kloudliteDevice: GlobalVPNKloudliteDeviceIn! metadata: MetadataIn! nonClusterUseAllowedIPs: [String!]! numAllocatedClusterCIDRs: Int! @@ -48,8 +53,3 @@ input GlobalVPNIn { wgInterface: String! } -input GlobalVPNKloudliteDeviceIn { - ipAddr: String! - name: String! -} - diff --git a/apps/infra/internal/entities/global-vpn.go b/apps/infra/internal/entities/global-vpn.go index 66ce8031c..19611d081 100644 --- a/apps/infra/internal/entities/global-vpn.go +++ b/apps/infra/internal/entities/global-vpn.go @@ -45,12 +45,12 @@ type GlobalVPN struct { KloudliteGatewayDevice struct { Name string `json:"name"` IPAddr string `json:"ipAddr"` - } `json:"kloudliteGatewayDevice"` + } `json:"kloudliteGatewayDevice" graphql:"noinput"` KloudliteClusterLocalDevice struct { Name string `json:"name"` IPAddr string `json:"ipAddr"` - } `json:"kloudliteClusterLocalDevice"` + } `json:"kloudliteClusterLocalDevice" graphql:"noinput"` } func (c *GlobalVPN) GetDisplayName() string { diff --git a/apps/websocket-server/internal/domain/resource-update.go b/apps/websocket-server/internal/domain/resource-update.go index 7b567c7fd..8eb0b1c2f 100644 --- a/apps/websocket-server/internal/domain/resource-update.go +++ b/apps/websocket-server/internal/domain/resource-update.go @@ -91,6 +91,7 @@ func (d *domain) handleResWatchMsg(ctx types.Context, resources *res_watch.ResWa Id: msg.Id, }); err != nil { utils.WriteError(ctx, err, msg.Id, types.ForResourceUpdate) + return } }) @@ -114,6 +115,7 @@ func (d *domain) handleResWatchMsg(ctx types.Context, resources *res_watch.ResWa delete(*resources, rd.Topic) utils.WriteInfo(ctx, fmt.Sprintf("unsubscribed from %s", rd.Topic), msg.Id, types.ForResourceUpdate) + return nil } utils.WriteError(ctx, fmt.Errorf("resource not found"), msg.Id, types.ForResourceUpdate) diff --git a/pkg/repos/mongo.go b/pkg/repos/mongo.go index 8662f9d45..a988a87de 100644 --- a/pkg/repos/mongo.go +++ b/pkg/repos/mongo.go @@ -12,6 +12,7 @@ import ( ) func NewMongoDatabase(ctx context.Context, uri string, dbName string) (db *mongo.Database, e error) { + // client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri).SetReadPreference(readpref.SecondaryPreferred())) client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri)) if err != nil { return nil, errors.NewEf(err, "could not connect to mongodb servers") @@ -36,6 +37,7 @@ func NewMongoClientFx[T MongoConfig]() fx.Option { lifecycle.Append(fx.Hook{ OnStart: func(ctx context.Context) error { if err := db.Client().Ping(ctx, nil); err != nil { + // if err := db.Client().Ping(ctx, readpref.Primary()); err != nil { return errors.NewEf(err, "could not ping Mongo") } logger.Infof("connected to mongodb database: %s", db.Name()) From 5195dc64bb64df7514625b4bd8c0b60c56d65bd8 Mon Sep 17 00:00:00 2001 From: Abdhesh Nayak Date: Fri, 28 Jun 2024 13:03:39 +0530 Subject: [PATCH 7/9] :bug: Added msvc archive to byok-clusters --- apps/infra/internal/domain/byok-clusters.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/infra/internal/domain/byok-clusters.go b/apps/infra/internal/domain/byok-clusters.go index c0f8973cc..be0cb87f9 100644 --- a/apps/infra/internal/domain/byok-clusters.go +++ b/apps/infra/internal/domain/byok-clusters.go @@ -221,6 +221,10 @@ func (d *domain) DeleteBYOKCluster(ctx InfraContext, name string) error { return errors.NewE(err) } + if err := d.ArchiveClusterManagedService(ctx, name); err != nil { + return errors.NewE(err) + } + if err := d.byokClusterRepo.DeleteOne(ctx, entities.UniqueBYOKClusterFilter(ctx.AccountName, name)); err != nil { return errors.NewE(err) } From 5a6308ad6ffe5a83acfb433432bfa6b097970e75 Mon Sep 17 00:00:00 2001 From: Piyush Kumar Date: Fri, 28 Jun 2024 16:16:47 +0530 Subject: [PATCH 8/9] remove app and external app intercept while cloning environment --- apps/console/internal/domain/environment.go | 30 ++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/apps/console/internal/domain/environment.go b/apps/console/internal/domain/environment.go index 1649d987d..08f149e16 100644 --- a/apps/console/internal/domain/environment.go +++ b/apps/console/internal/domain/environment.go @@ -277,6 +277,14 @@ func (d *domain) CloneEnvironment(ctx ConsoleContext, args CloneEnvironmentArgs) return nil, errors.NewE(err) } + externalApps, err := d.externalAppRepo.Find(ctx, repos.Query{ + Filter: filters, + Sort: nil, + }) + if err != nil { + return nil, errors.NewE(err) + } + secrets, err := d.secretRepo.Find(ctx, repos.Query{ Filter: filters, Sort: nil, @@ -322,11 +330,13 @@ func (d *domain) CloneEnvironment(ctx ConsoleContext, args CloneEnvironmentArgs) } for i := range apps { + appSpec := apps[i].Spec + appSpec.Intercept = nil if _, err := d.createAndApplyApp(resCtx, &entities.App{ App: crdsv1.App{ TypeMeta: apps[i].TypeMeta, ObjectMeta: objectMeta(apps[i].ObjectMeta, destEnv.Spec.TargetNamespace), - Spec: apps[i].Spec, + Spec: appSpec, }, AccountName: ctx.AccountName, EnvironmentName: destEnv.Name, @@ -337,6 +347,24 @@ func (d *domain) CloneEnvironment(ctx ConsoleContext, args CloneEnvironmentArgs) } } + for i := range externalApps { + externalAppSpec := externalApps[i].Spec + externalAppSpec.Intercept = nil + if _, err := d.createAndApplyExternalApp(resCtx, &entities.ExternalApp{ + ExternalApp: crdsv1.ExternalApp{ + TypeMeta: externalApps[i].TypeMeta, + ObjectMeta: objectMeta(externalApps[i].ObjectMeta, destEnv.Spec.TargetNamespace), + Spec: externalAppSpec, + }, + AccountName: ctx.AccountName, + EnvironmentName: destEnv.Name, + ResourceMetadata: resourceMetadata(externalApps[i].DisplayName), + SyncStatus: t.GenSyncStatus(t.SyncActionApply, 0), + }); err != nil { + return nil, err + } + } + for i := range secrets { if _, err := d.createAndApplySecret(resCtx, &entities.Secret{ Secret: corev1.Secret{ From e3571b874f95ed425e516651d30d3210e0e9e3ba Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Sat, 29 Jun 2024 11:33:03 +0530 Subject: [PATCH 9/9] ci: not pushing image on github PRs --- .github/actions/build-api-images/action.yml | 36 +++++++++++++-------- .tools/taskfiles/docker.Taskfile.yml | 4 ++- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/.github/actions/build-api-images/action.yml b/.github/actions/build-api-images/action.yml index 5d09e2d56..eb06318cf 100644 --- a/.github/actions/build-api-images/action.yml +++ b/.github/actions/build-api-images/action.yml @@ -102,6 +102,7 @@ runs: echo "GOMODCACHE=$GOMODCACHE" >> $GITHUB_ENV echo "GOCACHE=$GOCACHE" >> $GITHUB_ENV echo "FILES_HASH=${{ hashFiles('**/*.go', '**/go.mod', '**/go.sum')}}" >> $GITHUB_OUTPUT + echo "PUSH_IMAGE=false" >> $GITHUB_ENV - name: ensures path to setup action exists shell: bash @@ -132,6 +133,13 @@ runs: docker_username: ${{ github.actor }} docker_password: ${{ inputs.github_token }} + + - name: check if image needs to be pushed + if: github.event_name != 'pull_request' + shell: bash + run: |+ + echo "PUSH_IMAGE=true" >> $GITHUB_ENV + - name: Create Image Tag if: ${{ inputs.image_tag != '' }} shell: bash @@ -181,7 +189,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/accounts shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/accounts:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/accounts:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: auth api go build cache if: ${{ inputs.auth-api == 'true' }} @@ -199,7 +207,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/auth shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/auth:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/auth:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: comms api go build cache if: ${{ inputs.comms-api == 'true' }} @@ -217,7 +225,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/comms shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/comms:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/comms:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: console api go build cache if: ${{ inputs.console-api == 'true' }} @@ -235,7 +243,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/console shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/console:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/console:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: container-registry api go build cache if: ${{ inputs.container-registry-api == 'true' }} @@ -253,7 +261,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/container-registry shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/container-registry:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/container-registry:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: gateway api go build cache if: ${{ inputs.gateway-api == 'true' }} @@ -271,7 +279,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/gateway shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/gateway:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/gateway:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: iam api go build cache if: ${{ inputs.iam-api == 'true' }} @@ -289,7 +297,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/iam shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/iam:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/iam:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: infra api go build cache if: ${{ inputs.infra-api == 'true' }} @@ -307,7 +315,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/infra shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/infra:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/infra:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: iot-console api go build cache if: ${{ inputs.iot-console-api == 'true' }} @@ -325,7 +333,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/iot-console shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/iot-console:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/iot-console:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: message-office api go build cache if: ${{ inputs.message-office-api == 'true' }} @@ -343,7 +351,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/message-office shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/message-office:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/message-office:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: observability api go build cache if: ${{ inputs.observability-api == 'true' }} @@ -361,7 +369,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/observability shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/observability:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/observability:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: tenant-agent go build cache if: ${{ inputs.tenant-agent == 'true' }} @@ -379,7 +387,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/tenant-agent shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/tenant-agent:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/tenant-agent:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: webhook api go build cache if: ${{ inputs.webhook-api == 'true' }} @@ -397,7 +405,7 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/webhook shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/webhook:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/webhook:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} - name: websocket-server api go build cache if: ${{ inputs.websocket-server-api == 'true' }} @@ -415,5 +423,5 @@ runs: working-directory: ${{ inputs.git_directory }}/apps/websocket-server shell: bash run: | - task container:build-and-push image=ghcr.io/${{ github.repository }}/websocket-server:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE + task container:build-and-push image=ghcr.io/${{ github.repository }}/websocket-server:${IMAGE_TAG:-latest} upx=true override=$OVERRIDE_PUSHED_IMAGE push_image=${PUSH_IMAGE} diff --git a/.tools/taskfiles/docker.Taskfile.yml b/.tools/taskfiles/docker.Taskfile.yml index 2b492e8c1..70d4f596f 100644 --- a/.tools/taskfiles/docker.Taskfile.yml +++ b/.tools/taskfiles/docker.Taskfile.yml @@ -12,6 +12,8 @@ tasks: - "image" - "args" silent: true + vars: + push_image: "{{.push_image | default true}}" cmds: - cmd: |+ echo $(docker manifest inspect "{{.image}}" || echo "not-found") >/tmp/manifest-inspect-status 2>/dev/null @@ -20,4 +22,4 @@ tasks: echo "image exists, but overridden" fi - docker buildx build -t {{.image}} --output=type=image,compression=zstd,force-compression=true,compression-level=12,push=true {{.args}} + docker buildx build -t {{.image}} --output=type=image,compression=zstd,force-compression=true,compression-level=12,push={{.push_image}} {{.args}}