feat: [CDE-192]: modularize gitspace services (#2404)

* feat: [CDE-192]: resource identifier empty
* feat: [CDE-192]: resource identifier empty
* feat: [CDE-192]: resource identifier empty
* feat: [CDE-192]: resource identifier empty
* feat: [CDE-192]: address comments
* feat: [CDE-192]: split config and resource creation
* feat: [CDE-192]: split config and res creation
* feat: [CDE-192]: modularize gitspace services
pull/3545/head
Ansuman Satapathy 2024-08-07 08:27:29 +00:00 committed by Harness
parent 52bfdfb3f8
commit 9fc9a498e2
8 changed files with 271 additions and 85 deletions

View File

@ -185,7 +185,7 @@ func (c *Controller) createOrFindInfraProviderResource(
}
func (c *Controller) autoCreateDefaultResource(ctx context.Context, parentSpace *types.Space, now int64) error {
infraProviderConfig := &types.InfraProviderConfig{
defaultDockerConfig := &types.InfraProviderConfig{
Identifier: defaultResourceIdentifier,
Name: "default docker infrastructure",
Type: enum.InfraProviderTypeDocker,
@ -194,10 +194,10 @@ func (c *Controller) autoCreateDefaultResource(ctx context.Context, parentSpace
Created: now,
Updated: now,
}
defaultResource := &types.InfraProviderResource{
defaultResource := types.InfraProviderResource{
Identifier: defaultResourceIdentifier,
Name: "Standard Docker Resource",
InfraProviderConfigIdentifier: infraProviderConfig.Identifier,
InfraProviderConfigIdentifier: defaultDockerConfig.Identifier,
InfraProviderType: enum.InfraProviderTypeDocker,
CPU: wrapString("any"),
Memory: wrapString("any"),
@ -208,10 +208,10 @@ func (c *Controller) autoCreateDefaultResource(ctx context.Context, parentSpace
Created: now,
Updated: now,
}
infraProviderConfig.Resources = []*types.InfraProviderResource{defaultResource}
err := c.infraProviderSvc.CreateInfraProvider(ctx, infraProviderConfig)
defaultDockerConfig.Resources = []types.InfraProviderResource{defaultResource}
err := c.infraProviderSvc.CreateInfraProvider(ctx, defaultDockerConfig)
if err != nil {
return fmt.Errorf("could not autocreate the resources: %w", err)
return fmt.Errorf("could not auto-create the infra provider: %w", err)
}
return nil
}

View File

@ -17,7 +17,6 @@ package infraprovider
import (
"context"
"fmt"
"strings"
"time"
apiauth "github.com/harness/gitness/app/api/auth"
@ -27,6 +26,8 @@ import (
"github.com/harness/gitness/types/enum"
)
const NoResourceIdentifier = ""
type CreateInput struct {
Identifier string `json:"identifier"`
SpaceRef string `json:"space_ref"` // Ref of the parent space
@ -51,25 +52,31 @@ type ResourceInput struct {
TemplateIdentifier *string `json:"template_identifier"`
}
// Create creates a new infraprovider config.
type TemplateInput struct {
Identifier string `json:"identifier"`
Description string `json:"description"`
Data string `json:"data"`
}
// Create creates a new infra provider.
func (c *Controller) Create(
ctx context.Context,
session *auth.Session,
in *CreateInput,
session auth.Session,
in CreateInput,
) (*types.InfraProviderConfig, error) {
if err := c.sanitizeCreateInput(in); err != nil {
return nil, fmt.Errorf("invalid input: %w", err)
}
parentSpace, err := c.spaceStore.FindByRef(ctx, in.SpaceRef)
if err != nil {
return nil, fmt.Errorf("failed to find parent by ref: %w", err)
return nil, fmt.Errorf("failed to find parent by ref %q : %w", in.SpaceRef, err)
}
if err = apiauth.CheckInfraProvider(
ctx,
c.authorizer,
session,
&session,
parentSpace.Path,
"",
NoResourceIdentifier,
enum.PermissionInfraProviderEdit); err != nil {
return nil, err
}
@ -82,42 +89,17 @@ func (c *Controller) Create(
Created: now,
Updated: now,
}
var resources []*types.InfraProviderResource
for _, res := range in.Resources {
infraProviderResource := &types.InfraProviderResource{
Identifier: res.Identifier,
InfraProviderType: res.InfraProviderType,
Name: res.Name,
SpaceID: parentSpace.ID,
CPU: res.CPU,
Memory: res.Memory,
Disk: res.Disk,
Network: res.Network,
Region: strings.Join(res.Region, " "), // TODO fix
Metadata: res.Metadata,
GatewayHost: res.GatewayHost,
GatewayPort: res.GatewayPort, // No template as of now
Created: now,
Updated: now,
}
resources = append(resources, infraProviderResource)
}
infraProviderConfig.Resources = resources
infraProviderConfig.Resources = mapToResourceEntity(in.Resources, *parentSpace, infraProviderConfig.ID)
err = c.infraproviderSvc.CreateInfraProvider(ctx, infraProviderConfig)
if err != nil {
return nil, fmt.Errorf("unable to create the infraprovider: %w", err)
return nil, fmt.Errorf("unable to create the infraprovider: %q %w", infraProviderConfig.Identifier, err)
}
return infraProviderConfig, nil
}
func (c *Controller) sanitizeCreateInput(in *CreateInput) error {
func (c *Controller) sanitizeCreateInput(in CreateInput) error {
if err := check.Identifier(in.Identifier); err != nil {
return err
}
for _, resource := range in.Resources {
if err := check.Identifier(resource.Identifier); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,142 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package infraprovider
import (
"context"
"fmt"
"strings"
"time"
apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/auth"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/check"
"github.com/harness/gitness/types/enum"
)
func (c *Controller) CreateTemplate(
ctx context.Context,
session *auth.Session,
in *TemplateInput,
configIdentifier string,
spaceRef string,
) (*types.InfraProviderTemplate, error) {
now := time.Now().UnixMilli()
parentSpace, err := c.spaceStore.FindByRef(ctx, spaceRef)
if err != nil {
return nil, fmt.Errorf("failed to find parent by ref: %w", err)
}
if err = apiauth.CheckInfraProvider(
ctx,
c.authorizer,
session,
parentSpace.Path,
NoResourceIdentifier,
enum.PermissionInfraProviderEdit); err != nil {
return nil, err
}
infraProviderConfig, err := c.infraproviderSvc.Find(ctx, parentSpace, configIdentifier)
if err != nil {
return nil, fmt.Errorf("failed to find infraprovider config by ref: %w", err)
}
providerTemplate := &types.InfraProviderTemplate{
Identifier: in.Identifier,
InfraProviderConfigIdentifier: infraProviderConfig.Identifier,
InfraProviderConfigID: infraProviderConfig.ID,
Description: in.Description,
Data: in.Data,
Version: 0,
SpaceID: parentSpace.ID,
SpacePath: parentSpace.Path,
Created: now,
Updated: now,
}
err = c.infraproviderSvc.CreateTemplate(ctx, providerTemplate)
if err != nil {
return nil, err
}
return providerTemplate, nil
}
func (c *Controller) CreateResources(
ctx context.Context,
session auth.Session,
in []ResourceInput,
configIdentifier string,
spaceRef string,
) ([]types.InfraProviderResource, error) {
if err := c.sanitizeResourceInput(in); err != nil {
return nil, fmt.Errorf("invalid input: %w", err)
}
now := time.Now().UnixMilli()
parentSpace, err := c.spaceStore.FindByRef(ctx, spaceRef)
if err != nil {
return nil, fmt.Errorf("failed to find parent by ref: %w", err)
}
if err = apiauth.CheckInfraProvider(
ctx,
c.authorizer,
&session,
parentSpace.Path,
NoResourceIdentifier,
enum.PermissionInfraProviderEdit); err != nil {
return nil, err
}
infraProviderConfig, err := c.infraproviderSvc.Find(ctx, parentSpace, configIdentifier)
if err != nil {
return nil, fmt.Errorf("failed to find infraprovider config by ref: %q %w", infraProviderConfig.Identifier, err)
}
resources := mapToResourceEntity(in, *parentSpace, now)
err = c.infraproviderSvc.CreateResources(ctx, resources, infraProviderConfig.ID)
if err != nil {
return nil, err
}
return resources, nil
}
func mapToResourceEntity(in []ResourceInput, parentSpace types.Space, now int64) []types.InfraProviderResource {
var resources []types.InfraProviderResource
for _, res := range in {
infraProviderResource := types.InfraProviderResource{
Identifier: res.Identifier,
InfraProviderType: res.InfraProviderType,
Name: res.Name,
SpaceID: parentSpace.ID,
CPU: res.CPU,
Memory: res.Memory,
Disk: res.Disk,
Network: res.Network,
Region: strings.Join(res.Region, " "), // TODO fix
Metadata: res.Metadata,
GatewayHost: res.GatewayHost,
GatewayPort: res.GatewayPort, // No template as of now
Created: now,
Updated: now,
}
resources = append(resources, infraProviderResource)
}
return resources
}
func (c *Controller) sanitizeResourceInput(in []ResourceInput) error {
for _, resource := range in {
if err := check.Identifier(resource.Identifier); err != nil {
return err
}
}
return nil
}

View File

@ -36,7 +36,7 @@ func HandleCreateConfig(infraProviderCtrl *infraprovider.Controller) http.Handle
return
}
infraProviderConfig, err := infraProviderCtrl.Create(ctx, session, in)
infraProviderConfig, err := infraProviderCtrl.Create(ctx, *session, *in)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return

View File

@ -26,15 +26,17 @@ import (
func NewService(
tx dbtx.Transactor,
infraProviderResourceStore store.InfraProviderResourceStore,
infraProviderConfigStore store.InfraProviderConfigStore,
resourceStore store.InfraProviderResourceStore,
configStore store.InfraProviderConfigStore,
templateStore store.InfraProviderTemplateStore,
factory infraprovider.Factory,
spaceStore store.SpaceStore,
) *Service {
return &Service{
tx: tx,
infraProviderResourceStore: infraProviderResourceStore,
infraProviderConfigStore: infraProviderConfigStore,
infraProviderResourceStore: resourceStore,
infraProviderConfigStore: configStore,
infraProviderTemplateStore: templateStore,
infraProviderFactory: factory,
spaceStore: spaceStore,
}
@ -43,6 +45,7 @@ func NewService(
type Service struct {
infraProviderResourceStore store.InfraProviderResourceStore
infraProviderConfigStore store.InfraProviderConfigStore
infraProviderTemplateStore store.InfraProviderTemplateStore
infraProviderFactory infraprovider.Factory
spaceStore store.SpaceStore
tx dbtx.Transactor
@ -55,14 +58,21 @@ func (c *Service) Find(
) (*types.InfraProviderConfig, error) {
infraProviderConfig, err := c.infraProviderConfigStore.FindByIdentifier(ctx, space.ID, identifier)
if err != nil {
return nil, fmt.Errorf("failed to find infraprovider config: %w", err)
return nil, fmt.Errorf("failed to find infraprovider config: %q %w", identifier, err)
}
resources, err := c.infraProviderResourceStore.List(ctx, infraProviderConfig.ID, types.ListQueryFilter{})
if err != nil {
return nil, fmt.Errorf("failed to find infraprovider resources: %w", err)
return nil, fmt.Errorf("failed to find infraprovider resources for config: %q %w",
infraProviderConfig.Identifier, err)
}
infraProviderConfig.SpacePath = space.Path
infraProviderConfig.Resources = resources
values := make([]types.InfraProviderResource, len(infraProviderConfig.Resources))
for i, ptr := range resources {
if ptr != nil {
values[i] = *ptr
}
}
infraProviderConfig.Resources = values
return infraProviderConfig, nil
}
@ -82,34 +92,85 @@ func (c *Service) CreateInfraProvider(
infraProviderConfig *types.InfraProviderConfig,
) error {
err := c.tx.WithTx(ctx, func(ctx context.Context) error {
err := c.infraProviderConfigStore.Create(ctx, infraProviderConfig)
err := c.createConfig(ctx, infraProviderConfig)
if err != nil {
return fmt.Errorf("failed to create infraprovider config for : %q %w", infraProviderConfig.Identifier, err)
return fmt.Errorf("could not autocreate the config: %q %w", infraProviderConfig.Identifier, err)
}
infraProvider, err := c.infraProviderFactory.GetInfraProvider(infraProviderConfig.Type)
err = c.createResources(ctx, infraProviderConfig.Resources, infraProviderConfig.ID)
if err != nil {
return fmt.Errorf("failed to fetch infrastructure impl for type : %q %w", infraProviderConfig.Type, err)
}
if len(infraProvider.TemplateParams()) > 0 {
return fmt.Errorf("failed to fetch templates") // TODO Implement
}
parameters := []types.InfraProviderParameter{}
// TODO logic to populate paramteters as per the provider type
err = infraProvider.ValidateParams(parameters)
if err != nil {
return fmt.Errorf("failed to validate infraprovider templates")
}
for _, res := range infraProviderConfig.Resources {
res.InfraProviderConfigID = infraProviderConfig.ID
err = c.infraProviderResourceStore.Create(ctx, res)
if err != nil {
return fmt.Errorf("failed to create infraprovider resource for : %q %w", res.Identifier, err)
}
return fmt.Errorf("could not autocreate the resources: %v %w", infraProviderConfig.Resources, err)
}
return nil
})
if err != nil {
return fmt.Errorf("failed to complete txn for the infraprovider resource : %w", err)
return fmt.Errorf("failed to complete txn for the infraprovider %w", err)
}
return nil
}
func (c *Service) createConfig(ctx context.Context, infraProviderConfig *types.InfraProviderConfig) error {
err := c.infraProviderConfigStore.Create(ctx, infraProviderConfig)
if err != nil {
return fmt.Errorf("failed to create infraprovider config for : %q %w", infraProviderConfig.Identifier, err)
}
return nil
}
func (c *Service) CreateResources(ctx context.Context, resources []types.InfraProviderResource, configID int64) error {
err := c.tx.WithTx(ctx, func(ctx context.Context) error {
return c.createResources(ctx, resources, configID)
})
if err != nil {
return fmt.Errorf("failed to complete txn for the infraprovider resource %w", err)
}
return nil
}
func (c *Service) createResources(ctx context.Context, resources []types.InfraProviderResource, configID int64) error {
for idx, res := range resources {
res.InfraProviderConfigID = configID
infraProvider, err := c.infraProviderFactory.GetInfraProvider(res.InfraProviderType)
if err != nil {
return fmt.Errorf("failed to fetch infrastructure impl for type : %q %w", res.InfraProviderType, err)
}
if len(infraProvider.TemplateParams()) > 0 {
err = c.validateTemplates(ctx, infraProvider, res)
if err != nil {
return err
}
}
err = c.infraProviderResourceStore.Create(ctx, &resources[idx])
if err != nil {
return fmt.Errorf("failed to create infraprovider resource for : %q %w", res.Identifier, err)
}
}
return nil
}
func (c *Service) validateTemplates(
ctx context.Context,
infraProvider infraprovider.InfraProvider,
res types.InfraProviderResource,
) error {
templateParams := infraProvider.TemplateParams()
for _, param := range templateParams {
key := param.Name
if res.Metadata[key] != "" {
templateIdentifier := res.Metadata[key]
_, err := c.infraProviderTemplateStore.FindByIdentifier(
ctx, res.SpaceID, templateIdentifier)
if err != nil {
return fmt.Errorf("unable to get template params for ID : %s %w",
res.Metadata[key], err)
}
}
}
return nil
}
func (c *Service) CreateTemplate(
ctx context.Context,
template *types.InfraProviderTemplate,
) error {
return c.infraProviderTemplateStore.Create(ctx, template)
}

View File

@ -28,10 +28,11 @@ var WireSet = wire.NewSet(
func ProvideInfraProvider(
tx dbtx.Transactor,
infraProviderResourceStore store.InfraProviderResourceStore,
infraProviderConfigStore store.InfraProviderConfigStore,
resourceStore store.InfraProviderResourceStore,
configStore store.InfraProviderConfigStore,
templateStore store.InfraProviderTemplateStore,
infraProviderFactory infraprovider.Factory,
spaceStore store.SpaceStore,
) *Service {
return NewService(tx, infraProviderResourceStore, infraProviderConfigStore, infraProviderFactory, spaceStore)
return NewService(tx, resourceStore, configStore, templateStore, infraProviderFactory, spaceStore)
}

View File

@ -256,6 +256,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
gitspaceInstanceStore := database.ProvideGitspaceInstanceStore(db)
infraProviderResourceStore := database.ProvideInfraProviderResourceStore(db)
infraProviderConfigStore := database.ProvideInfraProviderConfigStore(db)
infraProviderTemplateStore := database.ProvideInfraProviderTemplateStore(db)
dockerConfig, err := server.ProvideDockerConfig(config)
if err != nil {
return nil, err
@ -267,7 +268,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
}
dockerProvider := infraprovider.ProvideDockerProvider(dockerConfig, dockerClientFactory, eventsReporter)
factory := infraprovider.ProvideFactory(dockerProvider)
infraproviderService := infraprovider2.ProvideInfraProvider(transactor, infraProviderResourceStore, infraProviderConfigStore, factory, spaceStore)
infraproviderService := infraprovider2.ProvideInfraProvider(transactor, infraProviderResourceStore, infraProviderConfigStore, infraProviderTemplateStore, factory, spaceStore)
gitspaceService := gitspace.ProvideGitspace(transactor, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, infraproviderService)
spaceController := space.ProvideController(config, transactor, provider, streamer, spaceIdentifier, authorizer, spacePathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore, repository, exporterRepository, resourceLimiter, publicaccessService, auditService, gitspaceService, labelService)
pipelineController := pipeline.ProvideController(repoStore, triggerStore, authorizer, pipelineStore)
@ -353,7 +354,6 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
genericSCM := scm.ProvideGenericSCM()
scmFactory := scm.ProvideFactory(gitnessSCM, genericSCM)
scmSCM := scm.ProvideSCM(scmFactory)
infraProviderTemplateStore := database.ProvideInfraProviderTemplateStore(db)
infraProvisionedStore := database.ProvideInfraProvisionedStore(db)
infrastructureConfig := server.ProvideGitspaceInfraProvisionerConfig(config)
infraProvisioner := infrastructure.ProvideInfraProvisionerService(infraProviderConfigStore, infraProviderResourceStore, factory, infraProviderTemplateStore, infraProvisionedStore, infrastructureConfig)

View File

@ -19,16 +19,16 @@ import (
)
type InfraProviderConfig struct {
ID int64 `json:"-"`
Identifier string `json:"identifier"`
Name string `json:"name"`
Type enum.InfraProviderType `json:"type"`
Metadata map[string]string `json:"metadata"`
Resources []*InfraProviderResource `json:"resources"`
SpaceID int64 `json:"-"`
SpacePath string `json:"space_path"`
Created int64 `json:"created"`
Updated int64 `json:"updated"`
ID int64 `json:"-"`
Identifier string `json:"identifier"`
Name string `json:"name"`
Type enum.InfraProviderType `json:"type"`
Metadata map[string]string `json:"metadata"`
Resources []InfraProviderResource `json:"resources"`
SpaceID int64 `json:"-"`
SpacePath string `json:"space_path"`
Created int64 `json:"created"`
Updated int64 `json:"updated"`
}
type InfraProviderResource struct {