feat: [CDE-203]: Making infra processing async. (#2325)

* Cleaning the flow around gitspace instance update.
* Renaming params and param schema types.
* Correcting comments.
* feat: [CDE-203]: Making infra processing async.
* feat: [CDE-203]: Making infra processing async.
* feat: [CDE-203]: Making infra processing async.
pull/3545/head
Dhruv Dhruv 2024-08-01 10:01:31 +00:00 committed by Harness
parent bd9cfce3ab
commit 9d5071b45c
52 changed files with 1300 additions and 455 deletions

View File

@ -34,7 +34,7 @@ import (
const defaultAccessKey = "Harness@123"
const defaultMachineUser = "harness"
const gitspaceTimedOutInMintues = 10
const gitspaceTimedOutInMintues = 5
type ActionInput struct {
Action enum.GitspaceActionType `json:"action"`
@ -135,21 +135,28 @@ func (c *Controller) startGitspaceAction(
func (c *Controller) asyncOperation(
ctxWithTimedOut context.Context,
config *types.GitspaceConfig,
config types.GitspaceConfig,
action enum.GitspaceActionType,
stateChannel chan enum.GitspaceInstanceStateType,
errChannel chan error,
) {
defer close(stateChannel)
defer close(errChannel)
var orchestrateErr error
var instanceState enum.GitspaceInstanceStateType
switch action {
case enum.GitspaceActionTypeStart:
orchestrateErr = c.orchestrator.StartGitspace(ctxWithTimedOut, config)
instanceState, orchestrateErr = c.orchestrator.TriggerStartGitspace(ctxWithTimedOut, config)
case enum.GitspaceActionTypeStop:
orchestrateErr = c.orchestrator.StopGitspace(ctxWithTimedOut, config)
instanceState, orchestrateErr = c.orchestrator.TriggerStopGitspace(ctxWithTimedOut, config)
}
if orchestrateErr != nil {
errChannel <- fmt.Errorf("failed to find start/stop gitspace : %s %w", config.Identifier, orchestrateErr)
errChannel <- fmt.Errorf("failed to start/stop gitspace: %s %w", config.Identifier, orchestrateErr)
}
close(errChannel)
stateChannel <- instanceState
}
func (c *Controller) submitAsyncOps(
@ -157,21 +164,25 @@ func (c *Controller) submitAsyncOps(
config *types.GitspaceConfig,
action enum.GitspaceActionType,
) {
errChannel := make(chan error)
stateChannel := make(chan enum.GitspaceInstanceStateType)
submitCtx := context.WithoutCancel(ctx)
ttlExecuteContext, cancel := context.WithTimeout(submitCtx, gitspaceTimedOutInMintues*time.Minute)
// submit an async task with a TTL
errChannel := make(chan error)
go c.asyncOperation(ttlExecuteContext, config, action, errChannel)
// wait execution completion for the specified time or mark it as an error
go c.asyncOperation(ttlExecuteContext, *config, action, stateChannel, errChannel)
var err error
var instanceState enum.GitspaceInstanceStateType
go func() {
defer c.updateGitspaceInstance(submitCtx, config)
select {
case <-ttlExecuteContext.Done():
if ttlExecuteContext.Err() != nil {
err = ttlExecuteContext.Err()
}
case err = <-errChannel:
case instanceState = <-stateChannel:
}
if err != nil {
log.Err(err).Msgf("error during async execution for %s", config.GitspaceInstance.Identifier)
@ -182,6 +193,15 @@ func (c *Controller) submitAsyncOps(
c.emitGitspaceConfigEvent(ttlExecuteContext, config, enum.GitspaceEventTypeGitspaceActionStopFailed)
}
}
if instanceState == "" {
instanceState = enum.GitspaceInstanceStateError
}
config.GitspaceInstance.State = instanceState
c.updateGitspaceInstance(submitCtx, config.GitspaceInstance)
cancel()
}()
}
@ -286,11 +306,11 @@ func (c *Controller) emitGitspaceConfigEvent(
func (c *Controller) updateGitspaceInstance(
ctx context.Context,
config *types.GitspaceConfig,
instance *types.GitspaceInstance,
) {
err := c.gitspaceInstanceStore.Update(ctx, config.GitspaceInstance)
err := c.gitspaceInstanceStore.Update(ctx, instance)
if err != nil {
log.Err(err).Msgf(
"failed to update gitspace instance during exec %q", config.GitspaceInstance.Identifier)
"failed to update gitspace instance during exec %q", instance.Identifier)
}
}

View File

@ -20,6 +20,7 @@ import (
"github.com/harness/gitness/app/gitspace/logutil"
"github.com/harness/gitness/app/gitspace/orchestrator"
"github.com/harness/gitness/app/gitspace/scm"
"github.com/harness/gitness/app/services/gitspace"
"github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/store/database/dbtx"
@ -38,6 +39,7 @@ type Controller struct {
statefulLogger *logutil.StatefulLogger
scm scm.SCM
repoStore store.RepoStore
gitspaceSvc *gitspace.Service
}
func NewController(
@ -53,6 +55,7 @@ func NewController(
statefulLogger *logutil.StatefulLogger,
scm scm.SCM,
repoStore store.RepoStore,
gitspaceSvc *gitspace.Service,
) *Controller {
return &Controller{
tx: tx,
@ -67,5 +70,6 @@ func NewController(
statefulLogger: statefulLogger,
scm: scm,
repoStore: repoStore,
gitspaceSvc: gitspaceSvc,
}
}

View File

@ -24,7 +24,6 @@ import (
apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/app/auth"
infraproviderenum "github.com/harness/gitness/infraprovider/enum"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/check"
"github.com/harness/gitness/types/enum"
@ -189,7 +188,7 @@ func (c *Controller) autoCreateDefaultResource(ctx context.Context, parentSpace
infraProviderConfig := &types.InfraProviderConfig{
Identifier: defaultResourceIdentifier,
Name: "default docker infrastructure",
Type: infraproviderenum.InfraProviderTypeDocker,
Type: enum.InfraProviderTypeDocker,
SpaceID: parentSpace.ID,
SpacePath: parentSpace.Path,
Created: now,
@ -199,7 +198,7 @@ func (c *Controller) autoCreateDefaultResource(ctx context.Context, parentSpace
Identifier: defaultResourceIdentifier,
Name: "Standard Docker Resource",
InfraProviderConfigIdentifier: infraProviderConfig.Identifier,
InfraProviderType: infraproviderenum.InfraProviderTypeDocker,
InfraProviderType: enum.InfraProviderTypeDocker,
CPU: wrapString("any"),
Memory: wrapString("any"),
Disk: wrapString("any"),

View File

@ -51,26 +51,34 @@ func (c *Controller) Delete(
instance, _ := c.gitspaceInstanceStore.FindLatestByGitspaceConfigID(ctx, gitspaceConfig.ID, gitspaceConfig.SpaceID)
gitspaceConfig.GitspaceInstance = instance
gitspaceConfig.SpacePath = space.Path
if instance != nil {
if stopErr := c.stopRunningGitspace(ctx, gitspaceConfig); stopErr != nil {
if instance == nil {
gitspaceConfig.IsDeleted = true
err = c.gitspaceConfigStore.Update(ctx, gitspaceConfig)
if err != nil {
return fmt.Errorf("failed to mark gitspace config as deleted: %w", err)
}
} else {
instanceState, stopErr := c.stopRunningGitspace(ctx, *gitspaceConfig)
if stopErr != nil {
return stopErr
}
}
gitspaceConfig.IsDeleted = true
if err = c.gitspaceConfigStore.Update(ctx, gitspaceConfig); err != nil {
return fmt.Errorf("failed to delete gitspace config with ID: %s %w", gitspaceConfig.Identifier, err)
instance.State = instanceState
err = c.gitspaceInstanceStore.Update(ctx, instance)
if err != nil {
return fmt.Errorf("failed to update instance: %w", err)
}
}
return nil
}
func (c *Controller) stopRunningGitspace(
ctx context.Context,
config *types.GitspaceConfig,
) error {
if instanceUpdated, err := c.orchestrator.DeleteGitspace(ctx, config); err != nil {
return err
} else if err = c.gitspaceInstanceStore.Update(ctx, instanceUpdated); err != nil {
return err
config types.GitspaceConfig,
) (enum.GitspaceInstanceStateType, error) {
instanceState, err := c.orchestrator.TriggerDeleteGitspace(ctx, config)
if err != nil {
return instanceState, err
}
return nil
return instanceState, nil
}

View File

@ -20,7 +20,6 @@ import (
apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/auth"
"github.com/harness/gitness/store/database/dbtx"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
@ -32,45 +31,18 @@ func (c *Controller) Find(
identifier string,
) (*types.GitspaceConfig, error) {
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
const resourceNotFoundErr = "Failed to find gitspace: resource not found"
if err != nil {
return nil, fmt.Errorf("failed to find space: %w", err)
}
err = apiauth.CheckGitspace(ctx, c.authorizer, session, space.Path, identifier, enum.PermissionGitspaceView)
if err != nil {
return nil, fmt.Errorf("failed to authorize: %w", err)
}
var gitspaceConfig *types.GitspaceConfig
err = c.tx.WithTx(ctx, func(ctx context.Context) error {
gitspaceConfig, err = c.gitspaceConfigStore.FindByIdentifier(ctx, space.ID, identifier)
if err != nil {
return fmt.Errorf("failed to find gitspace config: %w", err)
}
infraProviderResource, err := c.infraProviderSvc.FindResource(ctx, gitspaceConfig.InfraProviderResourceID)
if err != nil {
return fmt.Errorf("failed to find infra provider resource for gitspace config: %w", err)
}
gitspaceConfig.SpacePath = space.Path
gitspaceConfig.InfraProviderResourceIdentifier = infraProviderResource.Identifier
instance, err := c.gitspaceInstanceStore.FindLatestByGitspaceConfigID(ctx, gitspaceConfig.ID, gitspaceConfig.SpaceID)
if err != nil && err.Error() != resourceNotFoundErr { // TODO fix this
return fmt.Errorf("failed to find gitspace instance for config ID : %s %w", gitspaceConfig.Identifier, err)
}
if instance != nil {
gitspaceConfig.GitspaceInstance = instance
instance.SpacePath = gitspaceConfig.SpacePath
gitspaceStateType, err := enum.GetGitspaceStateFromInstance(instance.State)
if err != nil {
return err
}
gitspaceConfig.State = gitspaceStateType
} else {
gitspaceConfig.State = enum.GitspaceStateUninitialized
}
return nil
}, dbtx.TxDefaultReadOnly)
res, err := c.gitspaceSvc.Find(ctx, space.ID, space.Path, identifier)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to find gitspace: %w", err)
}
return gitspaceConfig, nil
return res, nil
}

View File

@ -20,6 +20,7 @@ import (
"github.com/harness/gitness/app/gitspace/logutil"
"github.com/harness/gitness/app/gitspace/orchestrator"
"github.com/harness/gitness/app/gitspace/scm"
"github.com/harness/gitness/app/services/gitspace"
"github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/store/database/dbtx"
@ -45,6 +46,7 @@ func ProvideController(
statefulLogger *logutil.StatefulLogger,
scm scm.SCM,
repoStore store.RepoStore,
gitspaceSvc *gitspace.Service,
) *Controller {
return NewController(
tx,
@ -59,5 +61,6 @@ func ProvideController(
statefulLogger,
scm,
repoStore,
gitspaceSvc,
)
}

View File

@ -22,34 +22,33 @@ import (
apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/auth"
infraproviderenum "github.com/harness/gitness/infraprovider/enum"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/check"
"github.com/harness/gitness/types/enum"
)
type CreateInput struct {
Identifier string `json:"identifier"`
SpaceRef string `json:"space_ref"` // Ref of the parent space
Name string `json:"name"`
Type infraproviderenum.InfraProviderType `json:"type"`
Metadata map[string]string `json:"metadata"`
Resources []ResourceInput `json:"resources"`
Identifier string `json:"identifier"`
SpaceRef string `json:"space_ref"` // Ref of the parent space
Name string `json:"name"`
Type enum.InfraProviderType `json:"type"`
Metadata map[string]string `json:"metadata"`
Resources []ResourceInput `json:"resources"`
}
type ResourceInput struct {
Identifier string `json:"identifier"`
Name string `json:"name"`
InfraProviderType infraproviderenum.InfraProviderType `json:"infra_provider_type"`
CPU *string `json:"cpu"`
Memory *string `json:"memory"`
Disk *string `json:"disk"`
Network *string `json:"network"`
Region []string `json:"region"`
Metadata map[string]string `json:"metadata"`
GatewayHost *string `json:"gateway_host"`
GatewayPort *string `json:"gateway_port"`
TemplateIdentifier *string `json:"template_identifier"`
Identifier string `json:"identifier"`
Name string `json:"name"`
InfraProviderType enum.InfraProviderType `json:"infra_provider_type"`
CPU *string `json:"cpu"`
Memory *string `json:"memory"`
Disk *string `json:"disk"`
Network *string `json:"network"`
Region []string `json:"region"`
Metadata map[string]string `json:"metadata"`
GatewayHost *string `json:"gateway_host"`
GatewayPort *string `json:"gateway_port"`
TemplateIdentifier *string `json:"template_identifier"`
}
// Create creates a new infraprovider config.

View File

@ -12,12 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package enum
package events
func toInterfaceSlice[T interface{}](vals []T) []interface{} {
res := make([]interface{}, len(vals))
for i := range vals {
res[i] = vals[i]
}
return res
}
const (
// category defines the event category used for this package.
category = "gitspace_infra"
)

View File

@ -0,0 +1,62 @@
// 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 events
import (
"context"
"github.com/harness/gitness/events"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
const (
// List all Gitspace Infra events below.
GitspaceInfraEvent events.EventType = "gitspace_infra_event"
)
type (
GitspaceInfraEventPayload struct {
Infra *types.Infrastructure `json:"infra,omitempty"`
Type enum.InfraEvent `json:"type"`
}
)
func (r *Reporter) EmitGitspaceInfraEvent(
ctx context.Context,
event events.EventType,
payload *GitspaceInfraEventPayload,
) {
if payload == nil {
return
}
eventID, err := events.ReporterSendEvent(r.innerReporter, ctx, event, payload)
if err != nil {
log.Ctx(ctx).Err(err).Msgf("failed to send %v event", event)
return
}
log.Ctx(ctx).Debug().Msgf("reported %v event with id '%s'", event, eventID)
}
func (r *Reader) RegisterGitspaceInfraEvent(
fn events.HandlerFunc[*GitspaceInfraEventPayload],
opts ...events.HandlerOption,
) error {
return events.ReaderRegisterEvent(r.innerReader, GitspaceInfraEvent, fn, opts...)
}

View File

@ -0,0 +1,38 @@
// 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 events
import (
"github.com/harness/gitness/events"
)
func NewReaderFactory(eventsSystem *events.System) (*events.ReaderFactory[*Reader], error) {
readerFactoryFunc := func(innerReader *events.GenericReader) (*Reader, error) {
return &Reader{
innerReader: innerReader,
}, nil
}
return events.NewReaderFactory(eventsSystem, category, readerFactoryFunc)
}
// Reader is the event reader for this package.
type Reader struct {
innerReader *events.GenericReader
}
func (r *Reader) Configure(opts ...events.ReaderOption) {
r.innerReader.Configure(opts...)
}

View File

@ -0,0 +1,37 @@
// 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 events
import (
"errors"
"github.com/harness/gitness/events"
)
// Reporter is the event reporter for this package.
type Reporter struct {
innerReporter *events.GenericReporter
}
func NewReporter(eventsSystem *events.System) (*Reporter, error) {
innerReporter, err := events.NewReporter(eventsSystem, category)
if err != nil {
return nil, errors.New("failed to create new GenericReporter from event system")
}
return &Reporter{
innerReporter: innerReporter,
}, nil
}

View File

@ -0,0 +1,35 @@
// 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 events
import (
"github.com/harness/gitness/events"
"github.com/google/wire"
)
// WireSet provides a wire set for this package.
var WireSet = wire.NewSet(
ProvideReaderFactory,
ProvideReporter,
)
func ProvideReaderFactory(eventsSystem *events.System) (*events.ReaderFactory[*Reader], error) {
return NewReaderFactory(eventsSystem)
}
func ProvideReporter(eventsSystem *events.System) (*Reporter, error) {
return NewReporter(eventsSystem)
}

View File

@ -17,40 +17,64 @@ package infrastructure
import (
"context"
"github.com/harness/gitness/infraprovider"
"github.com/harness/gitness/types"
)
// TODO Check if the interface can be discarded
type InfraProvisioner interface {
// Provision provisions infra resources using the infraProviderResource with different infra providers and
// stores the details in the db depending on the provisioning type.
Provision(
// TriggerProvision triggers the provisionining of infra resources using the infraProviderResource with different
// infra providers.
TriggerProvision(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
requiredPorts []int,
) (*infraprovider.Infrastructure, error)
) error
// Stop unprovisions those resources which can be stopped without losing the gitspace data.
Stop(
// ResumeProvision stores the provisioned infra details in the db depending on the provisioning type.
ResumeProvision(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig *types.GitspaceConfig,
) (*infraprovider.Infrastructure, error)
gitspaceConfig types.GitspaceConfig,
requiredPorts []int,
provisionedInfra *types.Infrastructure,
) (*types.Infrastructure, error)
// Deprovision removes all the resources created for the gitspace.
Deprovision(
// TriggerStop triggers deprovisioning of those resources which can be stopped without losing the Gitspace data.
TriggerStop(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig *types.GitspaceConfig,
) (*infraprovider.Infrastructure, error)
gitspaceConfig types.GitspaceConfig,
) error
// ResumeStop stores the deprovisioned infra details in the db depending on the provisioning type.
ResumeStop(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra *types.Infrastructure,
) (*types.Infrastructure, error)
// TriggerDeprovision triggers deprovisionign of all the resources created for the Gitspace.
TriggerDeprovision(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig types.GitspaceConfig,
) error
// ResumeDeprovision stores the deprovisioned infra details in the db depending on the provisioning type.
ResumeDeprovision(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra *types.Infrastructure,
) (*types.Infrastructure, error)
// Find finds the provisioned infra resources for the gitspace instance.
Find(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig *types.GitspaceConfig,
) (*infraprovider.Infrastructure, error)
gitspaceConfig types.GitspaceConfig,
) (*types.Infrastructure, error)
}

View File

@ -20,8 +20,8 @@ import (
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/infraprovider"
"github.com/harness/gitness/infraprovider/enum"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
var _ InfraProvisioner = (*infraProvisioner)(nil)
@ -44,31 +44,31 @@ func NewInfraProvisionerService(
}
}
func (i infraProvisioner) Provision(
func (i infraProvisioner) TriggerProvision(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
requiredPorts []int,
) (*infraprovider.Infrastructure, error) {
) error {
infraProviderEntity, err := i.getConfigFromResource(ctx, infraProviderResource)
if err != nil {
return nil, err
return err
}
infraProvider, err := i.getInfraProvider(infraProviderEntity)
infraProvider, err := i.getInfraProvider(infraProviderEntity.Type)
if err != nil {
return nil, err
return err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive,staticcheck
// TODO: Check if any existing infra is provisioned, its status and create new infraProvisioned record
}
var allParams []infraprovider.Parameter
var allParams []types.InfraProviderParameter
templateParams, err := i.getTemplateParams(infraProvider, infraProviderResource)
if err != nil {
return nil, err
return err
}
allParams = append(allParams, templateParams...)
@ -79,47 +79,44 @@ func (i infraProvisioner) Provision(
err = infraProvider.ValidateParams(allParams)
if err != nil {
return nil, fmt.Errorf("invalid provisioning params %v: %w", infraProviderResource.Metadata, err)
return fmt.Errorf("invalid provisioning params %v: %w", infraProviderResource.Metadata, err)
}
provisionedInfra, err := infraProvider.Provision(
err = infraProvider.Provision(
ctx,
gitspaceConfig.SpaceID,
gitspaceConfig.SpacePath,
gitspaceConfig.Identifier,
requiredPorts,
allParams,
)
if err != nil {
return nil, fmt.Errorf(
"unable to provision infrastructure for gitspaceConfigIdentifier %v: %w",
return fmt.Errorf(
"unable to trigger provision infrastructure for gitspaceConfigIdentifier %v: %w",
gitspaceConfig.Identifier,
err,
)
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive,staticcheck
// TODO: Update the infraProvisioned record
}
return provisionedInfra, nil
return nil
}
func (i infraProvisioner) Stop(
func (i infraProvisioner) TriggerStop(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig *types.GitspaceConfig,
) (*infraprovider.Infrastructure, error) {
gitspaceConfig types.GitspaceConfig,
) error {
infraProviderEntity, err := i.getConfigFromResource(ctx, infraProviderResource)
if err != nil {
return nil, err
return err
}
infraProvider, err := i.getInfraProvider(infraProviderEntity)
infraProvider, err := i.getInfraProvider(infraProviderEntity.Type)
if err != nil {
return nil, err
return err
}
var allParams []infraprovider.Parameter
var allParams []types.InfraProviderParameter
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive
// TODO: Fetch and check existing infraProvisioned record
@ -127,7 +124,7 @@ func (i infraProvisioner) Stop(
} else {
templateParams, err2 := i.getTemplateParams(infraProvider, infraProviderResource)
if err2 != nil {
return nil, err2
return err2
}
allParams = append(allParams, templateParams...)
@ -138,48 +135,46 @@ func (i infraProvisioner) Stop(
err = infraProvider.ValidateParams(allParams)
if err != nil {
return nil, fmt.Errorf("invalid provisioning params %+v: %w", infraProviderResource.Metadata, err)
return fmt.Errorf("invalid provisioning params %+v: %w", infraProviderResource.Metadata, err)
}
var provisionedInfra *infraprovider.Infrastructure
var provisionedInfra *types.Infrastructure
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive
// TODO: Fetch and check existing infraProvisioned record
} else {
provisionedInfra = &infraprovider.Infrastructure{
provisionedInfra = &types.Infrastructure{
SpaceID: gitspaceConfig.SpaceID,
SpacePath: gitspaceConfig.SpacePath,
ResourceKey: gitspaceConfig.Identifier,
ProviderType: infraProviderEntity.Type,
Parameters: allParams,
}
}
stoppedInfra, err := infraProvider.Stop(ctx, provisionedInfra)
err = infraProvider.Stop(ctx, provisionedInfra)
if err != nil {
return nil, fmt.Errorf("unable to stop provisioned infra %+v: %w", provisionedInfra, err)
return fmt.Errorf("unable to trigger stop infra %+v: %w", provisionedInfra, err)
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive,staticcheck
// TODO: Update existing infraProvisioned record
}
return stoppedInfra, err
return nil
}
func (i infraProvisioner) Deprovision(
func (i infraProvisioner) TriggerDeprovision(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
gitspaceConfig *types.GitspaceConfig,
) (*infraprovider.Infrastructure, error) {
gitspaceConfig types.GitspaceConfig,
) error {
infraProviderEntity, err := i.getConfigFromResource(ctx, infraProviderResource)
if err != nil {
return nil, err
return err
}
infraProvider, err := i.getInfraProvider(infraProviderEntity)
infraProvider, err := i.getInfraProvider(infraProviderEntity.Type)
if err != nil {
return nil, err
return err
}
var allParams []infraprovider.Parameter
var allParams []types.InfraProviderParameter
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive
// TODO: Fetch and check existing infraProvisioned record
@ -187,7 +182,7 @@ func (i infraProvisioner) Deprovision(
} else {
templateParams, err2 := i.getTemplateParams(infraProvider, infraProviderResource)
if err2 != nil {
return nil, err2
return err2
}
allParams = append(allParams, templateParams...)
@ -198,51 +193,48 @@ func (i infraProvisioner) Deprovision(
err = infraProvider.ValidateParams(allParams)
if err != nil {
return nil, fmt.Errorf("invalid provisioning params %+v: %w", infraProviderResource.Metadata, err)
return fmt.Errorf("invalid provisioning params %+v: %w", infraProviderResource.Metadata, err)
}
var provisionedInfra *infraprovider.Infrastructure
var provisionedInfra *types.Infrastructure
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive
// TODO: Fetch and check existing infraProvisioned record
} else {
provisionedInfra, err = infraProvider.Find(ctx, gitspaceConfig.SpacePath, gitspaceConfig.Identifier, allParams)
provisionedInfra, err = infraProvider.Find(
ctx, gitspaceConfig.SpaceID, gitspaceConfig.SpacePath, gitspaceConfig.Identifier, allParams)
if err != nil {
return nil, fmt.Errorf("unable to find provisioned infra for gitspace %s: %w",
return fmt.Errorf("unable to find provisioned infra for gitspace %s: %w",
gitspaceConfig.Identifier, err)
}
}
destroyedInfra, err := infraProvider.Deprovision(ctx, provisionedInfra)
err = infraProvider.Deprovision(ctx, provisionedInfra)
if err != nil {
return nil, fmt.Errorf("unable to stop provisioned infra %+v: %w", provisionedInfra, err)
return fmt.Errorf("unable to trigger deprovision infra %+v: %w", provisionedInfra, err)
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive,staticcheck
// TODO: Update existing infraProvisioned record
}
return destroyedInfra, err
return err
}
func (i infraProvisioner) Find(
ctx context.Context,
infraProviderResource *types.InfraProviderResource,
_ *types.GitspaceConfig,
) (*infraprovider.Infrastructure, error) {
_ types.GitspaceConfig,
) (*types.Infrastructure, error) {
infraProviderEntity, err := i.getConfigFromResource(ctx, infraProviderResource)
if err != nil {
return nil, err
}
infraProvider, err := i.getInfraProvider(infraProviderEntity)
infraProvider, err := i.getInfraProvider(infraProviderEntity.Type)
if err != nil {
return nil, err
}
var infra infraprovider.Infrastructure
var infra types.Infrastructure
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive
// TODO: Fetch existing infraProvisioned record and map to &infraprovider.Infrastructure
} else {
var allParams []infraprovider.Parameter
var allParams []types.InfraProviderParameter
templateParams, err2 := i.getTemplateParams(infraProvider, infraProviderResource)
if err2 != nil {
@ -254,7 +246,7 @@ func (i infraProvisioner) Find(
allParams = append(allParams, params...)
infra = infraprovider.Infrastructure{
infra = types.Infrastructure{
ProviderType: infraProviderEntity.Type,
Parameters: allParams,
Status: enum.InfraStatusProvisioned,
@ -277,11 +269,11 @@ func (i infraProvisioner) getConfigFromResource(
}
func (i infraProvisioner) getInfraProvider(
infraProviderEntity *types.InfraProviderConfig,
infraProviderType enum.InfraProviderType,
) (infraprovider.InfraProvider, error) {
infraProvider, err := i.providerFactory.GetInfraProvider(infraProviderEntity.Type)
infraProvider, err := i.providerFactory.GetInfraProvider(infraProviderType)
if err != nil {
return nil, fmt.Errorf("unable to get infra provider of type %v: %w", infraProviderEntity.Type, err)
return nil, fmt.Errorf("unable to get infra provider of type %v: %w", infraProviderType, err)
}
return infraProvider, nil
}
@ -289,7 +281,7 @@ func (i infraProvisioner) getInfraProvider(
func (i infraProvisioner) getTemplateParams(
infraProvider infraprovider.InfraProvider,
_ *types.InfraProviderResource,
) ([]infraprovider.Parameter, error) { //nolint:unparam
) ([]types.InfraProviderParameter, error) { //nolint:unparam
templateParams := infraProvider.TemplateParams()
if len(templateParams) > 0 { //nolint:revive,staticcheck
// TODO: Fetch templates and convert into []Parameters
@ -299,14 +291,14 @@ func (i infraProvisioner) getTemplateParams(
func (i infraProvisioner) paramsFromResource(
infraProviderResource *types.InfraProviderResource,
) []infraprovider.Parameter {
params := make([]infraprovider.Parameter, len(infraProviderResource.Metadata))
) []types.InfraProviderParameter {
params := make([]types.InfraProviderParameter, len(infraProviderResource.Metadata))
counter := 0
for key, value := range infraProviderResource.Metadata {
if key == "" || value == "" {
continue
}
params[counter] = infraprovider.Parameter{
params[counter] = types.InfraProviderParameter{
Name: key,
Value: value,
}
@ -314,3 +306,58 @@ func (i infraProvisioner) paramsFromResource(
}
return params
}
func (i infraProvisioner) ResumeProvision(
_ context.Context,
_ *types.InfraProviderResource,
_ types.GitspaceConfig,
_ []int,
provisionedInfra *types.Infrastructure,
) (*types.Infrastructure, error) {
infraProvider, err := i.getInfraProvider(provisionedInfra.ProviderType)
if err != nil {
return nil, err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive,staticcheck
// TODO: Update the infraProvisioned record
}
return provisionedInfra, nil
}
func (i infraProvisioner) ResumeStop(
_ context.Context,
_ *types.InfraProviderResource,
_ types.GitspaceConfig,
stoppedInfra *types.Infrastructure,
) (*types.Infrastructure, error) {
infraProvider, err := i.getInfraProvider(stoppedInfra.ProviderType)
if err != nil {
return nil, err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive,staticcheck
// TODO: Update existing infraProvisioned record
}
return stoppedInfra, err
}
func (i infraProvisioner) ResumeDeprovision(
_ context.Context,
_ *types.InfraProviderResource,
_ types.GitspaceConfig,
deprovisionedInfra *types.Infrastructure,
) (*types.Infrastructure, error) {
infraProvider, err := i.getInfraProvider(deprovisionedInfra.ProviderType)
if err != nil {
return nil, err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { //nolint:revive,staticcheck
// TODO: Update existing infraProvisioned record
}
return deprovisionedInfra, err
}

View File

@ -19,7 +19,6 @@ import (
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
"github.com/harness/gitness/app/gitspace/scm"
"github.com/harness/gitness/infraprovider"
"github.com/harness/gitness/types"
)
@ -29,19 +28,19 @@ type Orchestrator interface {
// It returns the container ID, name and ports used.
CreateAndStartGitspace(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
infra *infraprovider.Infrastructure,
gitspaceConfig types.GitspaceConfig,
infra *types.Infrastructure,
resolvedDetails *scm.ResolvedDetails,
defaultBaseImage string,
ideService ide.IDE,
) (*StartResponse, error)
// StopGitspace stops the gitspace container.
StopGitspace(ctx context.Context, config *types.GitspaceConfig, infra *infraprovider.Infrastructure) error
StopGitspace(ctx context.Context, config types.GitspaceConfig, infra *types.Infrastructure) error
// StopAndRemoveGitspace stops and removes the gitspace container.
StopAndRemoveGitspace(ctx context.Context, config *types.GitspaceConfig, infra *infraprovider.Infrastructure) error
StopAndRemoveGitspace(ctx context.Context, config types.GitspaceConfig, infra *types.Infrastructure) error
// Status checks if the infra is reachable and ready to orchestrate containers.
Status(ctx context.Context, infra *infraprovider.Infrastructure) error
Status(ctx context.Context, infra *types.Infrastructure) error
}

View File

@ -73,8 +73,8 @@ func NewEmbeddedDockerOrchestrator(
// It returns an error if the container is not running, exited or removed.
func (e *EmbeddedDockerOrchestrator) CreateAndStartGitspace(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
infra *infraprovider.Infrastructure,
gitspaceConfig types.GitspaceConfig,
infra *types.Infrastructure,
resolvedRepoDetails *scm.ResolvedDetails,
defaultBaseImage string,
ideService ide.IDE,
@ -202,7 +202,7 @@ func (e *EmbeddedDockerOrchestrator) getWorkingDir(repoName string) string {
func (e *EmbeddedDockerOrchestrator) startGitspace(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
containerName string,
dockerClient *client.Client,
ideService ide.IDE,
@ -210,7 +210,7 @@ func (e *EmbeddedDockerOrchestrator) startGitspace(
volumeName string,
workingDirectory string,
resolvedRepoDetails *scm.ResolvedDetails,
portMappings map[int]*infraprovider.PortMapping,
portMappings map[int]*types.PortMapping,
defaultBaseImage string,
) error {
var imageName = resolvedRepoDetails.DevcontainerConfig.Image
@ -357,7 +357,7 @@ func (e *EmbeddedDockerOrchestrator) getContainerInfo(
ctx context.Context,
containerName string,
dockerClient *client.Client,
portMappings map[int]*infraprovider.PortMapping,
portMappings map[int]*types.PortMapping,
) (string, map[int]string, error) {
inspectResp, err := dockerClient.ContainerInspect(ctx, containerName)
if err != nil {
@ -592,7 +592,7 @@ func (e *EmbeddedDockerOrchestrator) createContainer(
logStreamInstance *logutil.LogStreamInstance,
volumeName string,
workingDirectory string,
portMappings map[int]*infraprovider.PortMapping,
portMappings map[int]*types.PortMapping,
) error {
exposedPorts := nat.PortSet{}
portBindings := nat.PortMap{}
@ -707,8 +707,8 @@ func (e *EmbeddedDockerOrchestrator) pullImage(
// StopGitspace stops a container. If it is removed, it returns an error.
func (e EmbeddedDockerOrchestrator) StopGitspace(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
infra *infraprovider.Infrastructure,
gitspaceConfig types.GitspaceConfig,
infra *types.Infrastructure,
) error {
containerName := getGitspaceContainerName(gitspaceConfig)
@ -797,12 +797,12 @@ func (e EmbeddedDockerOrchestrator) stopContainer(
return nil
}
func getGitspaceContainerName(config *types.GitspaceConfig) string {
func getGitspaceContainerName(config types.GitspaceConfig) string {
return "gitspace-" + config.UserID + "-" + config.Identifier
}
// Status is NOOP for EmbeddedDockerOrchestrator as the docker host is verified by the infra provisioner.
func (e *EmbeddedDockerOrchestrator) Status(_ context.Context, _ *infraprovider.Infrastructure) error {
func (e *EmbeddedDockerOrchestrator) Status(_ context.Context, _ *types.Infrastructure) error {
return nil
}
@ -830,8 +830,8 @@ func (e *EmbeddedDockerOrchestrator) containerState(
// If the container is already removed, it returns.
func (e *EmbeddedDockerOrchestrator) StopAndRemoveGitspace(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
infra *infraprovider.Infrastructure,
gitspaceConfig types.GitspaceConfig,
infra *types.Infrastructure,
) error {
containerName := getGitspaceContainerName(gitspaceConfig)

View File

@ -18,19 +18,39 @@ import (
"context"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
type Orchestrator interface {
// StartGitspace is responsible for all the operations necessary to create the Gitspace container. It fetches the
// devcontainer.json from the code repo, provisions infra using the infra provisioner and setting up the Gitspace
// through the container orchestrator.
StartGitspace(ctx context.Context, gitspaceConfig *types.GitspaceConfig) error
// TriggerStartGitspace fetches the infra resources configured for the gitspace and triggers the infra provisioning.
TriggerStartGitspace(ctx context.Context, gitspaceConfig types.GitspaceConfig) (enum.GitspaceInstanceStateType, error)
// StopGitspace is responsible for stopping a running Gitspace. It stops the Gitspace container and unprovisions
// ResumeStartGitspace saves the provisioned infra, resolves the code repo details & creates the Gitspace container.
ResumeStartGitspace(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
provisionedInfra *types.Infrastructure,
) (types.GitspaceInstance, error)
// TriggerStopGitspace stops the Gitspace container and triggers infra deprovisioning to deprovision
// all the infra resources which are not required to restart the Gitspace.
StopGitspace(ctx context.Context, gitspaceConfig *types.GitspaceConfig) error
TriggerStopGitspace(ctx context.Context, gitspaceConfig types.GitspaceConfig) (enum.GitspaceInstanceStateType, error)
// DeleteGitspace is responsible for deleting a Gitspace. It stops the Gitspace container and unprovisions
// ResumeStopGitspace saves the deprovisioned infra details.
ResumeStopGitspace(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
stoppedInfra *types.Infrastructure,
) (enum.GitspaceInstanceStateType, error)
// TriggerDeleteGitspace removes the Gitspace container and triggers infra deprovisioning to deprovision
// all the infra resources.
DeleteGitspace(ctx context.Context, gitspaceConfig *types.GitspaceConfig) (*types.GitspaceInstance, error)
TriggerDeleteGitspace(ctx context.Context, gitspaceConfig types.GitspaceConfig) (enum.GitspaceInstanceStateType, error)
// ResumeDeleteGitspace saves the deprovisioned infra details.
ResumeDeleteGitspace(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra *types.Infrastructure,
) (enum.GitspaceInstanceStateType, error)
}

View File

@ -28,7 +28,6 @@ import (
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
"github.com/harness/gitness/app/gitspace/scm"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/infraprovider"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
@ -74,166 +73,80 @@ func NewOrchestrator(
}
}
func (o orchestrator) StartGitspace(
func (o orchestrator) TriggerStartGitspace(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
) error {
gitspaceInstance := gitspaceConfig.GitspaceInstance
gitspaceInstance.State = enum.GitspaceInstanceStateError
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerStart)
scmResolvedDetails, err := o.scm.GetSCMRepoDetails(ctx, gitspaceConfig)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerFailed)
return fmt.Errorf("failed to fetch code repo details for gitspace config ID %w %d", err, gitspaceConfig.ID)
}
devcontainerConfig := scmResolvedDetails.DevcontainerConfig
repoName := scmResolvedDetails.RepoName
if devcontainerConfig == nil {
log.Warn().Err(err).Msg("devcontainer config is nil, using empty config")
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerCompleted)
gitspaceConfig types.GitspaceConfig,
) (enum.GitspaceInstanceStateType, error) {
instanceState := enum.GitspaceInstanceStateError
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
if err != nil {
return fmt.Errorf("cannot get the infraprovider resource for ID %d: %w",
return instanceState, fmt.Errorf("cannot get the infraprovider resource for ID %d: %w",
gitspaceConfig.InfraProviderResourceID, err)
}
ideSvc, err := o.getIDEService(gitspaceConfig)
if err != nil {
return err
return instanceState, err
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningStart)
idePort := ideSvc.Port()
infra, err := o.infraProvisioner.Provision(ctx, infraProviderResource, gitspaceConfig, []int{idePort})
err = o.infraProvisioner.TriggerProvision(ctx, infraProviderResource, gitspaceConfig, []int{idePort})
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
return fmt.Errorf(
"cannot provision infrastructure for ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
return instanceState, fmt.Errorf(
"cannot trigger provision infrastructure for ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningCompleted)
instanceState = enum.GitspaceInstanceStateStarting
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectStart)
err = o.containerOrchestrator.Status(ctx, infra)
gitspaceInstance.State = enum.GitspaceInstanceStateError
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectFailed)
return fmt.Errorf("couldn't call the agent health API: %w", err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectCompleted)
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationStart)
startResponse, err := o.containerOrchestrator.CreateAndStartGitspace(
ctx, gitspaceConfig, infra, scmResolvedDetails, o.config.DefaultBaseImage, ideSvc)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationFailed)
return fmt.Errorf("couldn't call the agent start API: %w", err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationCompleted)
var ideURL url.URL
var forwardedPort string
if infra.PortMappings[idePort].PublishedPort == 0 {
forwardedPort = startResponse.PublishedPorts[idePort]
} else {
forwardedPort = strconv.Itoa(infra.PortMappings[idePort].ForwardedPort)
}
if gitspaceConfig.IDE == enum.IDETypeVSCodeWeb {
ideURL = url.URL{
Scheme: "http",
Host: infra.Host + ":" + forwardedPort,
RawQuery: filepath.Join("folder=", repoName),
}
} else if gitspaceConfig.IDE == enum.IDETypeVSCode {
// TODO: the following userID is hard coded and should be changed.
userID := "harness"
ideURL = url.URL{
Scheme: "vscode-remote",
Host: "", // Empty since we include the host and port in the path
Path: fmt.Sprintf(
"ssh-remote+%s@%s:%s",
userID,
infra.Host,
filepath.Join(forwardedPort, repoName),
),
}
}
ideURLString := ideURL.String()
gitspaceInstance.URL = &ideURLString
gitspaceInstance.LastUsed = time.Now().UnixMilli()
gitspaceInstance.State = enum.GitspaceInstanceStateRunning
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStartCompleted)
return nil
return instanceState, nil
}
func (o orchestrator) StopGitspace(
func (o orchestrator) TriggerStopGitspace(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
) error {
gitspaceInstance := gitspaceConfig.GitspaceInstance
gitspaceInstance.State = enum.GitspaceInstanceStateError
gitspaceConfig types.GitspaceConfig,
) (enum.GitspaceInstanceStateType, error) {
instanceState := enum.GitspaceInstanceStateError
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
if err != nil {
return fmt.Errorf(
return instanceState, fmt.Errorf(
"cannot get the infraProviderResource with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
infra, err := o.infraProvisioner.Find(ctx, infraProviderResource, gitspaceConfig)
if err != nil {
return fmt.Errorf("cannot find the provisioned infra: %w", err)
return instanceState, fmt.Errorf("cannot find the provisioned infra: %w", err)
}
err = o.stopGitspaceContainer(ctx, gitspaceConfig, infra)
if err != nil {
return err
return instanceState, err
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopStart)
_, err = o.infraProvisioner.Stop(ctx, infraProviderResource, gitspaceConfig)
err = o.infraProvisioner.TriggerStop(ctx, infraProviderResource, gitspaceConfig)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
return fmt.Errorf(
"cannot stop provisioned infrastructure with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
return instanceState, fmt.Errorf(
"cannot trigger stop infrastructure with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopCompleted)
instanceState = enum.GitspaceInstanceStateStopping
gitspaceInstance.State = enum.GitspaceInstanceStateDeleted
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStopCompleted)
return err
return instanceState, nil
}
func (o orchestrator) stopGitspaceContainer(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
infra *infraprovider.Infrastructure,
gitspaceConfig types.GitspaceConfig,
infra *types.Infrastructure,
) error {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectStart)
@ -261,8 +174,8 @@ func (o orchestrator) stopGitspaceContainer(
func (o orchestrator) stopAndRemoveGitspaceContainer(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
infra *infraprovider.Infrastructure,
gitspaceConfig types.GitspaceConfig,
infra *types.Infrastructure,
) error {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectStart)
@ -288,51 +201,45 @@ func (o orchestrator) stopAndRemoveGitspaceContainer(
return nil
}
func (o orchestrator) DeleteGitspace(
func (o orchestrator) TriggerDeleteGitspace(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
) (*types.GitspaceInstance, error) {
gitspaceInstance := gitspaceConfig.GitspaceInstance
gitspaceInstance.State = enum.GitspaceInstanceStateError
gitspaceConfig types.GitspaceConfig,
) (enum.GitspaceInstanceStateType, error) {
instanceState := enum.GitspaceInstanceStateError
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
if err != nil {
return nil, fmt.Errorf(
return instanceState, fmt.Errorf(
"cannot get the infraProviderResource with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
infra, err := o.infraProvisioner.Find(ctx, infraProviderResource, gitspaceConfig)
if err != nil {
return nil, fmt.Errorf("cannot find the provisioned infra: %w", err)
return instanceState, fmt.Errorf("cannot find the provisioned infra: %w", err)
}
err = o.stopAndRemoveGitspaceContainer(ctx, gitspaceConfig, infra)
if err != nil {
return nil, err
return instanceState, err
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningStart)
_, err = o.infraProvisioner.Deprovision(ctx, infraProviderResource, gitspaceConfig)
err = o.infraProvisioner.TriggerDeprovision(ctx, infraProviderResource, gitspaceConfig)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningFailed)
return nil, fmt.Errorf(
"cannot deprovision infrastructure with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
return instanceState, fmt.Errorf(
"cannot trigger deprovision infrastructure with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
instanceState = enum.GitspaceInstanceStateStopping
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningCompleted)
gitspaceInstance.State = enum.GitspaceInstanceStateDeleted
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStopCompleted)
return gitspaceInstance, nil
return instanceState, nil
}
func (o orchestrator) emitGitspaceEvent(
ctx context.Context,
config *types.GitspaceConfig,
config types.GitspaceConfig,
eventType enum.GitspaceEventType,
) {
o.eventReporter.EmitGitspaceEvent(
@ -347,7 +254,7 @@ func (o orchestrator) emitGitspaceEvent(
})
}
func (o orchestrator) getIDEService(gitspaceConfig *types.GitspaceConfig) (ide.IDE, error) {
func (o orchestrator) getIDEService(gitspaceConfig types.GitspaceConfig) (ide.IDE, error) {
var ideService ide.IDE
switch gitspaceConfig.IDE {
@ -361,3 +268,180 @@ func (o orchestrator) getIDEService(gitspaceConfig *types.GitspaceConfig) (ide.I
return ideService, nil
}
func (o orchestrator) ResumeStartGitspace(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
provisionedInfra *types.Infrastructure,
) (types.GitspaceInstance, error) {
gitspaceInstance := *gitspaceConfig.GitspaceInstance
gitspaceInstance.State = enum.GitspaceInstanceStateError
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
if err != nil {
return gitspaceInstance, fmt.Errorf("cannot get the infraprovider resource for ID %d: %w",
gitspaceConfig.InfraProviderResourceID, err)
}
ideSvc, err := o.getIDEService(gitspaceConfig)
if err != nil {
return gitspaceInstance, err
}
idePort := ideSvc.Port()
provisionedInfra, err = o.infraProvisioner.ResumeProvision(
ctx, infraProviderResource, gitspaceConfig, []int{idePort}, provisionedInfra)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
return gitspaceInstance, fmt.Errorf(
"cannot provision infrastructure for ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningCompleted)
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerStart)
scmResolvedDetails, err := o.scm.GetSCMRepoDetails(ctx, gitspaceConfig)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerFailed)
return gitspaceInstance, fmt.Errorf(
"failed to fetch code repo details for gitspace config ID %w %d", err, gitspaceConfig.ID)
}
devcontainerConfig := scmResolvedDetails.DevcontainerConfig
repoName := scmResolvedDetails.RepoName
if devcontainerConfig == nil {
log.Warn().Err(err).Msg("devcontainer config is nil, using empty config")
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerCompleted)
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectStart)
err = o.containerOrchestrator.Status(ctx, provisionedInfra)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectFailed)
return gitspaceInstance, fmt.Errorf("couldn't call the agent health API: %w", err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectCompleted)
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationStart)
startResponse, err := o.containerOrchestrator.CreateAndStartGitspace(
ctx, gitspaceConfig, provisionedInfra, scmResolvedDetails, o.config.DefaultBaseImage, ideSvc)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationFailed)
return gitspaceInstance, fmt.Errorf("couldn't call the agent start API: %w", err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationCompleted)
var ideURL url.URL
var forwardedPort string
if provisionedInfra.PortMappings[idePort].PublishedPort == 0 {
forwardedPort = startResponse.PublishedPorts[idePort]
} else {
forwardedPort = strconv.Itoa(provisionedInfra.PortMappings[idePort].ForwardedPort)
}
host := provisionedInfra.Host
if provisionedInfra.ProxyHost != "" {
host = provisionedInfra.ProxyHost
}
if gitspaceConfig.IDE == enum.IDETypeVSCodeWeb {
ideURL = url.URL{
Scheme: "http",
Host: host + ":" + forwardedPort,
RawQuery: filepath.Join("folder=", repoName),
}
} else if gitspaceConfig.IDE == enum.IDETypeVSCode {
// TODO: the following userID is hard coded and should be changed.
userID := "harness"
ideURL = url.URL{
Scheme: "vscode-remote",
Host: "", // Empty since we include the host and port in the path
Path: fmt.Sprintf(
"ssh-remote+%s@%s:%s",
userID,
host,
filepath.Join(forwardedPort, repoName),
),
}
}
ideURLString := ideURL.String()
gitspaceInstance.URL = &ideURLString
gitspaceInstance.LastUsed = time.Now().UnixMilli()
gitspaceInstance.State = enum.GitspaceInstanceStateRunning
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStartCompleted)
return gitspaceInstance, nil
}
func (o orchestrator) ResumeStopGitspace(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
stoppedInfra *types.Infrastructure,
) (enum.GitspaceInstanceStateType, error) {
instanceState := enum.GitspaceInstanceStateError
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
if err != nil {
return instanceState, fmt.Errorf(
"cannot get the infraProviderResource with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
_, err = o.infraProvisioner.ResumeStop(ctx, infraProviderResource, gitspaceConfig, stoppedInfra)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
return instanceState, fmt.Errorf(
"cannot stop provisioned infrastructure with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopCompleted)
instanceState = enum.GitspaceInstanceStateDeleted
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStopCompleted)
return instanceState, nil
}
func (o orchestrator) ResumeDeleteGitspace(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra *types.Infrastructure,
) (enum.GitspaceInstanceStateType, error) {
instanceState := enum.GitspaceInstanceStateError
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
if err != nil {
return instanceState, fmt.Errorf(
"cannot get the infraProviderResource with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
_, err = o.infraProvisioner.ResumeDeprovision(ctx, infraProviderResource, gitspaceConfig, deprovisionedInfra)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningFailed)
return instanceState, fmt.Errorf(
"cannot deprovision infrastructure with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningCompleted)
instanceState = enum.GitspaceInstanceStateDeleted
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStopCompleted)
return instanceState, nil
}

View File

@ -62,7 +62,7 @@ func NewGitnessSCM(repoStore store.RepoStore, git git.Interface,
func (s GitnessSCM) ResolveCredentials(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
) (*ResolvedCredentials, error) {
repoURL, err := url.Parse(gitspaceConfig.CodeRepoURL)
if err != nil {
@ -116,7 +116,7 @@ func (s GitnessSCM) ResolveCredentials(
}
func (s GitnessSCM) GetFileContent(ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
filePath string,
) ([]byte, error) {
repo, err := s.repoStore.FindByRef(ctx, *gitspaceConfig.CodeRepoRef)

View File

@ -39,7 +39,7 @@ func NewGenericSCM() *GenericSCM {
}
func (s GenericSCM) GetFileContent(ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
filePath string,
) ([]byte, error) {
gitWorkingDirectory := "/tmp/git/"
@ -102,7 +102,7 @@ func (s GenericSCM) GetFileContent(ctx context.Context,
func (s GenericSCM) ResolveCredentials(
_ context.Context,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
) (*ResolvedCredentials, error) {
var resolvedCredentials = &ResolvedCredentials{
Branch: gitspaceConfig.Branch,

View File

@ -41,7 +41,7 @@ type SCM interface {
// GetSCMRepoDetails fetches repository name, credentials & devcontainer config file from the given repo and branch.
GetSCMRepoDetails(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
) (*ResolvedDetails, error)
// CheckValidCodeRepo checks if the current URL is a valid and accessible code repo,
@ -86,7 +86,7 @@ func (s scm) CheckValidCodeRepo(
func (s scm) GetSCMRepoDetails(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
) (*ResolvedDetails, error) {
filePath := devcontainerDefaultPath
if gitspaceConfig.CodeRepoType == "" {

View File

@ -23,10 +23,10 @@ import (
)
type Provider interface {
ResolveCredentials(ctx context.Context, gitspaceConfig *types.GitspaceConfig) (*ResolvedCredentials, error)
ResolveCredentials(ctx context.Context, gitspaceConfig types.GitspaceConfig) (*ResolvedCredentials, error)
GetFileContent(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
gitspaceConfig types.GitspaceConfig,
filePath string,
) ([]byte, error)
}

View File

@ -0,0 +1,68 @@
// 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 gitspace
import (
"context"
"fmt"
"github.com/harness/gitness/store/database/dbtx"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
const resourceNotFoundErr = "Failed to find gitspace: resource not found"
func (c *Service) Find(
ctx context.Context,
spaceID int64,
spacePath string,
identifier string,
) (*types.GitspaceConfig, error) {
var gitspaceConfigResult *types.GitspaceConfig
txErr := c.tx.WithTx(ctx, func(ctx context.Context) error {
gitspaceConfig, err := c.gitspaceConfigStore.FindByIdentifier(ctx, spaceID, identifier)
if err != nil {
return fmt.Errorf("failed to find gitspace config: %w", err)
}
infraProviderResource, err := c.infraProviderSvc.FindResource(ctx, gitspaceConfig.InfraProviderResourceID)
if err != nil {
return fmt.Errorf("failed to find infra provider resource for gitspace config: %w", err)
}
gitspaceConfig.SpacePath = spacePath
gitspaceConfig.InfraProviderResourceIdentifier = infraProviderResource.Identifier
instance, err := c.gitspaceInstanceStore.FindLatestByGitspaceConfigID(ctx, gitspaceConfig.ID, gitspaceConfig.SpaceID)
if err != nil && err.Error() != resourceNotFoundErr { // TODO fix this
return fmt.Errorf("failed to find gitspace instance for config ID : %s %w", gitspaceConfig.Identifier, err)
}
if instance != nil {
gitspaceConfig.GitspaceInstance = instance
instance.SpacePath = gitspaceConfig.SpacePath
gitspaceStateType, err := enum.GetGitspaceStateFromInstance(instance.State)
if err != nil {
return err
}
gitspaceConfig.State = gitspaceStateType
} else {
gitspaceConfig.State = enum.GitspaceStateUninitialized
}
gitspaceConfigResult = gitspaceConfig
return nil
}, dbtx.TxDefaultReadOnly)
if txErr != nil {
return nil, txErr
}
return gitspaceConfigResult, nil
}

View File

@ -18,6 +18,7 @@ import (
"context"
"fmt"
"github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/store/database/dbtx"
"github.com/harness/gitness/types"
@ -29,12 +30,14 @@ func NewService(
gitspaceStore store.GitspaceConfigStore,
gitspaceInstanceStore store.GitspaceInstanceStore,
spaceStore store.SpaceStore,
infraProviderSvc *infraprovider.Service,
) *Service {
return &Service{
tx: tx,
gitspaceConfigStore: gitspaceStore,
gitspaceInstanceStore: gitspaceInstanceStore,
spaceStore: spaceStore,
infraProviderSvc: infraProviderSvc,
}
}
@ -43,6 +46,7 @@ type Service struct {
gitspaceInstanceStore store.GitspaceInstanceStore
spaceStore store.SpaceStore
tx dbtx.Transactor
infraProviderSvc *infraprovider.Service
}
func (c *Service) ListGitspacesForSpace(

View File

@ -0,0 +1,33 @@
// 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 gitspace
import (
"context"
"fmt"
"github.com/harness/gitness/types"
)
func (c *Service) UpdateConfig(
ctx context.Context,
gitspaceConfig *types.GitspaceConfig,
) error {
err := c.gitspaceConfigStore.Update(ctx, gitspaceConfig)
if err != nil {
return fmt.Errorf("failed to update gitspace config: %w", err)
}
return nil
}

View File

@ -0,0 +1,33 @@
// 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 gitspace
import (
"context"
"fmt"
"github.com/harness/gitness/types"
)
func (c *Service) UpdateInstance(
ctx context.Context,
gitspaceInstance *types.GitspaceInstance,
) error {
err := c.gitspaceInstanceStore.Update(ctx, gitspaceInstance)
if err != nil {
return fmt.Errorf("failed to update gitspace instance: %w", err)
}
return nil
}

View File

@ -15,6 +15,7 @@
package gitspace
import (
"github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/store/database/dbtx"
@ -30,6 +31,7 @@ func ProvideGitspace(
gitspaceStore store.GitspaceConfigStore,
gitspaceInstanceStore store.GitspaceInstanceStore,
spaceStore store.SpaceStore,
infraProviderSvc *infraprovider.Service,
) *Service {
return NewService(tx, gitspaceStore, gitspaceInstanceStore, spaceStore)
return NewService(tx, gitspaceStore, gitspaceInstanceStore, spaceStore, infraProviderSvc)
}

View File

@ -51,13 +51,13 @@ func (c *Config) Sanitize() error {
}
type Service struct {
config Config
config *Config
gitspaceEventStore store.GitspaceEventStore
}
func NewService(
ctx context.Context,
config Config,
config *Config,
gitspaceEventReaderFactory *events.ReaderFactory[*gitspaceevents.Reader],
gitspaceEventStore store.GitspaceEventStore,
) (*Service, error) {

View File

@ -30,7 +30,7 @@ var WireSet = wire.NewSet(
)
func ProvideService(ctx context.Context,
config Config,
config *Config,
gitspaceEventReaderFactory *events.ReaderFactory[*gitspaceevents.Reader],
gitspaceEventStore store.GitspaceEventStore,
) (*Service, error) {

View File

@ -0,0 +1,114 @@
// 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 gitspaceinfraevent
import (
"context"
"fmt"
"time"
gitspaceEvents "github.com/harness/gitness/app/events/gitspace"
gitspaceInfraEvents "github.com/harness/gitness/app/events/gitspaceinfra"
"github.com/harness/gitness/events"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
func (s *Service) handleGitspaceInfraEvent(
ctx context.Context,
event *events.Event[*gitspaceInfraEvents.GitspaceInfraEventPayload],
) error {
payload := event.Payload
config, fetchErr := s.getConfig(ctx, payload.Infra.SpaceID, payload.Infra.SpacePath, payload.Infra.ResourceKey)
if fetchErr != nil {
return fetchErr
}
var instance = config.GitspaceInstance
var err error
switch payload.Type {
case enum.InfraEventProvision:
updatedInstance, err := s.orchestrator.ResumeStartGitspace(ctx, *config, payload.Infra)
if err != nil {
s.emitGitspaceConfigEvent(ctx, config, enum.GitspaceEventTypeGitspaceActionStartFailed)
return fmt.Errorf("failed to resume start gitspace: %w", err)
}
instance = &updatedInstance
case enum.InfraEventStop:
instanceState, err := s.orchestrator.ResumeStopGitspace(ctx, *config, payload.Infra)
if err != nil {
s.emitGitspaceConfigEvent(ctx, config, enum.GitspaceEventTypeGitspaceActionStopFailed)
return fmt.Errorf("failed to resume stop gitspace: %w", err)
}
instance.State = instanceState
case enum.InfraEventDeprovision:
instanceState, err := s.orchestrator.ResumeDeleteGitspace(ctx, *config, payload.Infra)
if err != nil {
return fmt.Errorf("failed to resume delete gitspace: %w", err)
}
instance.State = instanceState
config.IsDeleted = true
if err = s.gitspaceSvc.UpdateConfig(ctx, config); err != nil {
return fmt.Errorf("failed to delete gitspace config with ID: %s %w", config.Identifier, err)
}
default:
return fmt.Errorf("unknown event type: %s", event.Payload.Type)
}
err = s.gitspaceSvc.UpdateInstance(ctx, instance)
if err != nil {
return fmt.Errorf("failed to update gitspace instance: %w", err)
}
return nil
}
func (s *Service) getConfig(
ctx context.Context,
spaceID int64,
spacePath string,
identifier string,
) (*types.GitspaceConfig, error) {
config, err := s.gitspaceSvc.Find(ctx, spaceID, spacePath, identifier)
if err != nil {
return nil, fmt.Errorf(
"failed to find gitspace config during infra event handling, identifier %s: %w", identifier, err)
}
return config, nil
}
func (s *Service) emitGitspaceConfigEvent(ctx context.Context,
config *types.GitspaceConfig,
eventType enum.GitspaceEventType,
) {
s.eventReporter.EmitGitspaceEvent(ctx, gitspaceEvents.GitspaceEvent, &gitspaceEvents.GitspaceEventPayload{
QueryKey: config.Identifier,
EntityID: config.ID,
EntityType: enum.GitspaceEntityTypeGitspaceConfig,
EventType: eventType,
Timestamp: time.Now().UnixNano(),
})
}

View File

@ -0,0 +1,77 @@
// 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 gitspaceinfraevent
import (
"context"
"fmt"
"time"
gitspaceevents "github.com/harness/gitness/app/events/gitspace"
gitspaceinfraevents "github.com/harness/gitness/app/events/gitspaceinfra"
"github.com/harness/gitness/app/gitspace/orchestrator"
"github.com/harness/gitness/app/services/gitspace"
"github.com/harness/gitness/app/services/gitspaceevent"
"github.com/harness/gitness/events"
"github.com/harness/gitness/stream"
)
const groupGitspaceInfraEvents = "gitness:gitspaceinfra"
type Service struct {
config *gitspaceevent.Config
orchestrator orchestrator.Orchestrator
gitspaceSvc *gitspace.Service
eventReporter *gitspaceevents.Reporter
}
func NewService(
ctx context.Context,
config *gitspaceevent.Config,
gitspaceInfraEventReaderFactory *events.ReaderFactory[*gitspaceinfraevents.Reader],
orchestrator orchestrator.Orchestrator,
gitspaceSvc *gitspace.Service,
eventReporter *gitspaceevents.Reporter,
) (*Service, error) {
if err := config.Sanitize(); err != nil {
return nil, fmt.Errorf("provided gitspace infra event service config is invalid: %w", err)
}
service := &Service{
config: config,
orchestrator: orchestrator,
gitspaceSvc: gitspaceSvc,
eventReporter: eventReporter,
}
_, err := gitspaceInfraEventReaderFactory.Launch(ctx, groupGitspaceInfraEvents, config.EventReaderName,
func(r *gitspaceinfraevents.Reader) error {
const idleTimeout = 1 * time.Minute
r.Configure(
stream.WithConcurrency(config.Concurrency),
stream.WithHandlerOptions(
stream.WithIdleTimeout(idleTimeout),
stream.WithMaxRetries(config.MaxRetries),
))
_ = r.RegisterGitspaceInfraEvent(service.handleGitspaceInfraEvent)
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to launch gitspace infra event reader: %w", err)
}
return service, nil
}

View File

@ -0,0 +1,51 @@
// 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 gitspaceinfraevent
import (
"context"
gitspaceevents "github.com/harness/gitness/app/events/gitspace"
gitspaceinfraevents "github.com/harness/gitness/app/events/gitspaceinfra"
"github.com/harness/gitness/app/gitspace/orchestrator"
"github.com/harness/gitness/app/services/gitspace"
"github.com/harness/gitness/app/services/gitspaceevent"
"github.com/harness/gitness/events"
"github.com/google/wire"
)
// WireSet provides a wire set for this package.
var WireSet = wire.NewSet(
ProvideService,
)
func ProvideService(
ctx context.Context,
config *gitspaceevent.Config,
gitspaceInfraEventReaderFactory *events.ReaderFactory[*gitspaceinfraevents.Reader],
orchestrator orchestrator.Orchestrator,
gitspaceSvc *gitspace.Service,
eventReporter *gitspaceevents.Reporter,
) (*Service, error) {
return NewService(
ctx,
config,
gitspaceInfraEventReaderFactory,
orchestrator,
gitspaceSvc,
eventReporter,
)
}

View File

@ -93,7 +93,7 @@ func (c *Service) CreateInfraProvider(
if len(infraProvider.TemplateParams()) > 0 {
return fmt.Errorf("failed to fetch templates") // TODO Implement
}
parameters := []infraprovider.Parameter{}
parameters := []types.InfraProviderParameter{}
// TODO logic to populate paramteters as per the provider type
err = infraProvider.ValidateParams(parameters)
if err != nil {

View File

@ -18,6 +18,7 @@ import (
"github.com/harness/gitness/app/services/cleanup"
"github.com/harness/gitness/app/services/gitspace"
"github.com/harness/gitness/app/services/gitspaceevent"
"github.com/harness/gitness/app/services/gitspaceinfraevent"
"github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/services/keywordsearch"
"github.com/harness/gitness/app/services/metric"
@ -36,19 +37,20 @@ var WireSet = wire.NewSet(
)
type Services struct {
Webhook *webhook.Service
PullReq *pullreq.Service
Trigger *trigger.Service
JobScheduler *job.Scheduler
MetricCollector *metric.Collector
RepoSizeCalculator *repo.SizeCalculator
Repo *repo.Service
Cleanup *cleanup.Service
Notification *notification.Service
Keywordsearch *keywordsearch.Service
GitspaceEvent *gitspaceevent.Service
infraProvider *infraprovider.Service
gitspace *gitspace.Service
Webhook *webhook.Service
PullReq *pullreq.Service
Trigger *trigger.Service
JobScheduler *job.Scheduler
MetricCollector *metric.Collector
RepoSizeCalculator *repo.SizeCalculator
Repo *repo.Service
Cleanup *cleanup.Service
Notification *notification.Service
Keywordsearch *keywordsearch.Service
GitspaceEvent *gitspaceevent.Service
infraProvider *infraprovider.Service
gitspace *gitspace.Service
gitspaceInfraEventSvc *gitspaceinfraevent.Service
}
func ProvideServices(
@ -65,20 +67,22 @@ func ProvideServices(
gitspaceEventSvc *gitspaceevent.Service,
infraProviderSvc *infraprovider.Service,
gitspaceSvc *gitspace.Service,
gitspaceInfraEventSvc *gitspaceinfraevent.Service,
) Services {
return Services{
Webhook: webhooksSvc,
PullReq: pullReqSvc,
Trigger: triggerSvc,
JobScheduler: jobScheduler,
MetricCollector: metricCollector,
RepoSizeCalculator: repoSizeCalculator,
Repo: repo,
Cleanup: cleanupSvc,
Notification: notificationSvc,
Keywordsearch: keywordsearchSvc,
GitspaceEvent: gitspaceEventSvc,
infraProvider: infraProviderSvc,
gitspace: gitspaceSvc,
Webhook: webhooksSvc,
PullReq: pullReqSvc,
Trigger: triggerSvc,
JobScheduler: jobScheduler,
MetricCollector: metricCollector,
RepoSizeCalculator: repoSizeCalculator,
Repo: repo,
Cleanup: cleanupSvc,
Notification: notificationSvc,
Keywordsearch: keywordsearchSvc,
GitspaceEvent: gitspaceEventSvc,
infraProvider: infraProviderSvc,
gitspace: gitspaceSvc,
gitspaceInfraEventSvc: gitspaceInfraEventSvc,
}
}

View File

@ -18,10 +18,10 @@ import (
"context"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/infraprovider/enum"
"github.com/harness/gitness/store/database"
"github.com/harness/gitness/store/database/dbtx"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/jmoiron/sqlx"
"github.com/pkg/errors"

View File

@ -19,10 +19,10 @@ import (
"encoding/json"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/infraprovider/enum"
"github.com/harness/gitness/store/database"
"github.com/harness/gitness/store/database/dbtx"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/guregu/null"
"github.com/jmoiron/sqlx"

View File

@ -413,8 +413,8 @@ func ProvideGitspaceOrchestratorConfig(config *types.Config) *orchestrator.Confi
}
// ProvideGitspaceEventConfig loads the gitspace event service config from the main config.
func ProvideGitspaceEventConfig(config *types.Config) gitspaceevent.Config {
return gitspaceevent.Config{
func ProvideGitspaceEventConfig(config *types.Config) *gitspaceevent.Config {
return &gitspaceevent.Config{
EventReaderName: config.InstanceID,
Concurrency: config.Gitspace.Events.Concurrency,
MaxRetries: config.Gitspace.Events.MaxRetries,

View File

@ -42,6 +42,7 @@ import (
"github.com/harness/gitness/app/bootstrap"
gitevents "github.com/harness/gitness/app/events/git"
gitspaceevents "github.com/harness/gitness/app/events/gitspace"
gitspaceinfraevents "github.com/harness/gitness/app/events/gitspaceinfra"
pullreqevents "github.com/harness/gitness/app/events/pullreq"
repoevents "github.com/harness/gitness/app/events/repo"
infrastructure "github.com/harness/gitness/app/gitspace/infrastructure"
@ -68,6 +69,7 @@ import (
"github.com/harness/gitness/app/services/exporter"
gitspaceSvc "github.com/harness/gitness/app/services/gitspace"
"github.com/harness/gitness/app/services/gitspaceevent"
gitspaceInfraEventSvc "github.com/harness/gitness/app/services/gitspaceinfraevent"
"github.com/harness/gitness/app/services/importer"
infraproviderSvc "github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/services/keywordsearch"
@ -153,6 +155,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
gitspaceCtrl.WireSet,
infraproviderSvc.WireSet,
gitspaceSvc.WireSet,
gitspaceInfraEventSvc.WireSet,
gitevents.WireSet,
pullreqevents.WireSet,
repoevents.WireSet,
@ -231,6 +234,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
logutil.WireSet,
cliserver.ProvideGitspaceOrchestratorConfig,
ide.WireSet,
gitspaceinfraevents.WireSet,
)
return &cliserver.System{}, nil
}

View File

@ -39,9 +39,10 @@ import (
"github.com/harness/gitness/app/auth/authn"
"github.com/harness/gitness/app/auth/authz"
"github.com/harness/gitness/app/bootstrap"
events4 "github.com/harness/gitness/app/events/git"
events5 "github.com/harness/gitness/app/events/gitspace"
events3 "github.com/harness/gitness/app/events/pullreq"
events5 "github.com/harness/gitness/app/events/git"
events6 "github.com/harness/gitness/app/events/gitspace"
events3 "github.com/harness/gitness/app/events/gitspaceinfra"
events4 "github.com/harness/gitness/app/events/pullreq"
events2 "github.com/harness/gitness/app/events/repo"
"github.com/harness/gitness/app/gitspace/infrastructure"
"github.com/harness/gitness/app/gitspace/logutil"
@ -67,6 +68,7 @@ import (
"github.com/harness/gitness/app/services/exporter"
"github.com/harness/gitness/app/services/gitspace"
"github.com/harness/gitness/app/services/gitspaceevent"
"github.com/harness/gitness/app/services/gitspaceinfraevent"
"github.com/harness/gitness/app/services/importer"
infraprovider2 "github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/services/keywordsearch"
@ -252,7 +254,21 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
}
gitspaceConfigStore := database.ProvideGitspaceConfigStore(db)
gitspaceInstanceStore := database.ProvideGitspaceInstanceStore(db)
gitspaceService := gitspace.ProvideGitspace(transactor, gitspaceConfigStore, gitspaceInstanceStore, spaceStore)
infraProviderResourceStore := database.ProvideInfraProviderResourceStore(db)
infraProviderConfigStore := database.ProvideInfraProviderConfigStore(db)
dockerConfig, err := server.ProvideDockerConfig(config)
if err != nil {
return nil, err
}
dockerClientFactory := infraprovider.ProvideDockerClientFactory(dockerConfig)
eventsReporter, err := events3.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
dockerProvider := infraprovider.ProvideDockerProvider(dockerConfig, dockerClientFactory, eventsReporter)
factory := infraprovider.ProvideFactory(dockerProvider)
infraproviderService := infraprovider2.ProvideInfraProvider(transactor, infraProviderResourceStore, infraProviderConfigStore, 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, gitspaceConfigStore, gitspaceInstanceStore, labelService)
pipelineController := pipeline.ProvideController(repoStore, triggerStore, authorizer, pipelineStore)
secretController := secret.ProvideController(encrypter, secretStore, authorizer, spaceStore)
@ -266,27 +282,27 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
pullReqReviewStore := database.ProvidePullReqReviewStore(db)
pullReqReviewerStore := database.ProvidePullReqReviewerStore(db, principalInfoCache)
pullReqFileViewStore := database.ProvidePullReqFileViewStore(db)
eventsReporter, err := events3.ProvideReporter(eventsSystem)
reporter2, err := events4.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
migrator := codecomments.ProvideMigrator(gitInterface)
readerFactory, err := events4.ProvideReaderFactory(eventsSystem)
readerFactory, err := events5.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
eventsReaderFactory, err := events3.ProvideReaderFactory(eventsSystem)
eventsReaderFactory, err := events4.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
repoGitInfoView := database.ProvideRepoGitInfoView(db)
repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView)
pullreqService, err := pullreq.ProvideService(ctx, config, readerFactory, eventsReaderFactory, eventsReporter, gitInterface, repoGitInfoCache, repoStore, pullReqStore, pullReqActivityStore, codeCommentView, migrator, pullReqFileViewStore, pubSub, provider, streamer)
pullreqService, err := pullreq.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter2, gitInterface, repoGitInfoCache, repoStore, pullReqStore, pullReqActivityStore, codeCommentView, migrator, pullReqFileViewStore, pubSub, provider, streamer)
if err != nil {
return nil, err
}
pullReq := importer.ProvidePullReqImporter(provider, gitInterface, principalStore, repoStore, pullReqStore, pullReqActivityStore, transactor)
pullreqController := pullreq2.ProvideController(transactor, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, principalInfoCache, pullReqFileViewStore, membershipStore, checkStore, gitInterface, eventsReporter, migrator, pullreqService, protectionManager, streamer, codeownersService, lockerLocker, pullReq, labelService)
pullreqController := pullreq2.ProvideController(transactor, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, principalInfoCache, pullReqFileViewStore, membershipStore, checkStore, gitInterface, reporter2, migrator, pullreqService, protectionManager, streamer, codeownersService, lockerLocker, pullReq, labelService)
webhookConfig := server.ProvideWebhookConfig(config)
webhookStore := database.ProvideWebhookStore(db)
webhookExecutionStore := database.ProvideWebhookExecutionStore(db)
@ -295,7 +311,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
return nil, err
}
webhookController := webhook2.ProvideController(webhookConfig, authorizer, webhookStore, webhookExecutionStore, repoStore, webhookService, encrypter)
reporter2, err := events4.ProvideReporter(eventsSystem)
reporter3, err := events5.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
@ -311,7 +327,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
if err != nil {
return nil, err
}
githookController := githook.ProvideController(authorizer, principalStore, repoStore, reporter2, reporter, gitInterface, pullReqStore, provider, protectionManager, clientFactory, resourceLimiter, settingsService, preReceiveExtender, updateExtender, postReceiveExtender)
githookController := githook.ProvideController(authorizer, principalStore, repoStore, reporter3, reporter, gitInterface, pullReqStore, provider, protectionManager, clientFactory, resourceLimiter, settingsService, preReceiveExtender, updateExtender, postReceiveExtender)
serviceaccountController := serviceaccount.NewController(principalUID, authorizer, principalStore, spaceStore, repoStore, tokenStore)
principalController := principal.ProvideController(principalStore, authorizer)
v := check2.ProvideCheckSanitizers()
@ -328,18 +344,8 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
uploadController := upload.ProvideController(authorizer, repoStore, blobStore)
searcher := keywordsearch.ProvideSearcher(localIndexSearcher)
keywordsearchController := keywordsearch2.ProvideController(authorizer, searcher, repoController, spaceController)
infraProviderResourceStore := database.ProvideInfraProviderResourceStore(db)
infraProviderConfigStore := database.ProvideInfraProviderConfigStore(db)
dockerConfig, err := server.ProvideDockerConfig(config)
if err != nil {
return nil, err
}
dockerClientFactory := infraprovider.ProvideDockerClientFactory(dockerConfig)
dockerProvider := infraprovider.ProvideDockerProvider(dockerConfig, dockerClientFactory)
factory := infraprovider.ProvideFactory(dockerProvider)
infraproviderService := infraprovider2.ProvideInfraProvider(transactor, infraProviderResourceStore, infraProviderConfigStore, factory, spaceStore)
infraproviderController := infraprovider3.ProvideController(authorizer, spaceStore, infraproviderService)
reporter3, err := events5.ProvideReporter(eventsSystem)
reporter4, err := events6.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
@ -354,9 +360,9 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
vsCode := ide.ProvideVSCodeService()
vsCodeWebConfig := server.ProvideIDEVSCodeWebConfig(config)
vsCodeWeb := ide.ProvideVSCodeWebService(vsCodeWebConfig)
orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, infraProviderResourceStore, infraProvisioner, containerOrchestrator, reporter3, orchestratorConfig, vsCode, vsCodeWeb)
orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, infraProviderResourceStore, infraProvisioner, containerOrchestrator, reporter4, orchestratorConfig, vsCode, vsCodeWeb)
gitspaceEventStore := database.ProvideGitspaceEventStore(db)
gitspaceController := gitspace2.ProvideController(transactor, authorizer, infraproviderService, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, reporter3, orchestratorOrchestrator, gitspaceEventStore, statefulLogger, scmSCM, repoStore)
gitspaceController := gitspace2.ProvideController(transactor, authorizer, infraproviderService, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, reporter4, orchestratorOrchestrator, gitspaceEventStore, statefulLogger, scmSCM, repoStore, gitspaceService)
migrateController := migrate.ProvideController(authorizer, principalStore)
openapiService := openapi.ProvideOpenAPIService()
routerRouter := router.ProvideRouter(ctx, config, authenticator, repoController, reposettingsController, executionController, logsController, spaceController, pipelineController, secretController, triggerController, connectorController, templateController, pluginController, pullreqController, webhookController, githookController, gitInterface, serviceaccountController, controller, principalController, checkController, systemController, uploadController, keywordsearchController, infraproviderController, gitspaceController, migrateController, provider, openapiService)
@ -410,7 +416,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
return nil, err
}
gitspaceeventConfig := server.ProvideGitspaceEventConfig(config)
readerFactory3, err := events5.ProvideReaderFactory(eventsSystem)
readerFactory3, err := events6.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
@ -418,7 +424,15 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
if err != nil {
return nil, err
}
servicesServices := services.ProvideServices(webhookService, pullreqService, triggerService, jobScheduler, collector, sizeCalculator, repoService, cleanupService, notificationService, keywordsearchService, gitspaceeventService, infraproviderService, gitspaceService)
readerFactory4, err := events3.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
gitspaceinfraeventService, err := gitspaceinfraevent.ProvideService(ctx, gitspaceeventConfig, readerFactory4, orchestratorOrchestrator, gitspaceService, reporter4)
if err != nil {
return nil, err
}
servicesServices := services.ProvideServices(webhookService, pullreqService, triggerService, jobScheduler, collector, sizeCalculator, repoService, cleanupService, notificationService, keywordsearchService, gitspaceeventService, infraproviderService, gitspaceService, gitspaceinfraeventService)
serverSystem := server.NewSystem(bootstrapBootstrap, serverServer, sshServer, poller, resolverManager, servicesServices)
return serverSystem, nil
}

View File

@ -20,7 +20,8 @@ import (
"net/http"
"path/filepath"
"github.com/harness/gitness/infraprovider/enum"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/docker/docker/client"
"github.com/docker/go-connections/tlsconfig"
@ -37,7 +38,7 @@ func NewDockerClientFactory(config *DockerConfig) *DockerClientFactory {
// NewDockerClient returns a new docker client created using the docker config and infra.
func (d *DockerClientFactory) NewDockerClient(
_ context.Context,
infra *Infrastructure,
infra *types.Infrastructure,
) (*client.Client, error) {
if infra.ProviderType != enum.InfraProviderTypeDocker {
return nil, fmt.Errorf("infra provider type %s not supported", infra.ProviderType)
@ -49,7 +50,7 @@ func (d *DockerClientFactory) NewDockerClient(
return dockerClient, nil
}
func (d *DockerClientFactory) getClient(_ []Parameter) (*client.Client, error) {
func (d *DockerClientFactory) getClient(_ []types.InfraProviderParameter) (*client.Client, error) {
var opts []client.Opt
opts = append(opts, client.WithHost(d.config.DockerHost))

View File

@ -19,7 +19,9 @@ import (
"fmt"
"strings"
"github.com/harness/gitness/infraprovider/enum"
events "github.com/harness/gitness/app/events/gitspaceinfra"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
@ -31,15 +33,18 @@ var _ InfraProvider = (*DockerProvider)(nil)
type DockerProvider struct {
config *DockerConfig
dockerClientFactory *DockerClientFactory
eventReporter *events.Reporter
}
func NewDockerProvider(
config *DockerConfig,
dockerClientFactory *DockerClientFactory,
eventReporter *events.Reporter,
) *DockerProvider {
return &DockerProvider{
config: config,
dockerClientFactory: dockerClientFactory,
eventReporter: eventReporter,
}
}
@ -47,17 +52,18 @@ func NewDockerProvider(
// It does not start docker engine. It creates a directory in the host machine using the given resource key.
func (d DockerProvider) Provision(
ctx context.Context,
spaceID int64,
spacePath string,
resourceKey string,
requiredPorts []int,
params []Parameter,
) (*Infrastructure, error) {
dockerClient, err := d.dockerClientFactory.NewDockerClient(ctx, &Infrastructure{
params []types.InfraProviderParameter,
) error {
dockerClient, err := d.dockerClientFactory.NewDockerClient(ctx, &types.Infrastructure{
ProviderType: enum.InfraProviderTypeDocker,
Parameters: params,
})
if err != nil {
return nil, fmt.Errorf("error getting docker client from docker client factory: %w", err)
return fmt.Errorf("error getting docker client from docker client factory: %w", err)
}
defer func() {
@ -69,20 +75,24 @@ func (d DockerProvider) Provision(
infrastructure, err := d.dockerHostInfo(ctx, dockerClient)
if err != nil {
return nil, err
return err
}
infrastructure.SpaceID = spaceID
infrastructure.SpacePath = spacePath
infrastructure.ResourceKey = resourceKey
storageName, err := d.createNamedVolume(ctx, spacePath, resourceKey, dockerClient)
if err != nil {
return nil, err
return err
}
infrastructure.Storage = storageName
var portMappings = make(map[int]*PortMapping, len(requiredPorts))
var portMappings = make(map[int]*types.PortMapping, len(requiredPorts))
for _, requiredPort := range requiredPorts {
portMapping := &PortMapping{
portMapping := &types.PortMapping{
PublishedPort: 0,
ForwardedPort: 0,
}
@ -92,55 +102,81 @@ func (d DockerProvider) Provision(
infrastructure.PortMappings = portMappings
return infrastructure, nil
event := &events.GitspaceInfraEventPayload{
Infra: infrastructure,
Type: enum.InfraEventProvision,
}
d.eventReporter.EmitGitspaceInfraEvent(ctx, events.GitspaceInfraEvent, event)
return nil
}
// Find fetches the infrastructure with the current state, the method has no side effects on the infra.
func (d DockerProvider) Find(
ctx context.Context,
spaceID int64,
spacePath string,
resourceKey string,
params []Parameter,
) (*Infrastructure, error) {
dockerClient, err := d.dockerClientFactory.NewDockerClient(ctx, &Infrastructure{
params []types.InfraProviderParameter,
) (*types.Infrastructure, error) {
dockerClient, err := d.dockerClientFactory.NewDockerClient(ctx, &types.Infrastructure{
ProviderType: enum.InfraProviderTypeDocker,
Parameters: params,
})
if err != nil {
return nil, fmt.Errorf("error getting docker client from docker client factory: %w", err)
}
defer func() {
closingErr := dockerClient.Close()
if closingErr != nil {
log.Ctx(ctx).Warn().Err(closingErr).Msg("failed to close docker client")
}
}()
infrastructure, err := d.dockerHostInfo(ctx, dockerClient)
if err != nil {
return nil, err
}
infrastructure.SpaceID = spaceID
infrastructure.SpacePath = spacePath
infrastructure.ResourceKey = resourceKey
name := volumeName(spacePath, resourceKey)
volumeInspect, err := dockerClient.VolumeInspect(ctx, name)
if err != nil {
return nil, fmt.Errorf("couldn't find the volume for %s : %w", name, err)
}
infrastructure.Storage = volumeInspect.Name
return infrastructure, nil
}
// Stop is NOOP as this provider uses already running docker engine. It does not stop the docker engine.
func (d DockerProvider) Stop(_ context.Context, infra *Infrastructure) (*Infrastructure, error) {
return infra, nil
func (d DockerProvider) Stop(ctx context.Context, infra *types.Infrastructure) error {
event := &events.GitspaceInfraEventPayload{
Infra: infra,
Type: enum.InfraEventStop,
}
d.eventReporter.EmitGitspaceInfraEvent(ctx, events.GitspaceInfraEvent, event)
return nil
}
// Deprovision deletes the host machine directory created by Provision. It does not stop the docker engine.
func (d DockerProvider) Deprovision(ctx context.Context, infra *Infrastructure) (*Infrastructure, error) {
dockerClient, err := d.dockerClientFactory.NewDockerClient(ctx, &Infrastructure{
// Deprovision deletes the volume created by Provision. It does not stop the docker engine.
func (d DockerProvider) Deprovision(ctx context.Context, infra *types.Infrastructure) error {
dockerClient, err := d.dockerClientFactory.NewDockerClient(ctx, &types.Infrastructure{
ProviderType: enum.InfraProviderTypeDocker,
Parameters: infra.Parameters,
})
if err != nil {
return nil, fmt.Errorf("error getting docker client from docker client factory: %w", err)
return fmt.Errorf("error getting docker client from docker client factory: %w", err)
}
defer func() {
closingErr := dockerClient.Close()
@ -150,23 +186,31 @@ func (d DockerProvider) Deprovision(ctx context.Context, infra *Infrastructure)
}()
err = dockerClient.VolumeRemove(ctx, infra.Storage, true)
if err != nil {
return nil, fmt.Errorf("couldn't delete volume for %s : %w", infra.Storage, err)
return fmt.Errorf("couldn't delete volume for %s : %w", infra.Storage, err)
}
return infra, nil
event := &events.GitspaceInfraEventPayload{
Infra: infra,
Type: enum.InfraEventDeprovision,
}
d.eventReporter.EmitGitspaceInfraEvent(ctx, events.GitspaceInfraEvent, event)
return nil
}
// AvailableParams returns empty slice as no params are defined.
func (d DockerProvider) AvailableParams() []ParameterSchema {
return []ParameterSchema{}
func (d DockerProvider) AvailableParams() []types.InfraProviderParameterSchema {
return []types.InfraProviderParameterSchema{}
}
// ValidateParams returns nil as no params are defined.
func (d DockerProvider) ValidateParams(_ []Parameter) error {
func (d DockerProvider) ValidateParams(_ []types.InfraProviderParameter) error {
return nil
}
// TemplateParams returns nil as no template params are used.
func (d DockerProvider) TemplateParams() []ParameterSchema {
func (d DockerProvider) TemplateParams() []types.InfraProviderParameterSchema {
return nil
}
@ -175,12 +219,15 @@ func (d DockerProvider) ProvisioningType() enum.InfraProvisioningType {
return enum.InfraProvisioningTypeExisting
}
func (d DockerProvider) dockerHostInfo(ctx context.Context, dockerClient *client.Client) (*Infrastructure, error) {
func (d DockerProvider) dockerHostInfo(
ctx context.Context,
dockerClient *client.Client,
) (*types.Infrastructure, error) {
info, err := dockerClient.Info(ctx)
if err != nil {
return nil, fmt.Errorf("unable to connect to docker engine: %w", err)
}
return &Infrastructure{
return &types.Infrastructure{
Identifier: info.ID,
ProviderType: enum.InfraProviderTypeDocker,
Status: enum.InfraStatusProvisioned,

View File

@ -17,30 +17,38 @@ package infraprovider
import (
"context"
"github.com/harness/gitness/infraprovider/enum"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
type InfraProvider interface {
// Provision provisions infrastructure against a resourceKey with the provided parameters.
Provision(
ctx context.Context,
spaceID int64,
spacePath string,
resourceKey string,
requiredPorts []int,
parameters []Parameter,
) (*Infrastructure, error)
parameters []types.InfraProviderParameter,
) error
// Find finds infrastructure provisioned against a resourceKey.
Find(ctx context.Context, spacePath string, resourceKey string, parameters []Parameter) (*Infrastructure, error)
Find(
ctx context.Context,
spaceID int64,
spacePath string,
resourceKey string,
parameters []types.InfraProviderParameter,
) (*types.Infrastructure, error)
// Stop frees up the resources allocated against a resourceKey, which can be freed.
Stop(ctx context.Context, infra *Infrastructure) (*Infrastructure, error)
Stop(ctx context.Context, infra *types.Infrastructure) error
// Deprovision removes all infrastructure provisioned againest the resourceKey.
Deprovision(ctx context.Context, infra *Infrastructure) (*Infrastructure, error)
Deprovision(ctx context.Context, infra *types.Infrastructure) error
// AvailableParams provides a schema to define the infrastructure.
AvailableParams() []ParameterSchema
AvailableParams() []types.InfraProviderParameterSchema
// ValidateParams validates the supplied params before defining the infrastructure resource .
ValidateParams(parameters []Parameter) error
ValidateParams(parameters []types.InfraProviderParameter) error
// TemplateParams provides a list of params which are of type template.
TemplateParams() []ParameterSchema
TemplateParams() []types.InfraProviderParameterSchema
// ProvisioningType specifies whether the provider will provision new infra resources or it will reuse existing.
ProvisioningType() enum.InfraProvisioningType
}

View File

@ -17,7 +17,7 @@ package infraprovider
import (
"fmt"
"github.com/harness/gitness/infraprovider/enum"
"github.com/harness/gitness/types/enum"
)
type Factory struct {

View File

@ -15,6 +15,8 @@
package infraprovider
import (
events "github.com/harness/gitness/app/events/gitspaceinfra"
"github.com/google/wire"
)
@ -28,8 +30,9 @@ var WireSet = wire.NewSet(
func ProvideDockerProvider(
config *DockerConfig,
dockerClientFactory *DockerClientFactory,
eventReporter *events.Reporter,
) *DockerProvider {
return NewDockerProvider(config, dockerClientFactory)
return NewDockerProvider(config, dockerClientFactory, eventReporter)
}
func ProvideFactory(dockerProvider *DockerProvider) Factory {

View File

@ -41,7 +41,8 @@ const (
)
func GetGitspaceStateFromInstance(
instanceState GitspaceInstanceStateType) (GitspaceStateType, error) {
instanceState GitspaceInstanceStateType,
) (GitspaceStateType, error) {
switch instanceState {
case GitspaceInstanceStateRunning:
return GitspaceStateRunning, nil

31
types/enum/infra_event.go Normal file
View File

@ -0,0 +1,31 @@
// 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 enum
type InfraEvent string
func (InfraEvent) Enum() []interface{} {
return toInterfaceSlice(infraEvents)
}
var infraEvents = []InfraEvent{
InfraEventProvision, InfraEventStop, InfraEventDeprovision,
}
const (
InfraEventProvision InfraEvent = "provision"
InfraEventStop InfraEvent = "stop"
InfraEventDeprovision InfraEvent = "deprovision"
)

View File

@ -15,7 +15,7 @@
package types
import (
"github.com/harness/gitness/infraprovider/enum"
"github.com/harness/gitness/types/enum"
)
type InfraProviderConfig struct {

View File

@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package infraprovider
package types
import "github.com/harness/gitness/infraprovider/enum"
import "github.com/harness/gitness/types/enum"
type ParameterSchema struct {
type InfraProviderParameterSchema struct {
Name string
Description string
DefaultValue string
@ -25,7 +25,7 @@ type ParameterSchema struct {
Editable bool
}
type Parameter struct {
type InfraProviderParameter struct {
Name string
Value string
}
@ -49,13 +49,15 @@ type Infrastructure struct {
// ProviderType specifies the type of the infra provider.
ProviderType enum.InfraProviderType
// Parameters which are required by the provider to provision the infra.
Parameters []Parameter
Parameters []InfraProviderParameter
// Status of the infra.
Status enum.InfraStatus
// Host through which the infra can be accessed for all purposes.
Host string
// Port on which the infra can be accessed to orchestrate containers.
Port int
// Host through which the infra can be accessed.
Host string
ProxyHost string
// AgentPort on which the agent can be accessed to orchestrate containers.
AgentPort int
ProxyPort int
// Storage is the name of the volume or disk created for the resource.
Storage string
// PortMappings contains the ports assigned for every requested port.