Jelajahi Sumber

created aws infra model

Alexander Belanger 5 tahun lalu
induk
melakukan
cf1e6633c5

+ 64 - 0
internal/models/infra.go

@@ -0,0 +1,64 @@
+package models
+
+import (
+	"fmt"
+
+	"gorm.io/gorm"
+)
+
+// InfraStatus is the status that an infrastructure can take
+type InfraStatus string
+
+// The allowed statuses
+const (
+	StatusCreating InfraStatus = "creating"
+	StatusCreated  InfraStatus = "created"
+	StatusUpdating InfraStatus = "updating"
+)
+
+// AWSInfra represents the metadata for an infrastructure type provisioned on
+// AWS
+type AWSInfra struct {
+	gorm.Model
+
+	// The type of infra that was provisioned
+	Kind string `json:"kind"`
+
+	// The project that this infra belongs to
+	ProjectID uint `json:"project_id"`
+
+	// Status is the status of the infra
+	Status InfraStatus `json:"status"`
+
+	// The AWS integration that was used to create the infra
+	AWSIntegrationID uint
+}
+
+// AWSInfraExternal is an external AWSInfra to be shared over REST
+type AWSInfraExternal struct {
+	ID uint `json:"id"`
+
+	// The project that this integration belongs to
+	ProjectID uint `json:"project_id"`
+
+	// The type of infra that was provisioned
+	Kind string `json:"kind"`
+
+	// Status is the status of the infra
+	Status InfraStatus `json:"status"`
+}
+
+// Externalize generates an external AWSInfra to be shared over REST
+func (ai *AWSInfra) Externalize() *AWSInfraExternal {
+	return &AWSInfraExternal{
+		ID:        ai.ID,
+		ProjectID: ai.ProjectID,
+		Kind:      ai.Kind,
+		Status:    ai.Status,
+	}
+}
+
+// GetWorkspaceID returns the unique workspace id for this infra
+func (ai *AWSInfra) GetWorkspaceID() string {
+	return fmt.Sprintf("%s-%d-%d", ai.Kind, ai.ProjectID, ai.ID)
+}

+ 3 - 0
internal/models/project.go

