Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added tailscale and fly integrations #2455

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package configs

type IntegrationCredentials struct {
Token string `json:"token"`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package configs

const (
DescriberDeploymentName = "og-describer-fly"
DescriberRunCommand = "/og-describer-fly"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package configs

import "github.com/opengovern/og-util/pkg/integration"

const (
IntegrationTypeFlyAccount = integration.Type("fly_account") // example: AWS_ACCOUNT, AZURE_SUBSCRIPTION
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package configs

const (
StreamName = "og_describer_fly"
JobQueueTopic = "og_describer_fly_job_queue"
ConsumerGroup = "describer-fly"
JobQueueTopicManuals = "og_describer_fly_manuals_job_queue"
ConsumerGroupManuals = "describer-fly-manuals"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package configs

var TablesToResourceTypes = map[string]string{
"fly_app": "Fly/App",
"fly_machine": "Fly/Machine",
"fly_volume": "Fly/Volume",
"fly_secret": "Fly/Secret",
}

var ResourceTypesList = []string{
"Fly/App",
"Fly/Machine",
"Fly/Volume",
"Fly/Secret",
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package discovery

import (
"encoding/json"
"errors"
"fmt"
"net/http"
)

// Config represents the JSON input configuration
type Config struct {
Token string `json:"token"`
}

type App struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
}

type Response struct {
Apps []App `json:"apps"`
}

// Discover retrieves fly user info
func Discover(token string) ([]App, error) {
var response Response

url := "https://api.machines.dev/v1/apps?org_slug=personal"

client := http.DefaultClient

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))

resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request execution failed: %w", err)
}
defer resp.Body.Close()

if err = json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}

return response.Apps, nil
}

func FlyIntegrationDiscovery(cfg Config) ([]App, error) {
// Check for the token
if cfg.Token == "" {
return nil, errors.New("token must be configured")
}

return Discover(cfg.Token)
}
104 changes: 104 additions & 0 deletions services/integration/integration-type/fly-account/fly_account.go
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

package name is wrong

Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package doppler_account

import (
"encoding/json"
"github.com/jackc/pgtype"
flyDescriberLocal "github.com/opengovern/opencomply/services/integration/integration-type/fly-account/configs"
"github.com/opengovern/opencomply/services/integration/integration-type/fly-account/discovery"
"github.com/opengovern/opencomply/services/integration/integration-type/fly-account/healthcheck"
"github.com/opengovern/opencomply/services/integration/integration-type/interfaces"
"github.com/opengovern/opencomply/services/integration/models"
)

type FlyAccountIntegration struct{}

func (i *FlyAccountIntegration) GetConfiguration() interfaces.IntegrationConfiguration {
return interfaces.IntegrationConfiguration{
NatsScheduledJobsTopic: flyDescriberLocal.JobQueueTopic,
NatsManualJobsTopic: flyDescriberLocal.JobQueueTopicManuals,
NatsStreamName: flyDescriberLocal.StreamName,
NatsConsumerGroup: flyDescriberLocal.ConsumerGroup,
NatsConsumerGroupManuals: flyDescriberLocal.ConsumerGroupManuals,

SteampipePluginName: "fly",

UISpecFileName: "fly-account.json",

DescriberDeploymentName: flyDescriberLocal.DescriberDeploymentName,
DescriberRunCommand: flyDescriberLocal.DescriberRunCommand,
}
}

func (i *FlyAccountIntegration) HealthCheck(jsonData []byte, providerId string, labels map[string]string, annotations map[string]string) (bool, error) {
var credentials flyDescriberLocal.IntegrationCredentials
err := json.Unmarshal(jsonData, &credentials)
if err != nil {
return false, err
}

var appName string
if v, ok := labels["AppName"]; ok {
appName = v
}
isHealthy, err := healthcheck.FlyIntegrationHealthcheck(healthcheck.Config{
Token: credentials.Token,
AppName: appName,
})
return isHealthy, err
}

func (i *FlyAccountIntegration) DiscoverIntegrations(jsonData []byte) ([]models.Integration, error) {
var credentials flyDescriberLocal.IntegrationCredentials
err := json.Unmarshal(jsonData, &credentials)
if err != nil {
return nil, err
}
var integrations []models.Integration
apps, err := discovery.FlyIntegrationDiscovery(discovery.Config{
Token: credentials.Token,
})
for _, app := range apps {
labels := map[string]string{
"AppName": app.Name,
"Status": app.Status,
}
labelsJsonData, err := json.Marshal(labels)
if err != nil {
return nil, err
}
integrationLabelsJsonb := pgtype.JSONB{}
err = integrationLabelsJsonb.Set(labelsJsonData)
if err != nil {
return nil, err
}
integrations = append(integrations, models.Integration{
ProviderID: app.ID,
Name: app.Name,
Labels: integrationLabelsJsonb,
})
}
return integrations, nil
}

func (i *FlyAccountIntegration) GetResourceTypesByLabels(labels map[string]string) (map[string]*interfaces.ResourceTypeConfiguration, error) {
resourceTypesMap := make(map[string]*interfaces.ResourceTypeConfiguration)
for _, resourceType := range flyDescriberLocal.ResourceTypesList {
resourceTypesMap[resourceType] = nil
}
return resourceTypesMap, nil
}

func (i *FlyAccountIntegration) GetResourceTypeFromTableName(tableName string) string {
if v, ok := flyDescriberLocal.TablesToResourceTypes[tableName]; ok {
return v
}
return ""
}

func (i *FlyAccountIntegration) GetTablesByLabels(map[string]string) ([]string, error) {
var tables []string
for t, _ := range flyDescriberLocal.TablesToResourceTypes {
tables = append(tables, t)
}
return tables, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package healthcheck

import (
"encoding/json"
"errors"
"fmt"
"net/http"
)

// Config represents the JSON input configuration
type Config struct {
Token string `json:"token"`
AppName string `json:"app_name"`
}

type App struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
}

