Browse Source

add api endpoints for overwriting aws integration

Alexander Belanger 5 years ago
parent
commit
719118500c

+ 14 - 0
dashboard/src/shared/api.tsx

@@ -45,6 +45,19 @@ const createAWSIntegration = baseApi<
   return `/api/projects/${pathParams.id}/integrations/aws`;
 });
 
+const overwriteAWSIntegration = baseApi<
+  {
+    aws_access_key_id: string;
+    aws_secret_access_key: string;
+  },
+  { 
+    projectID: number,
+    awsIntegrationID: number,
+  }
+>("POST", (pathParams) => {
+  return `/api/projects/${pathParams.projectID}/integrations/aws/${pathParams.awsIntegrationID}/overwrite`;
+});
+
 const createDOCR = baseApi<
   {
     do_integration_id: number;
@@ -861,6 +874,7 @@ export default {
   connectECRRegistry,
   connectGCRRegistry,
   createAWSIntegration,
+  overwriteAWSIntegration,
   createDOCR,
   createDOKS,
   createEmailVerification,

+ 9 - 0
internal/forms/integration.go

@@ -66,3 +66,12 @@ func (caf *CreateAWSIntegrationForm) ToAWSIntegration() (*ints.AWSIntegration, e
 		AWSSecretAccessKey: []byte(caf.AWSSecretAccessKey),
 	}, nil
 }
+
+// OverwriteAWSIntegrationForm represents the accepted values for overwriting an
+// AWS Integration
+type OverwriteAWSIntegrationForm struct {
+	UserID             uint   `json:"user_id" form:"required"`
+	ProjectID          uint   `json:"project_id" form:"required"`
+	AWSAccessKeyID     string `json:"aws_access_key_id"`
+	AWSSecretAccessKey string `json:"aws_secret_access_key"`
+}

+ 17 - 0
internal/repository/gorm/auth.go

@@ -936,6 +936,23 @@ func (repo *AWSIntegrationRepository) CreateAWSIntegration(
 	return am, nil
 }
 
+// UpdateCluster modifies an existing Cluster in the database
+func (repo *AWSIntegrationRepository) OverwriteAWSIntegration(
+	am *ints.AWSIntegration,
+) (*ints.AWSIntegration, error) {
+	err := repo.EncryptAWSIntegrationData(am, repo.key)
+
+	if err != nil {
+		return nil, err
+	}
+
+	if err := repo.db.Save(am).Error; err != nil {
+		return nil, err
+	}
+
+	return am, nil
+}
+
 // ReadAWSIntegration finds a aws auth mechanism by id
 func (repo *AWSIntegrationRepository) ReadAWSIntegration(
 	id uint,

+ 51 - 0
internal/repository/gorm/auth_test.go

@@ -499,6 +499,57 @@ func TestCreateAWSIntegration(t *testing.T) {
 	}
 }
 
+func TestOverwriteAWSIntegration(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_overwrite_aws.db",
+	}
+
+	setupTestEnv(tester, t)
+	initUser(tester, t)
+	initProject(tester, t)
+	initAWSIntegration(tester, t)
+	defer cleanup(tester, t)
+
+	aws, err := tester.repo.AWSIntegration.ReadAWSIntegration(1)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	aws.AWSAccessKeyID = []byte("accesskey2")
+	aws.AWSSecretAccessKey = []byte("secret2")
+
+	aws, err = tester.repo.AWSIntegration.OverwriteAWSIntegration(aws)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	gotAWS, err := tester.repo.AWSIntegration.ReadAWSIntegration(1)
+
+	expAWS := &ints.AWSIntegration{
+		ProjectID:          tester.initProjects[0].ID,
+		UserID:             tester.initUsers[0].ID,
+		AWSClusterID:       []byte("example-cluster-0"),
+		AWSAccessKeyID:     []byte("accesskey2"),
+		AWSSecretAccessKey: []byte("secret2"),
+		AWSSessionToken:    []byte("optional"),
+	}
+
+	// make sure id is 1
+	if gotAWS.Model.ID != 1 {
+		t.Errorf("incorrect aws integration ID: expected %d, got %d\n", 1, gotAWS.Model.ID)
+	}
+
+	// reset fields for deep.Equal
+	gotAWS.Model = orm.Model{}
+
+	if diff := deep.Equal(expAWS, gotAWS); diff != nil {
+		t.Errorf("incorrect aws integration")
+		t.Error(diff)
+	}
+}
+
 func TestListAWSIntegrationsByProjectID(t *testing.T) {
 	tester := &tester{
 		dbFileName: "./porter_list_awss.db",

+ 1 - 0
internal/repository/integrations.go

@@ -41,6 +41,7 @@ type OAuthIntegrationRepository interface {
 // mechanism
 type AWSIntegrationRepository interface {
 	CreateAWSIntegration(am *ints.AWSIntegration) (*ints.AWSIntegration, error)
+	OverwriteAWSIntegration(am *ints.AWSIntegration) (*ints.AWSIntegration, error)
 	ReadAWSIntegration(id uint) (*ints.AWSIntegration, error)
 	ListAWSIntegrationsByProjectID(projectID uint) ([]*ints.AWSIntegration, error)
 }

+ 17 - 0
internal/repository/memory/auth.go

@@ -311,6 +311,23 @@ func (repo *AWSIntegrationRepository) CreateAWSIntegration(
 	return am, nil
 }
 
+func (repo *AWSIntegrationRepository) OverwriteAWSIntegration(
+	am *ints.AWSIntegration,
+) (*ints.AWSIntegration, error) {
+	if !repo.canQuery {
+		return nil, errors.New("Cannot write database")
+	}
+
+	if int(am.ID-1) >= len(repo.awsIntegrations) || repo.awsIntegrations[am.ID-1] == nil {
+		return nil, gorm.ErrRecordNotFound
+	}
+
+	index := int(am.ID - 1)
+	repo.awsIntegrations[index] = am
+
+	return am, nil
+}
+
 // ReadAWSIntegration finds a aws auth mechanism by id
 func (repo *AWSIntegrationRepository) ReadAWSIntegration(
 	id uint,

+ 71 - 0
server/api/integration_handler.go

@@ -186,6 +186,77 @@ func (app *App) HandleCreateAWSIntegration(w http.ResponseWriter, r *http.Reques
 	}
 }
 
+// HandleOverwriteAWSIntegration overwrites the ID of an AWS integration in the DB
+func (app *App) HandleOverwriteAWSIntegration(w http.ResponseWriter, r *http.Request) {
+	userID, err := app.getUserIDFromRequest(r)
+
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
+
+	if err != nil || projID == 0 {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+
+	awsIntegrationID, err := strconv.ParseUint(chi.URLParam(r, "aws_integration_id"), 0, 64)
+
+	if err != nil || awsIntegrationID == 0 {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+
+	form := &forms.OverwriteAWSIntegrationForm{
+		UserID:    userID,
+		ProjectID: uint(projID),
+	}
+
+	// decode from JSON to form value
+	if err := json.NewDecoder(r.Body).Decode(form); err != nil {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+
+	// validate the form
+	if err := app.validator.Struct(form); err != nil {
+		app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
+		return
+	}
+
+	// read the aws integration by ID and overwrite the access id/secret
+	awsIntegration, err := app.Repo.AWSIntegration.ReadAWSIntegration(uint(awsIntegrationID))
+
+	if err != nil {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+
+	awsIntegration.AWSAccessKeyID = []byte(form.AWSAccessKeyID)
+	awsIntegration.AWSSecretAccessKey = []byte(form.AWSSecretAccessKey)
+
+	// handle write to the database
+	awsIntegration, err = app.Repo.AWSIntegration.OverwriteAWSIntegration(awsIntegration)
+
+	if err != nil {
+		app.handleErrorDataWrite(err, w)
+		return
+	}
+
+	app.Logger.Info().Msgf("AWS integration overwritten: %d", awsIntegration.ID)
+
+	w.WriteHeader(http.StatusCreated)
+
+	awsExt := awsIntegration.Externalize()
+
+	if err := json.NewEncoder(w).Encode(awsExt); err != nil {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+}
+
 // HandleCreateBasicAuthIntegration creates a new basic auth integration in the DB
 func (app *App) HandleCreateBasicAuthIntegration(w http.ResponseWriter, r *http.Request) {
 	userID, err := app.getUserIDFromRequest(r)

+ 15 - 0
server/router/router.go

@@ -693,6 +693,21 @@ func New(a *api.App) *chi.Mux {
 				),
 			)
 
+			r.Method(
+				"POST",
+				"/projects/{project_id}/integrations/aws/{aws_integration_id}/overwrite",
+				auth.DoesUserHaveProjectAccess(
+					auth.DoesUserHaveAWSIntegrationAccess(
+						requestlog.NewHandler(a.HandleOverwriteAWSIntegration, l),
+						mw.URLParam,
+						mw.URLParam,
+						false,
+					),
+					mw.URLParam,
+					mw.WriteAccess,
+				),
+			)
+
 			r.Method(
 				"POST",
 				"/projects/{project_id}/integrations/basic",