From 248749899473c4ec2e9434bdc6177df2515fd5ca Mon Sep 17 00:00:00 2001 From: Aditya Thebe Date: Wed, 19 Feb 2025 14:10:17 +0545 Subject: [PATCH 1/3] feat: permission for connection --- api/v1/permission_types.go | 5 +++++ go.mod | 2 +- go.sum | 2 -- notification/send.go | 6 ++---- playbook/runner/runner.go | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/api/v1/permission_types.go b/api/v1/permission_types.go index 740173cb4..6e0a4886f 100644 --- a/api/v1/permission_types.go +++ b/api/v1/permission_types.go @@ -95,6 +95,11 @@ type PermissionSubject struct { // Group is the group name Group string `json:"group,omitempty"` + + Playbook PermissionSubjectSelector `json:"playbook,omitempty"` + Canary PermissionSubjectSelector `json:"canary,omitempty"` + Scraper PermissionSubjectSelector `json:"scraper,omitempty"` + Topology PermissionSubjectSelector `json:"topology,omitempty"` } func (t *PermissionSubject) Validate() error { diff --git a/go.mod b/go.mod index 09920b8b6..5d6391998 100644 --- a/go.mod +++ b/go.mod @@ -367,7 +367,7 @@ require ( sigs.k8s.io/yaml v1.4.0 ) -// replace github.com/flanksource/duty => ../duty +replace github.com/flanksource/duty => ../duty // replace github.com/flanksource/gomplate/v3 => ../gomplat3 diff --git a/go.sum b/go.sum index 1a442c5df..902ccab5b 100644 --- a/go.sum +++ b/go.sum @@ -287,8 +287,6 @@ github.com/flanksource/artifacts v1.0.14 h1:Vv70bccsae0MwGaf/uSPp34J5V1/PyKfct9z github.com/flanksource/artifacts v1.0.14/go.mod h1:qHVCnQu5k50aWNJ5UhpcAKEl7pAzqUrFFKGSm147G70= github.com/flanksource/commons v1.36.1 h1:SDppXOYO6vk06d12SPOYVZJX+8gV72FmK1l9ar5fkjc= github.com/flanksource/commons v1.36.1/go.mod h1:nsYCn6JOhENXNLR5pz4zNco70DQV+bGObQ8NbOrUeuQ= -github.com/flanksource/duty v1.0.853 h1:0lvwYXeRk2fJGuF/1BvvYR629LYmEtwJgS6SFvh+VKg= -github.com/flanksource/duty v1.0.853/go.mod h1:hoCee0pTczWCMqgUsjhecE6+rkR+yhia7JzD4gqCeaE= github.com/flanksource/gomplate/v3 v3.24.55 h1:BW+KeMcggCkNawb4VTbY+Zn3s9eYIhwqb5/myiyJRb8= github.com/flanksource/gomplate/v3 v3.24.55/go.mod h1:hGEObNtnOQs8rNUX8sM8aJTAhnt4ehjyOw1MvDhl6AU= github.com/flanksource/is-healthy v1.0.61 h1:a+3KgNblosFXat7rht1RLTqRvF3pppd3yxCqi+LWWaU= diff --git a/notification/send.go b/notification/send.go index ec5fbdae5..d07e3d2aa 100644 --- a/notification/send.go +++ b/notification/send.go @@ -18,8 +18,8 @@ import ( "github.com/samber/lo" "go.opentelemetry.io/otel/trace" + pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/incident-commander/api" - "github.com/flanksource/incident-commander/db" "github.com/flanksource/incident-commander/logs" "github.com/flanksource/incident-commander/teams" @@ -193,11 +193,9 @@ func SendNotification(ctx *Context, connectionName, shoutrrrURL string, celEnv m var connection *models.Connection var err error if connectionName != "" { - connection, err = ctx.HydrateConnectionByURL(connectionName) + connection, err = pkgConnection.GetC(ctx.Context, connectionName) if err != nil { return "", err - } else if connection == nil { - return "", fmt.Errorf("connection (%s) not found", connectionName) } ctx.WithRecipient(RecipientTypeConnection, &connection.ID) diff --git a/playbook/runner/runner.go b/playbook/runner/runner.go index 6fd6b27a6..cab3fd8e7 100644 --- a/playbook/runner/runner.go +++ b/playbook/runner/runner.go @@ -273,7 +273,7 @@ func RunAction(ctx context.Context, run *models.PlaybookRun, action *models.Play return err } - ctx = ctx.WithObject(action, run) + ctx = ctx.WithObject(action, run).WithSubject(playbook.ID.String()) ctx, span := ctx.StartSpan(fmt.Sprintf("playbook.%s", playbook.Name)) defer span.End() From 9550a419676d19e4f4b5ac3063cd953a6d5c9de3 Mon Sep 17 00:00:00 2001 From: Aditya Thebe Date: Wed, 19 Feb 2025 14:19:41 +0545 Subject: [PATCH 2/3] feat: replace hydrateConnection with connection.Get --- api/notifications.go | 14 --- api/v1/permission_types.go | 22 ++++- api/v1/playbook_actions.go | 21 ++-- api/v1/zz_generated.deepcopy.go | 7 ++ artifacts/artifacts.go | 8 +- artifacts/controllers.go | 3 +- artifacts/jobs.go | 6 +- ...n-control.flanksource.com_permissions.yaml | 95 +++++++++++++++++++ config/schemas/permission.schema.json | 20 ++++ connection/controllers.go | 1 + fixtures/permissions/plyabook-connection.yaml | 15 +++ go.mod | 2 +- go.sum | 2 + notification/send.go | 4 +- playbook/actions/gitops.go | 10 +- playbook/actions/http.go | 3 +- playbook/actions/sql.go | 3 +- playbook/runner/artifacts.go | 3 +- 18 files changed, 191 insertions(+), 48 deletions(-) create mode 100644 fixtures/permissions/plyabook-connection.yaml diff --git a/api/notifications.go b/api/notifications.go index 28d607bdb..91355733d 100644 --- a/api/notifications.go +++ b/api/notifications.go @@ -4,7 +4,6 @@ import ( gocontext "context" "database/sql/driver" - "github.com/flanksource/duty/context" "github.com/flanksource/duty/types" "gorm.io/gorm" "gorm.io/gorm/clause" @@ -42,16 +41,3 @@ func (t NotificationConfig) GormDBDataType(db *gorm.DB, field *schema.Field) str func (t NotificationConfig) GormValue(ctx gocontext.Context, db *gorm.DB) clause.Expr { return types.GormValue(t) } - -func (t *NotificationConfig) HydrateConnection(ctx context.Context) error { - connection, err := ctx.HydrateConnectionByURL(t.Connection) - if err != nil { - return err - } else if connection == nil { - return nil - } - - t.URL = connection.URL - - return nil -} diff --git a/api/v1/permission_types.go b/api/v1/permission_types.go index 6e0a4886f..63af1b91b 100644 --- a/api/v1/permission_types.go +++ b/api/v1/permission_types.go @@ -78,9 +78,20 @@ func (t PermissionSubjectSelector) Find(ctx context.Context, table string) (stri Where("name = ?", name). Find(&id).Error return id, models.PermissionSubjectTypeNotification, err - } - return "", "", nil + case "playbooks": + splits := strings.Split(string(t), "/") + namespace, name := splits[0], splits[1] + var id string + err := ctx.DB().Select("id").Table(table). + Where("namespace = ?", namespace). + Where("name = ?", name). + Find(&id).Error + return id, models.PermissionSubjectTypePlaybook, err + + default: + return "", "", fmt.Errorf("unknown table: %v", table) + } } type PermissionSubject struct { @@ -103,8 +114,8 @@ type PermissionSubject struct { } func (t *PermissionSubject) Validate() error { - if t.Person == "" && t.Team == "" && t.Notification == "" && t.Group == "" { - return errors.New("subject is empty: one of person, team, notification or a group is required") + if t.Person == "" && t.Team == "" && t.Notification == "" && t.Group == "" && t.Playbook == "" { + return errors.New("subject is empty: one of person, team, playbook, notification or a group is required") } return nil @@ -127,6 +138,9 @@ func (t *PermissionSubject) Populate(ctx context.Context) (string, models.Permis if t.Group != "" { return string(t.Group), models.PermissionSubjectTypeGroup, nil } + if t.Playbook != "" { + return t.Playbook.Find(ctx, "playbooks") + } return "", "", errors.New("subject not found") } diff --git a/api/v1/playbook_actions.go b/api/v1/playbook_actions.go index 4ece8f15b..c6e8a4f13 100644 --- a/api/v1/playbook_actions.go +++ b/api/v1/playbook_actions.go @@ -1,7 +1,6 @@ package v1 import ( - gocontext "context" "encoding/json" "fmt" "time" @@ -266,7 +265,7 @@ type AIActionClient struct { func (t *AIActionClient) Populate(ctx context.Context) error { if t.Connection != nil { - conn, err := ctx.HydrateConnectionByURL(*t.Connection) + conn, err := connection.Get(ctx, *t.Connection) if err != nil { return err } else if conn == nil { @@ -396,12 +395,6 @@ func (e *ExecAction) ToShellExec() shell.Exec { } } -type connectionContext interface { - gocontext.Context - HydrateConnectionByURL(connectionName string) (*models.Connection, error) - GetEnvValueFromCache(env types.EnvVar, namespace string) (string, error) -} - type GCPConnection struct { // ConnectionName of the connection. It'll be used to populate the endpoint and credentials. ConnectionName string `yaml:"connection,omitempty" json:"connection,omitempty"` @@ -411,8 +404,8 @@ type GCPConnection struct { // HydrateConnection attempts to find the connection by name // and populate the endpoint and credentials. -func (g *GCPConnection) HydrateConnection(ctx connectionContext) error { - connection, err := ctx.HydrateConnectionByURL(g.ConnectionName) +func (g *GCPConnection) HydrateConnection(ctx context.Context) error { + connection, err := connection.Get(ctx, g.ConnectionName) if err != nil { return err } @@ -434,8 +427,8 @@ type AzureConnection struct { // HydrateConnection attempts to find the connection by name // and populate the endpoint and credentials. -func (g *AzureConnection) HydrateConnection(ctx connectionContext) error { - connection, err := ctx.HydrateConnectionByURL(g.ConnectionName) +func (g *AzureConnection) HydrateConnection(ctx context.Context) error { + connection, err := connection.Get(ctx, g.ConnectionName) if err != nil { return err } @@ -467,9 +460,9 @@ type AWSConnection struct { // Populate populates an AWSConnection with credentials and other information. // If a connection name is specified, it'll be used to populate the endpoint, accessKey and secretKey. -func (t *AWSConnection) Populate(ctx connectionContext, k8s kubernetes.Interface, namespace string) error { +func (t *AWSConnection) Populate(ctx context.Context, k8s kubernetes.Interface, namespace string) error { if t.ConnectionName != "" { - connection, err := ctx.HydrateConnectionByURL(t.ConnectionName) + connection, err := connection.Get(ctx, t.ConnectionName) if err != nil { return fmt.Errorf("could not parse EC2 access key: %v", err) } diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 4031c5dbf..c70f014aa 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1874,6 +1874,13 @@ func (in *PermissionObject) DeepCopyInto(out *PermissionObject) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Connections != nil { + in, out := &in.Connections, &out.Connections + *out = make([]types.ResourceSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.Configs != nil { in, out := &in.Configs, &out.Configs *out = make([]types.ResourceSelector, len(*in)) diff --git a/artifacts/artifacts.go b/artifacts/artifacts.go index ab8833327..09949c691 100644 --- a/artifacts/artifacts.go +++ b/artifacts/artifacts.go @@ -7,17 +7,19 @@ import ( "github.com/flanksource/artifacts" dutyAPI "github.com/flanksource/duty/api" + pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/duty/context" "github.com/flanksource/duty/models" - "github.com/flanksource/incident-commander/api" "github.com/google/uuid" "gorm.io/gorm" + + "github.com/flanksource/incident-commander/api" ) // UploadArtifact Uploads the given artifact data to the default artifact store func UploadArtifact(ctx context.Context, artifactID string, reader io.ReadCloser) error { if _, err := uuid.Parse(artifactID); err != nil { - return dutyAPI.Errorf(dutyAPI.EINVALID, fmt.Sprintf("(%s) is not a valid uuid", artifactID)) + return dutyAPI.Errorf(dutyAPI.EINVALID, "(%s) is not a valid uuid", artifactID) } var artifact models.Artifact @@ -29,7 +31,7 @@ func UploadArtifact(ctx context.Context, artifactID string, reader io.ReadCloser return fmt.Errorf("failed to get artifact: %w", err) } - conn, err := ctx.HydrateConnectionByURL(api.DefaultArtifactConnection) + conn, err := pkgConnection.Get(ctx, api.DefaultArtifactConnection) if err != nil { return fmt.Errorf("failed to get connection: %w", err) } else if conn == nil { diff --git a/artifacts/controllers.go b/artifacts/controllers.go index 241b480b3..bf29057b5 100644 --- a/artifacts/controllers.go +++ b/artifacts/controllers.go @@ -9,6 +9,7 @@ import ( "github.com/flanksource/artifacts" "github.com/flanksource/commons/logger" "github.com/flanksource/duty/api" + pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/duty/context" "github.com/flanksource/duty/models" "github.com/flanksource/duty/query" @@ -82,7 +83,7 @@ func DownloadArtifact(c echo.Context) error { return api.WriteError(c, api.Errorf(api.ENOTFOUND, "artifact(%s) was not found", artifactID)) } - conn, err := ctx.HydrateConnectionByURL(artifact.ConnectionID.String()) + conn, err := pkgConnection.Get(ctx, artifact.ConnectionID.String()) if err != nil { return api.WriteError(c, err) } else if conn == nil { diff --git a/artifacts/jobs.go b/artifacts/jobs.go index 0a5b43083..e696506dd 100644 --- a/artifacts/jobs.go +++ b/artifacts/jobs.go @@ -5,11 +5,13 @@ import ( "github.com/flanksource/artifacts" "github.com/flanksource/artifacts/fs" + pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/duty/context" "github.com/flanksource/duty/models" "github.com/flanksource/duty/upstream" - "github.com/flanksource/incident-commander/api" "gorm.io/gorm/clause" + + "github.com/flanksource/incident-commander/api" ) // agentArtifactConnection is the cached agent artifact store connection @@ -17,7 +19,7 @@ var agentArtifactConnection *models.Connection func getArtifactStore(ctx context.Context) (fs.FilesystemRW, error) { if agentArtifactConnection == nil { - artifactConnection, err := ctx.HydrateConnectionByURL(api.DefaultArtifactConnection) + artifactConnection, err := pkgConnection.Get(ctx, api.DefaultArtifactConnection) if err != nil { return nil, err } else if artifactConnection == nil { diff --git a/config/crds/mission-control.flanksource.com_permissions.yaml b/config/crds/mission-control.flanksource.com_permissions.yaml index b694ecb32..44093ff10 100644 --- a/config/crds/mission-control.flanksource.com_permissions.yaml +++ b/config/crds/mission-control.flanksource.com_permissions.yaml @@ -185,6 +185,66 @@ spec: type: array type: object type: array + connections: + items: + properties: + agent: + description: |- + Agent can be the agent id or the name of the agent. + Additionally, the special "self" value can be used to select resources without an agent. + type: string + cache: + description: |- + Cache directives + 'no-cache' (should not fetch from cache but can be cached) + 'no-store' (should not cache) + 'max-age=X' (cache for X duration) + type: string + fieldSelector: + type: string + health: + description: |- + Health filters resources by the health. + Multiple healths can be provided separated by comma. + type: string + id: + type: string + includeDeleted: + type: boolean + labelSelector: + type: string + limit: + type: integer + name: + type: string + namespace: + type: string + scope: + description: |- + Scope is the reference for parent of the resource to select. + For config items, the scope is the scraper id + For checks, it's canaries and + For components, it's topology. + It can either be a uuid or namespace/name + type: string + search: + description: Search query that applies to the resource name, + tag & labels. + type: string + statuses: + description: Statuses filter resources by the status + items: + type: string + type: array + tagSelector: + type: string + types: + description: Types filter resources by the type + items: + type: string + type: array + type: object + type: array playbooks: items: properties: @@ -250,8 +310,19 @@ spec: description: Subject defines the entity (e.g., user, group) to which the permission applies. properties: +<<<<<<< HEAD group: description: Group is the group name +||||||| parent of d278685 (feat: replace hydrateConnection with connection.Get) +======= + canary: + description: |- + Subject of the permission. + Can be + - a permission group name + - id of a resource + - / of a resource +>>>>>>> d278685 (feat: replace hydrateConnection with connection.Get) type: string notification: description: Notification / selector @@ -259,9 +330,33 @@ spec: person: description: ID or email of the person type: string + playbook: + description: |- + Subject of the permission. + Can be + - a permission group name + - id of a resource + - / of a resource + type: string + scraper: + description: |- + Subject of the permission. + Can be + - a permission group name + - id of a resource + - / of a resource + type: string team: description: Team is the team name type: string + topology: + description: |- + Subject of the permission. + Can be + - a permission group name + - id of a resource + - / of a resource + type: string type: object tags: additionalProperties: diff --git a/config/schemas/permission.schema.json b/config/schemas/permission.schema.json index 15564c22f..4e776476b 100644 --- a/config/schemas/permission.schema.json +++ b/config/schemas/permission.schema.json @@ -166,6 +166,12 @@ }, "type": "array" }, + "connections": { + "items": { + "$ref": "#/$defs/ResourceSelector" + }, + "type": "array" + }, "configs": { "items": { "$ref": "#/$defs/ResourceSelector" @@ -239,7 +245,21 @@ "notification": { "type": "string" }, +<<<<<<< HEAD "group": { +||||||| parent of d278685 (feat: replace hydrateConnection with connection.Get) +======= + "playbook": { + "type": "string" + }, + "canary": { + "type": "string" + }, + "scraper": { + "type": "string" + }, + "topology": { +>>>>>>> d278685 (feat: replace hydrateConnection with connection.Get) "type": "string" } }, diff --git a/connection/controllers.go b/connection/controllers.go index 8de4da6ee..eb52c0946 100644 --- a/connection/controllers.go +++ b/connection/controllers.go @@ -20,6 +20,7 @@ import ( func init() { echoSrv.RegisterRoutes(RegisterRoutes) } + func RegisterRoutes(e *echo.Echo) { logger.Infof("Registering /connection routes") diff --git a/fixtures/permissions/plyabook-connection.yaml b/fixtures/permissions/plyabook-connection.yaml new file mode 100644 index 000000000..f15b3bde7 --- /dev/null +++ b/fixtures/permissions/plyabook-connection.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: mission-control.flanksource.com/v1 +kind: Permission +metadata: + name: playbook-read-connection + namespace: mc +spec: + description: Grant John read permissions to catalogs + subject: + playbook: default/cause-error + actions: + - read + object: + connections: + - name: "*" diff --git a/go.mod b/go.mod index 5d6391998..09920b8b6 100644 --- a/go.mod +++ b/go.mod @@ -367,7 +367,7 @@ require ( sigs.k8s.io/yaml v1.4.0 ) -replace github.com/flanksource/duty => ../duty +// replace github.com/flanksource/duty => ../duty // replace github.com/flanksource/gomplate/v3 => ../gomplat3 diff --git a/go.sum b/go.sum index 902ccab5b..1a442c5df 100644 --- a/go.sum +++ b/go.sum @@ -287,6 +287,8 @@ github.com/flanksource/artifacts v1.0.14 h1:Vv70bccsae0MwGaf/uSPp34J5V1/PyKfct9z github.com/flanksource/artifacts v1.0.14/go.mod h1:qHVCnQu5k50aWNJ5UhpcAKEl7pAzqUrFFKGSm147G70= github.com/flanksource/commons v1.36.1 h1:SDppXOYO6vk06d12SPOYVZJX+8gV72FmK1l9ar5fkjc= github.com/flanksource/commons v1.36.1/go.mod h1:nsYCn6JOhENXNLR5pz4zNco70DQV+bGObQ8NbOrUeuQ= +github.com/flanksource/duty v1.0.853 h1:0lvwYXeRk2fJGuF/1BvvYR629LYmEtwJgS6SFvh+VKg= +github.com/flanksource/duty v1.0.853/go.mod h1:hoCee0pTczWCMqgUsjhecE6+rkR+yhia7JzD4gqCeaE= github.com/flanksource/gomplate/v3 v3.24.55 h1:BW+KeMcggCkNawb4VTbY+Zn3s9eYIhwqb5/myiyJRb8= github.com/flanksource/gomplate/v3 v3.24.55/go.mod h1:hGEObNtnOQs8rNUX8sM8aJTAhnt4ehjyOw1MvDhl6AU= github.com/flanksource/is-healthy v1.0.61 h1:a+3KgNblosFXat7rht1RLTqRvF3pppd3yxCqi+LWWaU= diff --git a/notification/send.go b/notification/send.go index d07e3d2aa..1c14d2bf0 100644 --- a/notification/send.go +++ b/notification/send.go @@ -10,6 +10,7 @@ import ( "github.com/flanksource/commons/collections" "github.com/flanksource/commons/utils" + pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/duty/context" "github.com/flanksource/duty/models" "github.com/flanksource/duty/types" @@ -18,7 +19,6 @@ import ( "github.com/samber/lo" "go.opentelemetry.io/otel/trace" - pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/incident-commander/api" "github.com/flanksource/incident-commander/db" "github.com/flanksource/incident-commander/logs" @@ -193,7 +193,7 @@ func SendNotification(ctx *Context, connectionName, shoutrrrURL string, celEnv m var connection *models.Connection var err error if connectionName != "" { - connection, err = pkgConnection.GetC(ctx.Context, connectionName) + connection, err = pkgConnection.Get(ctx.Context, connectionName) if err != nil { return "", err } diff --git a/playbook/actions/gitops.go b/playbook/actions/gitops.go index a11549e30..32168f524 100644 --- a/playbook/actions/gitops.go +++ b/playbook/actions/gitops.go @@ -10,15 +10,17 @@ import ( "github.com/flanksource/commons/files" "github.com/flanksource/commons/logger" + pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/duty/context" "github.com/flanksource/duty/models" "github.com/flanksource/duty/shell" - v1 "github.com/flanksource/incident-commander/api/v1" - "github.com/flanksource/incident-commander/pkg/clients/git" - "github.com/flanksource/incident-commander/pkg/clients/git/connectors" gitv5 "github.com/go-git/go-git/v5" "github.com/samber/lo" "github.com/samber/oops" + + v1 "github.com/flanksource/incident-commander/api/v1" + "github.com/flanksource/incident-commander/pkg/clients/git" + "github.com/flanksource/incident-commander/pkg/clients/git/connectors" ) type GitOps struct { @@ -158,7 +160,7 @@ func (t *GitOps) generateSpec(ctx context.Context, action v1.GitOpsAction) error } if action.Repo.Connection != "" { - conn, err := ctx.HydrateConnectionByURL(action.Repo.Connection) + conn, err := pkgConnection.Get(ctx, action.Repo.Connection) if err != nil { return ctx.Oops().Wrap(err) } else if conn == nil { diff --git a/playbook/actions/http.go b/playbook/actions/http.go index 9d72120d0..12eb8503e 100644 --- a/playbook/actions/http.go +++ b/playbook/actions/http.go @@ -6,6 +6,7 @@ import ( "net/url" "github.com/flanksource/commons/http" + pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/duty/context" "github.com/flanksource/duty/models" v1 "github.com/flanksource/incident-commander/api/v1" @@ -21,7 +22,7 @@ type HTTP struct { } func (c *HTTP) Run(ctx context.Context, action v1.HTTPAction) (*HTTPResult, error) { - connection, err := ctx.HydrateConnectionByURL(action.HTTPConnection.Connection) + connection, err := pkgConnection.Get(ctx, action.HTTPConnection.Connection) if err != nil { return nil, fmt.Errorf("failed to hydrate connection: %w", err) } else if connection != nil { diff --git a/playbook/actions/sql.go b/playbook/actions/sql.go index f674885ae..7f48cb358 100644 --- a/playbook/actions/sql.go +++ b/playbook/actions/sql.go @@ -4,6 +4,7 @@ import ( "database/sql" "fmt" + pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/duty/context" v1 "github.com/flanksource/incident-commander/api/v1" ) @@ -19,7 +20,7 @@ type SQL struct{} // Returns check result and metrics func (c *SQL) Run(ctx context.Context, action v1.SQLAction) (*SQLResult, error) { if action.Connection != "" { - connection, err := ctx.HydrateConnectionByURL(action.Connection) + connection, err := pkgConnection.Get(ctx, action.Connection) if err != nil { return nil, fmt.Errorf("error getting connection: %w", err) } else if connection == nil { diff --git a/playbook/runner/artifacts.go b/playbook/runner/artifacts.go index d88f5e780..996310b9a 100644 --- a/playbook/runner/artifacts.go +++ b/playbook/runner/artifacts.go @@ -7,6 +7,7 @@ import ( "github.com/flanksource/artifacts" "github.com/flanksource/commons/logger" "github.com/flanksource/commons/utils" + pkgConnection "github.com/flanksource/duty/connection" "github.com/flanksource/duty/context" "github.com/flanksource/duty/models" "github.com/google/uuid" @@ -24,7 +25,7 @@ func saveArtifacts(ctx context.Context, playbookActionID uuid.UUID, generatedArt return nil } - connection, err := ctx.HydrateConnectionByURL(api.DefaultArtifactConnection) + connection, err := pkgConnection.Get(ctx, api.DefaultArtifactConnection) if err != nil { return fmt.Errorf("error getting connection(%s): %w", api.DefaultArtifactConnection, err) } else if connection == nil { From 6c24489ebd2a95c228a0776e9c086a828b9eaa0c Mon Sep 17 00:00:00 2001 From: Aditya Thebe Date: Wed, 19 Feb 2025 14:20:32 +0545 Subject: [PATCH 3/3] chore: make generate --- api/v1/permission_types.go | 6 +- ...n-control.flanksource.com_permissions.yaml | 33 +- ...ion-control.flanksource.com_playbooks.yaml | 305 ++++++++++++++++++ config/schemas/permission.schema.json | 6 +- config/schemas/playbook-spec.schema.json | 97 ++++++ config/schemas/playbook.schema.json | 97 ++++++ 6 files changed, 521 insertions(+), 23 deletions(-) diff --git a/api/v1/permission_types.go b/api/v1/permission_types.go index 63af1b91b..c8564d270 100644 --- a/api/v1/permission_types.go +++ b/api/v1/permission_types.go @@ -68,7 +68,7 @@ func (t PermissionSubjectSelector) Find(ctx context.Context, table string) (stri splits := strings.Split(string(t), "/") if len(splits) != 2 { - return "", "", fmt.Errorf("%s is not a valid notification subject. must be /", t) + return "", "", fmt.Errorf("%s is not a valid notification subject. Must be /", t) } namespace, name := splits[0], splits[1] @@ -81,6 +81,10 @@ func (t PermissionSubjectSelector) Find(ctx context.Context, table string) (stri case "playbooks": splits := strings.Split(string(t), "/") + if len(splits) != 2 { + return "", "", fmt.Errorf("%s is not a valid playbooks subject. Must be /", t) + } + namespace, name := splits[0], splits[1] var id string err := ctx.DB().Select("id").Table(table). diff --git a/config/crds/mission-control.flanksource.com_permissions.yaml b/config/crds/mission-control.flanksource.com_permissions.yaml index 44093ff10..9e91aa984 100644 --- a/config/crds/mission-control.flanksource.com_permissions.yaml +++ b/config/crds/mission-control.flanksource.com_permissions.yaml @@ -310,19 +310,16 @@ spec: description: Subject defines the entity (e.g., user, group) to which the permission applies. properties: -<<<<<<< HEAD - group: - description: Group is the group name -||||||| parent of d278685 (feat: replace hydrateConnection with connection.Get) -======= canary: description: |- Subject of the permission. - Can be - - a permission group name + Can be in various formats depending on the table - id of a resource - - / of a resource ->>>>>>> d278685 (feat: replace hydrateConnection with connection.Get) + - name or email for person + - / of a notification + type: string + group: + description: Group is the group name type: string notification: description: Notification / selector @@ -333,18 +330,18 @@ spec: playbook: description: |- Subject of the permission. - Can be - - a permission group name + Can be in various formats depending on the table - id of a resource - - / of a resource + - name or email for person + - / of a notification type: string scraper: description: |- Subject of the permission. - Can be - - a permission group name + Can be in various formats depending on the table - id of a resource - - / of a resource + - name or email for person + - / of a notification type: string team: description: Team is the team name @@ -352,10 +349,10 @@ spec: topology: description: |- Subject of the permission. - Can be - - a permission group name + Can be in various formats depending on the table - id of a resource - - / of a resource + - name or email for person + - / of a notification type: string type: object tags: diff --git a/config/crds/mission-control.flanksource.com_playbooks.yaml b/config/crds/mission-control.flanksource.com_playbooks.yaml index 8c1b28eb2..73e8759c3 100644 --- a/config/crds/mission-control.flanksource.com_playbooks.yaml +++ b/config/crds/mission-control.flanksource.com_playbooks.yaml @@ -817,8 +817,313 @@ spec: type: object kubernetes: properties: + cnrm: + properties: + clusterResource: + type: string + clusterResourceNamespace: + type: string + gke: + properties: + cluster: + type: string + connection: + description: ConnectionName of the connection. + It'll be used to populate the endpoint + and credentials. + type: string + credentials: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + helmRef: + properties: + key: + description: Key is a JSONPath + expression used to fetch the + key from the merged JSON. + type: string + name: + type: string + required: + - key + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + serviceAccount: + description: ServiceAccount specifies + the service account whose token + should be fetched + type: string + type: object + type: object + endpoint: + type: string + projectID: + type: string + skipTLSVerify: + description: Skip TLS verify + type: boolean + zone: + type: string + required: + - cluster + - projectID + - zone + type: object + required: + - clusterResource + - clusterResourceNamespace + - gke + type: object connection: + description: Connection name to populate kubeconfig type: string + eks: + properties: + accessKey: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + helmRef: + properties: + key: + description: Key is a JSONPath expression + used to fetch the key from the + merged JSON. + type: string + name: + type: string + required: + - key + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + serviceAccount: + description: ServiceAccount specifies + the service account whose token should + be fetched + type: string + type: object + type: object + assumeRole: + type: string + cluster: + type: string + connection: + description: ConnectionName of the connection. + It'll be used to populate the endpoint, accessKey + and secretKey. + type: string + endpoint: + type: string + region: + type: string + secretKey: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + helmRef: + properties: + key: + description: Key is a JSONPath expression + used to fetch the key from the + merged JSON. + type: string + name: + type: string + required: + - key + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + serviceAccount: + description: ServiceAccount specifies + the service account whose token should + be fetched + type: string + type: object + type: object + sessionToken: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + helmRef: + properties: + key: + description: Key is a JSONPath expression + used to fetch the key from the + merged JSON. + type: string + name: + type: string + required: + - key + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + serviceAccount: + description: ServiceAccount specifies + the service account whose token should + be fetched + type: string + type: object + type: object + skipTLSVerify: + description: Skip TLS verify when connecting + to aws + type: boolean + required: + - cluster + type: object + gke: + properties: + cluster: + type: string + connection: + description: ConnectionName of the connection. + It'll be used to populate the endpoint and + credentials. + type: string + credentials: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + helmRef: + properties: + key: + description: Key is a JSONPath expression + used to fetch the key from the + merged JSON. + type: string + name: + type: string + required: + - key + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + required: + - key + type: object + serviceAccount: + description: ServiceAccount specifies + the service account whose token should + be fetched + type: string + type: object + type: object + endpoint: + type: string + projectID: + type: string + skipTLSVerify: + description: Skip TLS verify + type: boolean + zone: + type: string + required: + - cluster + - projectID + - zone + type: object kubeconfig: properties: name: diff --git a/config/schemas/permission.schema.json b/config/schemas/permission.schema.json index 4e776476b..96e4f3b32 100644 --- a/config/schemas/permission.schema.json +++ b/config/schemas/permission.schema.json @@ -245,10 +245,9 @@ "notification": { "type": "string" }, -<<<<<<< HEAD "group": { -||||||| parent of d278685 (feat: replace hydrateConnection with connection.Get) -======= + "type": "string" + }, "playbook": { "type": "string" }, @@ -259,7 +258,6 @@ "type": "string" }, "topology": { ->>>>>>> d278685 (feat: replace hydrateConnection with connection.Get) "type": "string" } }, diff --git a/config/schemas/playbook-spec.schema.json b/config/schemas/playbook-spec.schema.json index e4222f656..9412ee21a 100644 --- a/config/schemas/playbook-spec.schema.json +++ b/config/schemas/playbook-spec.schema.json @@ -199,6 +199,26 @@ "additionalProperties": false, "type": "object" }, + "CNRMConnection": { + "properties": { + "gke": { + "$ref": "#/$defs/GKEConnection" + }, + "clusterResource": { + "type": "string" + }, + "clusterResourceNamespace": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "gke", + "clusterResource", + "clusterResourceNamespace" + ] + }, "ConfigMapKeySelector": { "properties": { "name": { @@ -214,6 +234,42 @@ "key" ] }, + "EKSConnection": { + "properties": { + "connection": { + "type": "string" + }, + "accessKey": { + "$ref": "#/$defs/EnvVar" + }, + "secretKey": { + "$ref": "#/$defs/EnvVar" + }, + "sessionToken": { + "$ref": "#/$defs/EnvVar" + }, + "assumeRole": { + "type": "string" + }, + "region": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "skipTLSVerify": { + "type": "boolean" + }, + "cluster": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "cluster" + ] + }, "EnvVar": { "properties": { "name": { @@ -322,6 +378,38 @@ "additionalProperties": false, "type": "object" }, + "GKEConnection": { + "properties": { + "connection": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "credentials": { + "$ref": "#/$defs/EnvVar" + }, + "skipTLSVerify": { + "type": "boolean" + }, + "projectID": { + "type": "string" + }, + "zone": { + "type": "string" + }, + "cluster": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "projectID", + "zone", + "cluster" + ] + }, "GitConnection": { "properties": { "url": { @@ -602,6 +690,15 @@ }, "kubeconfig": { "$ref": "#/$defs/EnvVar" + }, + "eks": { + "$ref": "#/$defs/EKSConnection" + }, + "gke": { + "$ref": "#/$defs/GKEConnection" + }, + "cnrm": { + "$ref": "#/$defs/CNRMConnection" } }, "additionalProperties": false, diff --git a/config/schemas/playbook.schema.json b/config/schemas/playbook.schema.json index edcdb1b3b..dd452f8eb 100644 --- a/config/schemas/playbook.schema.json +++ b/config/schemas/playbook.schema.json @@ -199,6 +199,26 @@ "additionalProperties": false, "type": "object" }, + "CNRMConnection": { + "properties": { + "gke": { + "$ref": "#/$defs/GKEConnection" + }, + "clusterResource": { + "type": "string" + }, + "clusterResourceNamespace": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "gke", + "clusterResource", + "clusterResourceNamespace" + ] + }, "ConfigMapKeySelector": { "properties": { "name": { @@ -214,6 +234,42 @@ "key" ] }, + "EKSConnection": { + "properties": { + "connection": { + "type": "string" + }, + "accessKey": { + "$ref": "#/$defs/EnvVar" + }, + "secretKey": { + "$ref": "#/$defs/EnvVar" + }, + "sessionToken": { + "$ref": "#/$defs/EnvVar" + }, + "assumeRole": { + "type": "string" + }, + "region": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "skipTLSVerify": { + "type": "boolean" + }, + "cluster": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "cluster" + ] + }, "EnvVar": { "properties": { "name": { @@ -327,6 +383,38 @@ "additionalProperties": false, "type": "object" }, + "GKEConnection": { + "properties": { + "connection": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "credentials": { + "$ref": "#/$defs/EnvVar" + }, + "skipTLSVerify": { + "type": "boolean" + }, + "projectID": { + "type": "string" + }, + "zone": { + "type": "string" + }, + "cluster": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "projectID", + "zone", + "cluster" + ] + }, "GitConnection": { "properties": { "url": { @@ -607,6 +695,15 @@ }, "kubeconfig": { "$ref": "#/$defs/EnvVar" + }, + "eks": { + "$ref": "#/$defs/EKSConnection" + }, + "gke": { + "$ref": "#/$defs/GKEConnection" + }, + "cnrm": { + "$ref": "#/$defs/CNRMConnection" } }, "additionalProperties": false,