// IsHealthy checks if the JWT has read access to all required resources
func IsHealthy(token, appName string) error {
var app App

url := fmt.Sprintf("https://api.machines.dev/v1/apps/%s", appName)

client := http.DefaultClient

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))

resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("request execution failed: %w", err)
}
defer resp.Body.Close()

if err = json.NewDecoder(resp.Body).Decode(&app); err != nil {
return fmt.Errorf("failed to decode response: %w", err)
}

return nil
}

func FlyIntegrationHealthcheck(cfg Config) (bool, error) {
// Check for the token
if cfg.Token == "" {
return false, errors.New("token must be configured")
}

if cfg.AppName == "" {
return false, errors.New("app name must be configured")
}

err := IsHealthy(cfg.Token, cfg.AppName)
if err != nil {
return false, err
}

return true, nil
}
10 changes: 10 additions & 0 deletions services/integration/integration-type/integrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
dopplerConfigs "github.com/opengovern/opencomply/services/integration/integration-type/doppler-account/configs"
"github.com/opengovern/opencomply/services/integration/integration-type/entra-id-directory"
entraidConfigs "github.com/opengovern/opencomply/services/integration/integration-type/entra-id-directory/configs"
fly "github.com/opengovern/opencomply/services/integration/integration-type/fly-account"
flyConfigs "github.com/opengovern/opencomply/services/integration/integration-type/fly-account/configs"
githubaccount "github.com/opengovern/opencomply/services/integration/integration-type/github-account"
githubConfigs "github.com/opengovern/opencomply/services/integration/integration-type/github-account/configs"
google_workspace_account "github.com/opengovern/opencomply/services/integration/integration-type/google-workspace-account"
Expand All @@ -31,6 +33,8 @@ import (
openaiConfigs "github.com/opengovern/opencomply/services/integration/integration-type/openai-integration/configs"
render "github.com/opengovern/opencomply/services/integration/integration-type/render-account"
renderConfigs "github.com/opengovern/opencomply/services/integration/integration-type/render-account/configs"
tailscale "github.com/opengovern/opencomply/services/integration/integration-type/tailscale-account"
tailscaleConfigs "github.com/opengovern/opencomply/services/integration/integration-type/tailscale-account/configs"
)

const (
Expand All @@ -47,6 +51,8 @@ const (
IntegrationTypeOCIRepository = ociConfigs.IntegrationTypeOciRepository
IntegrationTypeRenderAccount = renderConfigs.IntegrationTypeRenderAccount
IntegrationTypeDopplerAccount = dopplerConfigs.IntegrationTypeDopplerAccount
IntegrationTypeTailScaleAccount = tailscaleConfigs.IntegrationTypeTailScaleAccount
IntegrationTypeFlyAccount = flyConfigs.IntegrationTypeFlyAccount
)

var AllIntegrationTypes = []integration.Type{
Expand All @@ -63,6 +69,8 @@ var AllIntegrationTypes = []integration.Type{
IntegrationTypeOCIRepository,
IntegrationTypeRenderAccount,
IntegrationTypeDopplerAccount,
IntegrationTypeTailScaleAccount,
IntegrationTypeFlyAccount,
}

var IntegrationTypes = map[integration.Type]interfaces.IntegrationType{
Expand All @@ -79,6 +87,8 @@ var IntegrationTypes = map[integration.Type]interfaces.IntegrationType{
IntegrationTypeOCIRepository: &oci.Integration{},
IntegrationTypeRenderAccount: &render.RenderAccountIntegration{},
IntegrationTypeDopplerAccount: &doppler.DopplerAccountIntegration{},
IntegrationTypeTailScaleAccount: &tailscale.TailScaleAccountIntegration{},
IntegrationTypeFlyAccount: &fly.FlyAccountIntegration{},
}

func ParseType(str string) integration.Type {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package configs

type IntegrationCredentials struct {
Token string `json:"token"`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package configs

const (
DescriberDeploymentName = "og-describer-tailscale"
DescriberRunCommand = "/og-describer-tailscale"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package configs

import "github.com/opengovern/og-util/pkg/integration"

const (
IntegrationTypeTailScaleAccount = integration.Type("tailscale_account") // example: AWS_ACCOUNT, AZURE_SUBSCRIPTION
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package configs

const (
StreamName = "og_describer_tailscale"
JobQueueTopic = "og_describer_tailscale_job_queue"
ConsumerGroup = "describer-tailscale"
JobQueueTopicManuals = "og_describer_tailscale_manuals_job_queue"
ConsumerGroupManuals = "describer-tailscale-manuals"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package configs

var TablesToResourceTypes = map[string]string{
"tailscale_device": "TailScale/Device",
"tailscale_user": "TailScale/User",
"tailscale_contact": "TailScale/Contact",
"tailscale_device_invite": "TailScale/Device/Invite",
"tailscale_device_posture": "TailScale/Device/Posture",
"tailscale_user_invite": "TailScale/User/Invite",
"tailscale_key": "TailScale/Key",
"tailscale_policy": "TailScale/Policy",
"tailscale_tailnet_setting": "TailScale/TailnetSetting",
"tailscale_webhook": "TailScale/Webhook",
"tailscale_dns": "TailScale/DNS",
}

var ResourceTypesList = []string{
"TailScale/Device",
"TailScale/User",
"TailScale/Contact",
"TailScale/Device/Invite",
"TailScale/Device/Posture",
"TailScale/User/Invite",
"TailScale/Key",
"TailScale/Policy",
"TailScale/TailnetSetting",
"TailScale/Webhook",
"TailScale/DNS",
}
Loading
Loading