@@ -26,6 +26,9 @@ type Project struct {
 	// linked helm repos
 	HelmRepos []HelmRepo `json:"helm_repos"`
 
+	// provisioned aws infra
+	AWSInfras []AWSInfra `json:"aws_infras"`
+
 	// auth mechanisms
 	KubeIntegrations  []ints.KubeIntegration  `json:"kube_integrations"`
 	BasicIntegrations []ints.BasicIntegration `json:"basic_integrations"`

+ 40 - 16
internal/repository/gorm/helpers_test.go

@@ -13,22 +13,23 @@ import (
 )
 
 type tester struct {
-	repo         *repository.Repository
-	key          *[32]byte
-	dbFileName   string
-	initUsers    []*models.User
-	initProjects []*models.Project
-	initGRs      []*models.GitRepo
-	initRegs     []*models.Registry
-	initClusters []*models.Cluster
-	initHRs      []*models.HelmRepo
-	initCCs      []*models.ClusterCandidate
-	initKIs      []*ints.KubeIntegration
-	initBasics   []*ints.BasicIntegration
-	initOIDCs    []*ints.OIDCIntegration
-	initOAuths   []*ints.OAuthIntegration
-	initGCPs     []*ints.GCPIntegration
-	initAWSs     []*ints.AWSIntegration
+	repo          *repository.Repository
+	key           *[32]byte
+	dbFileName    string
+	initUsers     []*models.User
+	initProjects  []*models.Project
+	initGRs       []*models.GitRepo
+	initRegs      []*models.Registry
+	initClusters  []*models.Cluster
+	initHRs       []*models.HelmRepo
+	initAWSInfras []*models.AWSInfra
+	initCCs       []*models.ClusterCandidate
+	initKIs       []*ints.KubeIntegration
+	initBasics    []*ints.BasicIntegration
+	initOIDCs     []*ints.OIDCIntegration
+	initOAuths    []*ints.OAuthIntegration
+	initGCPs      []*ints.GCPIntegration
+	initAWSs      []*ints.AWSIntegration
 }
 
 func setupTestEnv(tester *tester, t *testing.T) {
@@ -56,6 +57,7 @@ func setupTestEnv(tester *tester, t *testing.T) {
 		&models.Cluster{},
 		&models.ClusterCandidate{},
 		&models.ClusterResolver{},
+		&models.AWSInfra{},
 		&ints.KubeIntegration{},
 		&ints.BasicIntegration{},
 		&ints.OIDCIntegration{},
@@ -435,3 +437,25 @@ func initHelmRepo(tester *tester, t *testing.T) {
 
 	tester.initHRs = append(tester.initHRs, hr)
 }
+
+func initAWSInfra(tester *tester, t *testing.T) {
+	t.Helper()
+
+	if len(tester.initProjects) == 0 {
+		initProject(tester, t)
+	}
+
+	infra := &models.AWSInfra{
+		Kind:      "ecr",
+		ProjectID: tester.initProjects[0].Model.ID,
+		Status:    models.StatusCreated,
+	}
+
+	infra, err := tester.repo.AWSInfra.CreateAWSInfra(infra)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initAWSInfras = append(tester.initAWSInfras, infra)
+}

+ 64 - 0
internal/repository/gorm/infra.go

@@ -0,0 +1,64 @@
+package gorm
+
+import (
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
+)
+
+// AWSInfraRepository uses gorm.DB for querying the database
+type AWSInfraRepository struct {
+	db *gorm.DB
+}
+
+// NewAWSInfraRepository returns a AWSInfraRepository which uses
+// gorm.DB for querying the database
+func NewAWSInfraRepository(db *gorm.DB) repository.AWSInfraRepository {
+	return &AWSInfraRepository{db}
+}
+
+// CreateAWSInfra creates a new aws infra
+func (repo *AWSInfraRepository) CreateAWSInfra(infra *models.AWSInfra) (*models.AWSInfra, error) {
+	project := &models.Project{}
+
+	if err := repo.db.Where("id = ?", infra.ProjectID).First(&project).Error; err != nil {
+		return nil, err
+	}
+
+	assoc := repo.db.Model(&project).Association("AWSInfras")
+
+	if assoc.Error != nil {
+		return nil, assoc.Error
+	}
+
+	if err := assoc.Append(infra); err != nil {
+		return nil, err
+	}
+
+	return infra, nil
+}
+
+// ReadAWSInfra gets a aws infra specified by a unique id
+func (repo *AWSInfraRepository) ReadAWSInfra(id uint) (*models.AWSInfra, error) {
+	infra := &models.AWSInfra{}
+
+	if err := repo.db.Where("id = ?", id).First(&infra).Error; err != nil {
+		return nil, err
+	}
+
+	return infra, nil
+}
+
+// ListAWSInfrasByProjectID finds all aws infras
+// for a given project id
+func (repo *AWSInfraRepository) ListAWSInfrasByProjectID(
+	projectID uint,
+) ([]*models.AWSInfra, error) {
+	infras := []*models.AWSInfra{}
+
+	if err := repo.db.Where("project_id = ?", projectID).Find(&infras).Error; err != nil {
+		return nil, err
+	}
+
+	return infras, nil
+}

+ 90 - 0
internal/repository/gorm/infra_test.go

@@ -0,0 +1,90 @@
+package gorm_test
+
+import (
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/porter-dev/porter/internal/models"
+	"gorm.io/gorm"
+)
+
+func TestCreateAWSInfra(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_create_aws_infra.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	defer cleanup(tester, t)
+
+	infra := &models.AWSInfra{
+		Kind:      "ecr",
+		ProjectID: tester.initProjects[0].Model.ID,
+		Status:    models.StatusCreated,
+	}
+
+	infra, err := tester.repo.AWSInfra.CreateAWSInfra(infra)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	infra, err = tester.repo.AWSInfra.ReadAWSInfra(infra.Model.ID)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	// make sure id is 1 and name is "ecr"
+	if infra.Model.ID != 1 {
+		t.Errorf("incorrect registry ID: expected %d, got %d\n", 1, infra.Model.ID)
+	}
+
+	if infra.Kind != "ecr" {
+		t.Errorf("incorrect aws infra kind: expected %s, got %s\n", "ecr", infra.Kind)
+	}
+
+	if infra.Status != models.StatusCreated {
+		t.Errorf("incorrect aws infra status: expected %s, got %s\n", models.StatusCreated, infra.Status)
+	}
+}
+
+func TestListAWSInfrasByProjectID(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_list_aws_infras.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	initAWSInfra(tester, t)
+	defer cleanup(tester, t)
+
+	infras, err := tester.repo.AWSInfra.ListAWSInfrasByProjectID(
+		tester.initProjects[0].Model.ID,
+	)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	if len(infras) != 1 {
+		t.Fatalf("length of aws infras incorrect: expected %d, got %d\n", 1, len(infras))
+	}
+
+	// make sure data is correct
+	expAWSInfra := models.AWSInfra{
+		Kind:      "ecr",
+		ProjectID: tester.initProjects[0].Model.ID,
+		Status:    models.StatusCreated,
+	}
+
+	infra := infras[0]
+
+	// reset fields for reflect.DeepEqual
+	infra.Model = gorm.Model{}
+
+	if diff := deep.Equal(expAWSInfra, *infra); diff != nil {
+		t.Errorf("incorrect aws infra")
+		t.Error(diff)
+	}
+}

+ 1 - 0
internal/repository/gorm/repository.go

@@ -17,6 +17,7 @@ func NewRepository(db *gorm.DB, key *[32]byte) *repository.Repository {
 		Cluster:          NewClusterRepository(db, key),
 		HelmRepo:         NewHelmRepoRepository(db, key),
 		Registry:         NewRegistryRepository(db, key),
+		AWSInfra:         NewAWSInfraRepository(db),
 		KubeIntegration:  NewKubeIntegrationRepository(db, key),
 		BasicIntegration: NewBasicIntegrationRepository(db, key),
 		OIDCIntegration:  NewOIDCIntegrationRepository(db, key),

+ 12 - 0
internal/repository/infra.go

@@ -0,0 +1,12 @@
+package repository
+
+import (
+	"github.com/porter-dev/porter/internal/models"
+)
+
+// AWSInfraRepository represents the set of queries on the AWSInfra model
+type AWSInfraRepository interface {
+	CreateAWSInfra(repo *models.AWSInfra) (*models.AWSInfra, error)
+	ReadAWSInfra(id uint) (*models.AWSInfra, error)
+	ListAWSInfrasByProjectID(projectID uint) ([]*models.AWSInfra, error)
+}

+ 73 - 0
internal/repository/memory/infra.go

@@ -0,0 +1,73 @@
+package test
+
+import (
+	"errors"
+
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
+)
+
+// AWSInfraRepository implements repository.AWSInfraRepository
+type AWSInfraRepository struct {
+	canQuery  bool
+	awsInfras []*models.AWSInfra
+}
+
+// NewAWSInfraRepository will return errors if canQuery is false
+func NewAWSInfraRepository(canQuery bool) repository.AWSInfraRepository {
+	return &AWSInfraRepository{
+		canQuery,
+		[]*models.AWSInfra{},
+	}
+}
+
+// CreateAWSInfra creates a new aws infra
+func (repo *AWSInfraRepository) CreateAWSInfra(
+	infra *models.AWSInfra,
+) (*models.AWSInfra, error) {
+	if !repo.canQuery {
+		return nil, errors.New("Cannot write database")
+	}
+
+	repo.awsInfras = append(repo.awsInfras, infra)
+	infra.ID = uint(len(repo.awsInfras))
+
+	return infra, nil
+}
+
+// ReadAWSInfra finds a aws infra by id
+func (repo *AWSInfraRepository) ReadAWSInfra(
+	id uint,
+) (*models.AWSInfra, error) {
+	if !repo.canQuery {
+		return nil, errors.New("Cannot read from database")
+	}
+
+	if int(id-1) >= len(repo.awsInfras) || repo.awsInfras[id-1] == nil {
+		return nil, gorm.ErrRecordNotFound
+	}
+
+	index := int(id - 1)
+	return repo.awsInfras[index], nil
+}
+
+// ListAWSInfrasByProjectID finds all aws infras
+// for a given project id
+func (repo *AWSInfraRepository) ListAWSInfrasByProjectID(
+	projectID uint,
+) ([]*models.AWSInfra, error) {
+	if !repo.canQuery {
+		return nil, errors.New("Cannot read from database")
+	}
+
+	res := make([]*models.AWSInfra, 0)
+
+	for _, infra := range repo.awsInfras {
+		if infra != nil && infra.ProjectID == projectID {
+			res = append(res, infra)
+		}
+	}
+
+	return res, nil
+}

+ 1 - 0
internal/repository/repository.go

@@ -10,6 +10,7 @@ type Repository struct {
 	Cluster          ClusterRepository
 	HelmRepo         HelmRepoRepository
 	Registry         RegistryRepository
+	AWSInfra         AWSInfraRepository
 	KubeIntegration  KubeIntegrationRepository
 	BasicIntegration BasicIntegrationRepository
 	OIDCIntegration  OIDCIntegrationRepository