feat: [CDE-681]: Find infra from DB and status from GCP (#3538) (#3540)

* feat: [CDE-681]: Find infra from DB and status from GCP (#3538)

* Merge branch 'hybrid' into CDE-681
* feat: [CDE-681]: fix lint
* feat: [CDE-681]: fix lint
* feat: [CDE-681]: merge
* feat: [CDE-681]: fix wiring
* feat: [CDE-681]: handle delete and fallback for it
* feat: [CDE-681]: handle delete and fallback for it
* feat: [CDE-681]: Find infra from DB and status from GCP
* feat: [CDE-681]: Find infra from DB and status from GCP
* feat: [CDE-681]: Find infra from DB and status from GCP
* feat: [CDE-681]: Find infra from DB and status from GCP
* feat: [CDE-681]: Find infra from DB and status from GCP
* feat: [CDE-681]: merge
* feat: [CDE-661]: set starting state by default in resume
* Merge branch 'main' into hybrid
* feat: [CDE-661]: fix host and port (#3511)

* feat: [CDE-661]: fix host and port
* feat: [CDE-661]: fix host and port
* feat: [CDE-661]: send remove request for hybrid (#3500)

* feat: [CDE-661]: add debug logs
* feat: [CDE-661]: send remove request for hybrid
* feat:
try-new-ui
Vikyath Harekal 2025-03-12 10:43:31 +00:00 committed by Harness
parent 0a573a566c
commit ff18742bdd
39 changed files with 1124 additions and 215 deletions

View File

@ -0,0 +1,20 @@
// 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
const (
// category defines the event category used for this package.
category = "gitspace_operations"
)

View File

@ -0,0 +1,63 @@
// 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"
"fmt"
"github.com/harness/gitness/events"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
const (
GitspaceOperationsEvent events.EventType = "gitspace_operations_event"
)
type (
GitspaceOperationsEventPayload struct {
Type enum.GitspaceOperationsEvent `json:"type"`
Infra types.Infrastructure `json:"infra,omitempty"`
Response any `json:"response,omitempty"`
}
)
func (r *Reporter) EmitGitspaceOperationsEvent(
ctx context.Context,
event events.EventType,
payload *GitspaceOperationsEventPayload,
) error {
if payload == nil {
return fmt.Errorf("payload can not be nil for event type %s", GitspaceOperationsEvent)
}
eventID, err := events.ReporterSendEvent(r.innerReporter, ctx, event, payload)
if err != nil {
return fmt.Errorf("failed to send %+v event", event)
}
log.Ctx(ctx).Debug().Msgf("reported %v event with id '%s'", event, eventID)
return nil
}
func (r *Reader) RegisterGitspaceOperationsEvent(
fn events.HandlerFunc[*GitspaceOperationsEventPayload],
opts ...events.HandlerOption,
) error {
return events.ReaderRegisterEvent(r.innerReader, GitspaceOperationsEvent, 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

@ -28,7 +28,6 @@ import (
func (i InfraProvisioner) Find(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
requiredGitspacePorts []types.GitspacePort,
) (*types.Infrastructure, error) {
infraProviderResource := gitspaceConfig.InfraProviderResource
infraProviderEntity, err := i.getConfigFromResource(ctx, infraProviderResource)
@ -41,35 +40,43 @@ func (i InfraProvisioner) Find(
return nil, err
}
var inputParams []types.InfraProviderParameter
var configMetadata map[string]any
var agentPort = 0
var infra *types.Infrastructure
//nolint:nestif
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew {
inputParams, configMetadata, err = i.paramsForProvisioningTypeNew(ctx, gitspaceConfig)
inputParams, _, err := i.paramsForProvisioningTypeNew(ctx, gitspaceConfig)
if err != nil {
return nil, err
}
// TODO: What if the agent port has deviated from when the last instance was created?
agentPort = i.config.AgentPort
infra, err = i.GetInfraFromStoredInfo(ctx, gitspaceConfig)
if err != nil {
return nil, fmt.Errorf("failed to find infrastructure from stored info: %w", err)
}
status, err := infraProvider.FindInfraStatus(
ctx,
gitspaceConfig.Identifier,
gitspaceConfig.GitspaceInstance.Identifier,
inputParams,
)
if err != nil {
return nil, fmt.Errorf("failed to find infra status: %w", err)
}
if status != nil {
infra.Status = *status
}
} else {
inputParams, configMetadata, err = i.paramsForProvisioningTypeExisting(ctx, infraProviderResource, infraProvider)
inputParams, _, err := i.paramsForProvisioningTypeExisting(ctx, infraProviderResource, infraProvider)
if err != nil {
return nil, err
}
}
infra, err := infraProvider.Find(ctx, gitspaceConfig.SpaceID, gitspaceConfig.SpacePath,
gitspaceConfig.Identifier, gitspaceConfig.GitspaceInstance.Identifier,
agentPort, requiredGitspacePorts, inputParams, configMetadata)
if err != nil {
return nil, fmt.Errorf("failed to find infrastructure: %w", err)
}
if infra == nil { // fallback
infra, err = i.getInfraFromStoredInfo(ctx, gitspaceConfig)
infra, err = infraProvider.Find(
ctx,
gitspaceConfig.SpaceID,
gitspaceConfig.SpacePath,
gitspaceConfig.Identifier,
inputParams,
)
if err != nil {
return nil, fmt.Errorf("failed to build infrastructure from stored info: %w", err)
return nil, fmt.Errorf("failed to find infrastructure from provider: %w", err)
}
}
@ -143,7 +150,7 @@ func getGitspaceScheme(ideType enum.IDEType, gitspaceSchemeFromMetadata string)
}
}
func (i InfraProvisioner) getInfraFromStoredInfo(
func (i InfraProvisioner) GetInfraFromStoredInfo(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
) (*types.Infrastructure, error) {

View File

@ -18,6 +18,7 @@ import (
"context"
"encoding/json"
"fmt"
"math"
"strconv"
"time"
@ -47,13 +48,13 @@ func (i InfraProvisioner) PostInfraEventComplete(
enum.InfraEventDeprovision,
enum.InfraEventStop,
enum.InfraEventCleanup:
return i.updateInfraProvisioned(ctx, gitspaceConfig.GitspaceInstance.ID, infra)
return i.UpdateInfraProvisioned(ctx, gitspaceConfig.GitspaceInstance.ID, infra)
default:
return fmt.Errorf("unsupported event type: %s", eventType)
}
}
func (i InfraProvisioner) updateInfraProvisioned(
func (i InfraProvisioner) UpdateInfraProvisioned(
ctx context.Context,
gitspaceInstanceID int64,
infrastructure types.Infrastructure,
@ -72,8 +73,22 @@ func (i InfraProvisioner) updateInfraProvisioned(
infraProvisionedLatest.InfraStatus = infrastructure.Status
infraProvisionedLatest.ServerHostIP = infrastructure.AgentHost
infraProvisionedLatest.ServerHostPort = strconv.Itoa(infrastructure.AgentPort)
infraProvisionedLatest.ProxyHost = infrastructure.ProxyAgentHost
infraProvisionedLatest.ProxyPort = int32(infrastructure.ProxyAgentPort)
proxyHost := infrastructure.AgentHost
if infrastructure.ProxyAgentHost != "" {
proxyHost = infrastructure.ProxyAgentHost
}
infraProvisionedLatest.ProxyHost = proxyHost
proxyPort := infrastructure.AgentPort
if infrastructure.ProxyAgentPort != 0 {
proxyPort = infrastructure.ProxyAgentPort
}
if proxyPort > math.MaxInt32 || proxyPort < math.MinInt32 {
return fmt.Errorf("proxyPort value %d exceeds int32 range", proxyPort)
}
infraProvisionedLatest.ProxyPort = int32(proxyPort)
infraProvisionedLatest.ResponseMetadata = &responseMetaDataJSON
infraProvisionedLatest.Updated = time.Now().UnixMilli()

View File

@ -163,6 +163,22 @@ func (i InfraProvisioner) provisionNewInfrastructure(
if err != nil {
return err
}
infrastructure := types.Infrastructure{
Identifier: gitspaceConfig.GitspaceInstance.Identifier,
SpaceID: gitspaceConfig.SpaceID,
SpacePath: gitspaceConfig.SpacePath,
GitspaceConfigIdentifier: gitspaceConfig.Identifier,
GitspaceInstanceIdentifier: gitspaceConfig.GitspaceInstance.Identifier,
ProviderType: infraProviderType,
InputParameters: allParams,
ConfigMetadata: configMetadata,
}
responseMetadata, err := json.Marshal(infrastructure)
if err != nil {
return fmt.Errorf("unable to marshal infra object %+v: %w", responseMetadata, err)
}
responseMetaDataJSON := string(responseMetadata)
infraProvisioned := &types.InfraProvisioned{
GitspaceInstanceID: gitspaceConfig.GitspaceInstance.ID,
InfraProviderType: infraProviderType,
@ -172,6 +188,7 @@ func (i InfraProvisioner) provisionNewInfrastructure(
InputParams: paramsBytes,
InfraStatus: enum.InfraStatusPending,
SpaceID: gitspaceConfig.SpaceID,
ResponseMetadata: &responseMetaDataJSON,
}
err = i.infraProvisionedStore.Create(ctx, infraProvisioned)
@ -190,7 +207,6 @@ func (i InfraProvisioner) provisionNewInfrastructure(
agentPort,
requiredGitspacePorts,
allParams,
configMetadata,
)
if err != nil {
infraProvisioned.InfraStatus = enum.InfraStatusUnknown
@ -216,7 +232,7 @@ func (i InfraProvisioner) provisionExistingInfrastructure(
gitspaceConfig types.GitspaceConfig,
requiredGitspacePorts []types.GitspacePort,
) error {
allParams, configMetadata, err := i.getAllParamsFromDB(ctx, gitspaceConfig.InfraProviderResource, infraProvider)
allParams, _, err := i.getAllParamsFromDB(ctx, gitspaceConfig.InfraProviderResource, infraProvider)
if err != nil {
return fmt.Errorf("could not get all params from DB while provisioning: %w", err)
}
@ -235,7 +251,6 @@ func (i InfraProvisioner) provisionExistingInfrastructure(
0, // NOTE: Agent port is not required for provisioning type Existing.
requiredGitspacePorts,
allParams,
configMetadata,
)
if err != nil {
return fmt.Errorf(

View File

@ -33,13 +33,21 @@ type Orchestrator interface {
resolvedDetails scm.ResolvedDetails,
defaultBaseImage string,
ideService ide.IDE,
) (*StartResponse, error)
) error
// RetryCreateAndStartGitspaceIfRequired will handle the delegate task response and retry if status code is > 202
RetryCreateAndStartGitspaceIfRequired(ctx context.Context)
// StopGitspace stops the gitspace container.
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 types.Infrastructure) error
StopAndRemoveGitspace(
ctx context.Context,
config types.GitspaceConfig,
infra types.Infrastructure,
canDeleteUserData bool,
) error
// Status checks if the infra is reachable and ready to orchestrate containers.
Status(ctx context.Context, infra types.Infrastructure) error

View File

@ -28,6 +28,7 @@ import (
"strconv"
"strings"
"github.com/harness/gitness/app/gitspace/orchestrator/container/response"
"github.com/harness/gitness/app/gitspace/orchestrator/runarg"
"github.com/harness/gitness/app/gitspace/orchestrator/utils"
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
@ -794,7 +795,7 @@ func GetContainerResponse(
containerName string,
portMappings map[int]*types.PortMapping,
repoName string,
) (*StartResponse, error) {
) (*response.StartResponse, error) {
id, ports, remoteUser, err := GetContainerInfo(ctx, containerName, dockerClient, portMappings)
if err != nil {
return nil, err
@ -803,7 +804,7 @@ func GetContainerResponse(
homeDir := GetUserHomeDir(remoteUser)
codeRepoDir := filepath.Join(homeDir, repoName)
return &StartResponse{
return &response.StartResponse{
ContainerID: id,
ContainerName: containerName,
PublishedPorts: ports,

View File

@ -20,7 +20,9 @@ import (
"path/filepath"
"strings"
events "github.com/harness/gitness/app/events/gitspaceoperations"
"github.com/harness/gitness/app/gitspace/logutil"
"github.com/harness/gitness/app/gitspace/orchestrator/container/response"
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
"github.com/harness/gitness/app/gitspace/orchestrator/runarg"
@ -29,6 +31,7 @@ import (
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
"github.com/harness/gitness/infraprovider"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/client"
@ -46,6 +49,7 @@ type EmbeddedDockerOrchestrator struct {
dockerClientFactory *infraprovider.DockerClientFactory
statefulLogger *logutil.StatefulLogger
runArgProvider runarg.Provider
eventReporter *events.Reporter
}
// Step represents a single setup action.
@ -87,11 +91,13 @@ func NewEmbeddedDockerOrchestrator(
dockerClientFactory *infraprovider.DockerClientFactory,
statefulLogger *logutil.StatefulLogger,
runArgProvider runarg.Provider,
) Orchestrator {
return &EmbeddedDockerOrchestrator{
eventReporter *events.Reporter,
) EmbeddedDockerOrchestrator {
return EmbeddedDockerOrchestrator{
dockerClientFactory: dockerClientFactory,
statefulLogger: statefulLogger,
runArgProvider: runArgProvider,
eventReporter: eventReporter,
}
}
@ -106,20 +112,20 @@ func (e *EmbeddedDockerOrchestrator) CreateAndStartGitspace(
resolvedRepoDetails scm.ResolvedDetails,
defaultBaseImage string,
ideService ide.IDE,
) (*StartResponse, error) {
) error {
containerName := GetGitspaceContainerName(gitspaceConfig)
logger := log.Ctx(ctx).With().Str(loggingKey, containerName).Logger()
// Step 1: Validate access key
accessKey, err := e.getAccessKey(gitspaceConfig)
if err != nil {
return nil, err
return err
}
// Step 2: Get Docker client
dockerClient, err := e.getDockerClient(ctx, infra)
if err != nil {
return nil, err
return err
}
defer e.closeDockerClient(dockerClient)
@ -129,7 +135,7 @@ func (e *EmbeddedDockerOrchestrator) CreateAndStartGitspace(
// Step 3: Check the current state of the container
state, err := e.checkContainerState(ctx, dockerClient, containerName)
if err != nil {
return nil, err
return err
}
// Step 4: Handle different container states
@ -146,7 +152,7 @@ func (e *EmbeddedDockerOrchestrator) CreateAndStartGitspace(
accessKey,
ideService,
); err != nil {
return nil, err
return err
}
case ContainerStateRemoved:
if err = e.createAndStartNewGitspace(
@ -158,18 +164,37 @@ func (e *EmbeddedDockerOrchestrator) CreateAndStartGitspace(
defaultBaseImage,
ideService,
imagAuthMap); err != nil {
return nil, err
return err
}
case ContainerStatePaused, ContainerStateCreated, ContainerStateUnknown, ContainerStateDead:
// TODO handle the following states
return nil, fmt.Errorf("gitspace %s is in a unhandled state: %s", containerName, state)
return fmt.Errorf("gitspace %s is in a unhandled state: %s", containerName, state)
default:
return nil, fmt.Errorf("gitspace %s is in a bad state: %s", containerName, state)
return fmt.Errorf("gitspace %s is in a bad state: %s", containerName, state)
}
// Step 5: Retrieve container information and return response
return GetContainerResponse(ctx, dockerClient, containerName, infra.GitspacePortMappings, resolvedRepoDetails.RepoName)
startResponse, err := GetContainerResponse(
ctx,
dockerClient,
containerName,
infra.GitspacePortMappings,
resolvedRepoDetails.RepoName,
)
if err != nil {
return err
}
return e.eventReporter.EmitGitspaceOperationsEvent(
ctx,
events.GitspaceOperationsEvent,
&events.GitspaceOperationsEventPayload{
Type: enum.GitspaceOperationsEventStart,
Infra: infra,
Response: *startResponse,
},
)
}
// startStoppedGitspace starts the Gitspace container if it was stopped.
@ -293,8 +318,16 @@ func (e *EmbeddedDockerOrchestrator) StopGitspace(
return fmt.Errorf("gitspace %s is in a bad state: %s", containerName, state)
}
err = e.eventReporter.EmitGitspaceOperationsEvent(
ctx,
events.GitspaceOperationsEvent,
&events.GitspaceOperationsEventPayload{
Type: enum.GitspaceOperationsEventStop,
Infra: infra,
},
)
logger.Debug().Msg("stopped gitspace")
return nil
return err
}
// stopRunningGitspace handles stopping the container when it is in a running state.
@ -326,6 +359,7 @@ func (e *EmbeddedDockerOrchestrator) StopAndRemoveGitspace(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
canDeleteUserData bool,
) error {
containerName := GetGitspaceContainerName(gitspaceConfig)
logger := log.Ctx(ctx).With().Str(loggingKey, containerName).Logger()
@ -373,8 +407,17 @@ func (e *EmbeddedDockerOrchestrator) StopAndRemoveGitspace(
return fmt.Errorf("failed to remove gitspace %s: %w", containerName, err)
}
err = e.eventReporter.EmitGitspaceOperationsEvent(
ctx,
events.GitspaceOperationsEvent,
&events.GitspaceOperationsEventPayload{
Type: enum.GitspaceOperationsEventDelete,
Infra: infra,
Response: &response.DeleteResponse{CanDeleteUserData: canDeleteUserData},
},
)
logger.Debug().Msg("removed gitspace")
return nil
return err
}
func (e *EmbeddedDockerOrchestrator) StreamLogs(
@ -833,3 +876,7 @@ func getImage(devcontainerConfig types.DevcontainerConfig, defaultBaseImage stri
}
return imageName
}
func (e *EmbeddedDockerOrchestrator) RetryCreateAndStartGitspaceIfRequired(_ context.Context) {
// Nothing to do here as the event will be published from CreateAndStartGitspace itself.
}

View File

@ -0,0 +1,43 @@
// 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 container
import (
"fmt"
"github.com/harness/gitness/types/enum"
)
type Factory interface {
GetContainerOrchestrator(providerType enum.InfraProviderType) (Orchestrator, error)
}
type factory struct {
containerOrchestrators map[enum.InfraProviderType]Orchestrator
}
func NewFactory(embeddedDockerOrchestrator EmbeddedDockerOrchestrator) Factory {
containerOrchestrators := make(map[enum.InfraProviderType]Orchestrator)
containerOrchestrators[enum.InfraProviderTypeDocker] = &embeddedDockerOrchestrator
return &factory{containerOrchestrators: containerOrchestrators}
}
func (f *factory) GetContainerOrchestrator(infraProviderType enum.InfraProviderType) (Orchestrator, error) {
val, exist := f.containerOrchestrators[infraProviderType]
if !exist {
return nil, fmt.Errorf("unsupported infra provider type: %s", infraProviderType)
}
return val, nil
}

View File

@ -0,0 +1,19 @@
// 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 response
type DeleteResponse struct {
CanDeleteUserData bool `json:"can_delete_user_data"`
}

View File

@ -0,0 +1,23 @@
// 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 response
type StartResponse struct {
ContainerID string `json:"container_id"`
ContainerName string `json:"container_name"`
PublishedPorts map[int]string `json:"published_ports"`
AbsoluteRepoPath string `json:"absolute_repo_path"`
RemoteUser string `json:"remote_user"`
}

View File

@ -14,14 +14,6 @@
package container
type StartResponse struct {
ContainerID string
ContainerName string
PublishedPorts map[int]string
AbsoluteRepoPath string
RemoteUser string
}
type PostAction string
const (

View File

@ -18,14 +18,17 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"path/filepath"
"sync"
"github.com/harness/gitness/app/gitspace/orchestrator/container/response"
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
"github.com/harness/gitness/types"
dockerTypes "github.com/docker/docker/api/types"
"github.com/rs/zerolog/log"
)
const (
@ -155,3 +158,32 @@ func ExecuteLifecycleCommands(
return nil
}
func ProcessStartResponse(
ctx context.Context,
config types.GitspaceConfig,
resp io.ReadCloser,
) (*response.StartResponse, error) {
var err error
defer func() {
err = resp.Close()
if err != nil {
log.Ctx(ctx).Warn().Err(err).Msgf(
"failed to close response after starting gitspace %s", config.Identifier)
}
}()
bodyBytes, _ := io.ReadAll(resp)
responseBody := string(bodyBytes)
log.Debug().Msgf("response from %s %s", config.GitspaceInstance.Identifier, responseBody)
var startResponse response.StartResponse
err = json.Unmarshal(bodyBytes, &startResponse)
if err != nil {
return nil, fmt.Errorf("error unmarshalling start response for gitspace instance %s: %w",
config.GitspaceInstance.Identifier, err)
}
return &startResponse, nil
}

View File

@ -15,6 +15,7 @@
package container
import (
events "github.com/harness/gitness/app/events/gitspaceoperations"
"github.com/harness/gitness/app/gitspace/logutil"
"github.com/harness/gitness/app/gitspace/orchestrator/runarg"
"github.com/harness/gitness/infraprovider"
@ -24,16 +25,25 @@ import (
var WireSet = wire.NewSet(
ProvideEmbeddedDockerOrchestrator,
ProvideContainerOrchestratorFactory,
)
func ProvideEmbeddedDockerOrchestrator(
dockerClientFactory *infraprovider.DockerClientFactory,
statefulLogger *logutil.StatefulLogger,
runArgProvdier runarg.Provider,
) Orchestrator {
runArgProvider runarg.Provider,
eventReporter *events.Reporter,
) EmbeddedDockerOrchestrator {
return NewEmbeddedDockerOrchestrator(
dockerClientFactory,
statefulLogger,
runArgProvdier,
runArgProvider,
eventReporter,
)
}
func ProvideContainerOrchestratorFactory(
embeddedDockerOrchestrator EmbeddedDockerOrchestrator,
) Factory {
return NewFactory(embeddedDockerOrchestrator)
}

View File

@ -20,11 +20,9 @@ import (
"strconv"
"time"
"github.com/harness/gitness/app/gitspace/orchestrator/container"
"github.com/harness/gitness/app/gitspace/orchestrator/container/response"
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
"github.com/harness/gitness/app/gitspace/secret"
secretenum "github.com/harness/gitness/app/gitspace/secret/enum"
"github.com/harness/gitness/app/paths"
"github.com/harness/gitness/app/gitspace/orchestrator/utils"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
@ -39,39 +37,16 @@ func (o Orchestrator) ResumeStartGitspace(
provisionedInfra types.Infrastructure,
) (types.GitspaceInstance, *types.GitspaceError) {
gitspaceInstance := gitspaceConfig.GitspaceInstance
gitspaceInstance.State = enum.GitspaceInstanceStateError
secretResolver, err := o.getSecretResolver(gitspaceInstance.AccessType)
gitspaceInstance.State = enum.GitspaceInstanceStateStarting
secretValue, err := utils.ResolveSecret(ctx, o.secretResolverFactory, gitspaceConfig)
if err != nil {
log.Err(err).Msgf("could not find secret resolver for type: %s", gitspaceInstance.AccessType)
return *gitspaceInstance, &types.GitspaceError{
Error: err,
Error: fmt.Errorf("cannot resolve secret for ID %s: %w",
gitspaceConfig.InfraProviderResource.UID, err),
ErrorMessage: ptr.String(err.Error()),
}
}
rootSpaceID, _, err := paths.DisectRoot(gitspaceConfig.SpacePath)
if err != nil {
log.Err(err).Msgf("unable to find root space id from space path: %s", gitspaceConfig.SpacePath)
return *gitspaceInstance, &types.GitspaceError{
Error: err,
ErrorMessage: ptr.String(err.Error()),
}
}
resolvedSecret, err := secretResolver.Resolve(ctx, secret.ResolutionContext{
UserIdentifier: gitspaceConfig.GitspaceUser.Identifier,
GitspaceIdentifier: gitspaceConfig.Identifier,
SecretRef: *gitspaceInstance.AccessKeyRef,
SpaceIdentifier: rootSpaceID,
})
if err != nil {
log.Err(err).Msgf("could not resolve secret type: %s, ref: %s",
gitspaceInstance.AccessType, *gitspaceInstance.AccessKeyRef)
return *gitspaceInstance, &types.GitspaceError{
Error: err,
ErrorMessage: ptr.String(err.Error()),
}
}
gitspaceInstance.AccessKey = &resolvedSecret.SecretValue
gitspaceInstance.AccessKey = secretValue
ideSvc, err := o.ideFactory.GetIDE(gitspaceConfig.IDE)
if err != nil {
@ -118,13 +93,13 @@ func (o Orchestrator) ResumeStartGitspace(
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectStart)
err = o.containerOrchestrator.Status(ctx, provisionedInfra)
containerOrchestrator, err := o.containerOrchestratorFactory.GetContainerOrchestrator(provisionedInfra.ProviderType)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectFailed)
agentUnreachableErr := fmt.Errorf("couldn't call the agent health API: %w", err)
return *gitspaceInstance, &types.GitspaceError{
Error: agentUnreachableErr,
ErrorMessage: ptr.String(agentUnreachableErr.Error()),
Error: fmt.Errorf("failed to get the container orchestrator for infra provider type %s: %w",
provisionedInfra.ProviderType, err),
ErrorMessage: ptr.String(err.Error()),
}
}
@ -153,7 +128,7 @@ func (o Orchestrator) ResumeStartGitspace(
// NOTE: Currently we use a static identifier as the Gitspace user.
gitspaceConfig.GitspaceUser.Identifier = harnessUser
startResponse, err := o.containerOrchestrator.CreateAndStartGitspace(
err = containerOrchestrator.CreateAndStartGitspace(
ctx, gitspaceConfig, provisionedInfra, *scmResolvedDetails, o.config.DefaultBaseImage, ideSvc)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationFailed)
@ -164,7 +139,26 @@ func (o Orchestrator) ResumeStartGitspace(
}
}
return *gitspaceConfig.GitspaceInstance, nil
}
// FinishResumeStartGitspace needs to be called from the API Handler.
func (o Orchestrator) FinishResumeStartGitspace(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
provisionedInfra types.Infrastructure,
startResponse *response.StartResponse,
) (types.GitspaceInstance, *types.GitspaceError) {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationCompleted)
gitspaceInstance := gitspaceConfig.GitspaceInstance
ideSvc, err := o.ideFactory.GetIDE(gitspaceConfig.IDE)
if err != nil {
return *gitspaceInstance, &types.GitspaceError{
Error: err,
ErrorMessage: ptr.String(err.Error()),
}
}
ideURLString := generateIDEURL(provisionedInfra, ideSvc, startResponse)
gitspaceInstance.URL = &ideURLString
@ -183,7 +177,7 @@ func (o Orchestrator) ResumeStartGitspace(
func generateIDEURL(
provisionedInfra types.Infrastructure,
ideSvc ide.IDE,
startResponse *container.StartResponse,
startResponse *response.StartResponse,
) string {
idePort := ideSvc.Port()
var forwardedPort string
@ -202,19 +196,6 @@ func generateIDEURL(
return ideSvc.GenerateURL(startResponse.AbsoluteRepoPath, host, forwardedPort, startResponse.RemoteUser)
}
func (o Orchestrator) getSecretResolver(accessType enum.GitspaceAccessType) (secret.Resolver, error) {
secretType := secretenum.PasswordSecretType
switch accessType {
case enum.GitspaceAccessTypeUserCredentials:
secretType = secretenum.PasswordSecretType
case enum.GitspaceAccessTypeJWTToken:
secretType = secretenum.JWTSecretType
case enum.GitspaceAccessTypeSSHKey:
secretType = secretenum.SSHSecretType
}
return o.secretResolverFactory.GetSecretResolver(secretType)
}
// ResumeStopGitspace saves the deprovisioned infra details.
func (o Orchestrator) ResumeStopGitspace(
ctx context.Context,

View File

@ -26,6 +26,7 @@ import (
"github.com/harness/gitness/app/gitspace/platformconnector"
"github.com/harness/gitness/app/gitspace/scm"
"github.com/harness/gitness/app/gitspace/secret"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
@ -41,35 +42,38 @@ type Config struct {
}
type Orchestrator struct {
scm *scm.SCM
platformConnector platformconnector.PlatformConnector
infraProvisioner infrastructure.InfraProvisioner
containerOrchestrator container.Orchestrator
eventReporter *events.Reporter
config *Config
ideFactory ide.Factory
secretResolverFactory *secret.ResolverFactory
scm *scm.SCM
platformConnector platformconnector.PlatformConnector
infraProvisioner infrastructure.InfraProvisioner
containerOrchestratorFactory container.Factory
eventReporter *events.Reporter
config *Config
ideFactory ide.Factory
secretResolverFactory *secret.ResolverFactory
gitspaceInstanceStore store.GitspaceInstanceStore
}
func NewOrchestrator(
scm *scm.SCM,
platformConnector platformconnector.PlatformConnector,
infraProvisioner infrastructure.InfraProvisioner,
containerOrchestrator container.Orchestrator,
containerOrchestratorFactory container.Factory,
eventReporter *events.Reporter,
config *Config,
ideFactory ide.Factory,
secretResolverFactory *secret.ResolverFactory,
gitspaceInstanceStore store.GitspaceInstanceStore,
) Orchestrator {
return Orchestrator{
scm: scm,
platformConnector: platformConnector,
infraProvisioner: infraProvisioner,
containerOrchestrator: containerOrchestrator,
eventReporter: eventReporter,
config: config,
ideFactory: ideFactory,
secretResolverFactory: secretResolverFactory,
scm: scm,
platformConnector: platformConnector,
infraProvisioner: infraProvisioner,
containerOrchestratorFactory: containerOrchestratorFactory,
eventReporter: eventReporter,
config: config,
ideFactory: ideFactory,
secretResolverFactory: secretResolverFactory,
gitspaceInstanceStore: gitspaceInstanceStore,
}
}
@ -165,19 +169,6 @@ func (o Orchestrator) TriggerStopGitspace(
}
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopStart)
err = o.infraProvisioner.TriggerInfraEvent(ctx, enum.InfraEventStop, gitspaceConfig, infra)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
infraStopErr := fmt.Errorf("cannot trigger stop infrastructure with ID %s: %w",
gitspaceConfig.InfraProviderResource.UID, err)
return &types.GitspaceError{
Error: infraStopErr,
ErrorMessage: ptr.String(infraStopErr.Error()), // TODO: Fetch explicit error msg
}
}
return nil
}
@ -188,11 +179,10 @@ func (o Orchestrator) stopGitspaceContainer(
) error {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectStart)
err := o.containerOrchestrator.Status(ctx, infra)
containerOrchestrator, err := o.containerOrchestratorFactory.GetContainerOrchestrator(infra.ProviderType)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectFailed)
return fmt.Errorf("couldn't call the agent health API: %w", err)
return fmt.Errorf("couldn't get the container orchestrator: %w", err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectCompleted)
@ -202,14 +192,35 @@ func (o Orchestrator) stopGitspaceContainer(
// NOTE: Currently we use a static identifier as the Gitspace user.
gitspaceConfig.GitspaceUser.Identifier = harnessUser
err = o.containerOrchestrator.StopGitspace(ctx, gitspaceConfig, infra)
err = containerOrchestrator.StopGitspace(ctx, gitspaceConfig, infra)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceStopFailed)
return fmt.Errorf("error stopping the Gitspace container: %w", err)
}
return nil
}
func (o Orchestrator) FinishStopGitspaceContainer(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
) *types.GitspaceError {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceStopCompleted)
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopStart)
err := o.infraProvisioner.TriggerInfraEvent(ctx, enum.InfraEventStop, gitspaceConfig, &infra)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
infraStopErr := fmt.Errorf("cannot trigger stop infrastructure with ID %s: %w",
gitspaceConfig.InfraProviderResource.UID, err)
return &types.GitspaceError{
Error: infraStopErr,
ErrorMessage: ptr.String(infraStopErr.Error()), // TODO: Fetch explicit error msg
}
}
return nil
}
@ -217,14 +228,14 @@ func (o Orchestrator) stopAndRemoveGitspaceContainer(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
canDeleteUserData bool,
) error {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectStart)
err := o.containerOrchestrator.Status(ctx, infra)
containerOrchestrator, err := o.containerOrchestratorFactory.GetContainerOrchestrator(infra.ProviderType)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectFailed)
return fmt.Errorf("couldn't call the agent health API: %w", err)
return fmt.Errorf("couldn't get the container orchestrator: %w", err)
}
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectCompleted)
@ -234,12 +245,43 @@ func (o Orchestrator) stopAndRemoveGitspaceContainer(
// NOTE: Currently we use a static identifier as the Gitspace user.
gitspaceConfig.GitspaceUser.Identifier = harnessUser
err = o.containerOrchestrator.StopAndRemoveGitspace(ctx, gitspaceConfig, infra)
err = containerOrchestrator.StopAndRemoveGitspace(ctx, gitspaceConfig, infra, canDeleteUserData)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceDeletionFailed)
log.Err(err).Msgf("error stopping the Gitspace container")
}
return nil
}
func (o Orchestrator) FinishStopAndRemoveGitspaceContainer(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
canDeleteUserData bool,
) *types.GitspaceError {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceDeletionCompleted)
if canDeleteUserData {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningStart)
} else {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceDeletionCompleted)
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraResetStart)
}
opts := infrastructure.InfraEventOpts{CanDeleteUserData: canDeleteUserData}
err := o.infraProvisioner.TriggerInfraEventWithOpts(ctx, enum.InfraEventDeprovision, gitspaceConfig, &infra, opts)
if err != nil {
if canDeleteUserData {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningFailed)
} else {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraResetFailed)
}
return &types.GitspaceError{
Error: fmt.Errorf(
"cannot trigger deprovision infrastructure with ID %s: %w",
gitspaceConfig.InfraProviderResource.UID,
err,
),
ErrorMessage: ptr.String(err.Error()),
}
}
return nil
}
@ -302,30 +344,66 @@ func (o Orchestrator) TriggerDeleteGitspace(
"unable to find provisioned infra while triggering delete for gitspace instance %s: %w",
gitspaceConfig.GitspaceInstance.Identifier, err)
}
if infra.ProviderType == enum.InfraProviderTypeDocker {
if err = o.stopAndRemoveGitspaceContainer(ctx, gitspaceConfig, *infra); err != nil {
return err
}
}
if canDeleteUserData {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningStart)
} else {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraResetStart)
if err = o.stopAndRemoveGitspaceContainer(ctx, gitspaceConfig, *infra, canDeleteUserData); err != nil {
log.Warn().Msgf("error stopping and removing gitspace container: %v", err)
}
opts := infrastructure.InfraEventOpts{CanDeleteUserData: canDeleteUserData}
err = o.infraProvisioner.TriggerInfraEventWithOpts(ctx, enum.InfraEventDeprovision, gitspaceConfig, infra, opts)
if err != nil {
if canDeleteUserData {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningFailed)
} else {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraResetFailed)
}
return fmt.Errorf(
"cannot trigger deprovision infrastructure with ID %s: %w", gitspaceConfig.InfraProviderResource.UID, err)
}
// TODO: Add a job for cleanup of infra if stop fails
log.Warn().Msgf(
"Checking and force deleting the infra if required for gitspace instance %s",
gitspaceConfig.GitspaceInstance.Identifier,
)
ticker := time.NewTicker(60 * time.Second)
timeout := time.After(15 * time.Minute)
defer ticker.Stop()
ch := make(chan error)
return nil
for {
select {
case msg := <-ch:
if msg == nil {
return msg
}
case <-ticker.C:
instance, err := o.gitspaceInstanceStore.Find(
ctx,
gitspaceConfig.GitspaceInstance.ID,
)
if err != nil {
return fmt.Errorf(
"failed to find gitspace instance %s: %w",
gitspaceConfig.GitspaceInstance.Identifier,
err,
)
}
if instance.State == enum.GitspaceInstanceStateDeleted ||
instance.State == enum.GitspaceInstanceStateCleaned {
return nil
}
case <-timeout:
opts := infrastructure.InfraEventOpts{CanDeleteUserData: true}
err := o.infraProvisioner.TriggerInfraEventWithOpts(
ctx,
enum.InfraEventDeprovision,
gitspaceConfig,
infra,
opts,
)
if err != nil {
if canDeleteUserData {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningFailed)
} else {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraResetFailed)
}
return fmt.Errorf(
"cannot trigger deprovision infrastructure with gitspace identifier %s: %w",
gitspaceConfig.GitspaceInstance.Identifier,
err,
)
}
return nil
}
}
}
func (o Orchestrator) emitGitspaceEvent(
@ -379,9 +457,14 @@ func (o Orchestrator) GetGitspaceLogs(ctx context.Context, gitspaceConfig types.
gitspaceConfig.GitspaceInstance.Identifier, err)
}
containerOrchestrator, err := o.containerOrchestratorFactory.GetContainerOrchestrator(infra.ProviderType)
if err != nil {
return "", fmt.Errorf("couldn't get the container orchestrator: %w", err)
}
// NOTE: Currently we use a static identifier as the Gitspace user.
gitspaceConfig.GitspaceUser.Identifier = harnessUser
logs, err := o.containerOrchestrator.StreamLogs(ctx, gitspaceConfig, *infra)
logs, err := containerOrchestrator.StreamLogs(ctx, gitspaceConfig, *infra)
if err != nil {
return "", fmt.Errorf("error while fetching logs from container orchestrator: %w", err)
}
@ -394,12 +477,7 @@ func (o Orchestrator) getProvisionedInfra(
gitspaceConfig types.GitspaceConfig,
expectedStatus []enum.InfraStatus,
) (*types.Infrastructure, error) {
requiredGitspacePorts, err := o.getPortsRequiredForGitspace(gitspaceConfig, types.DevcontainerConfig{})
if err != nil {
return nil, fmt.Errorf("cannot get the ports required for gitspace: %w", err)
}
infra, err := o.infraProvisioner.Find(ctx, gitspaceConfig, requiredGitspacePorts)
infra, err := o.infraProvisioner.Find(ctx, gitspaceConfig)
if err != nil {
return nil, fmt.Errorf("cannot find the provisioned infra: %w", err)
}

View File

@ -0,0 +1,67 @@
// 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 utils
import (
"context"
"fmt"
"github.com/harness/gitness/app/gitspace/secret"
"github.com/harness/gitness/app/gitspace/secret/enum"
"github.com/harness/gitness/app/paths"
"github.com/harness/gitness/types"
gitnessenum "github.com/harness/gitness/types/enum"
)
func ResolveSecret(ctx context.Context, secretResolverFactory *secret.ResolverFactory, config types.GitspaceConfig) (*string, error) {
rootSpaceID, _, err := paths.DisectRoot(config.SpacePath)
if err != nil {
return nil, fmt.Errorf("unable to find root space id from space path: %s", config.SpacePath)
}
secretType := GetSecretType(config.GitspaceInstance.AccessType)
secretResolver, err := secretResolverFactory.GetSecretResolver(secretType)
if err != nil {
return nil, fmt.Errorf("could not find secret resolver for type: %s", config.GitspaceInstance.AccessType)
}
resolvedSecret, err := secretResolver.Resolve(ctx, secret.ResolutionContext{
UserIdentifier: config.GitspaceUser.Identifier,
GitspaceIdentifier: config.Identifier,
SecretRef: *config.GitspaceInstance.AccessKeyRef,
SpaceIdentifier: rootSpaceID,
})
if err != nil {
return nil, fmt.Errorf(
"could not resolve secret type: %s, ref: %s",
config.GitspaceInstance.AccessType,
*config.GitspaceInstance.AccessKeyRef,
)
}
return &resolvedSecret.SecretValue, nil
}
func GetSecretType(accessType gitnessenum.GitspaceAccessType) enum.SecretType {
secretType := enum.PasswordSecretType
switch accessType {
case gitnessenum.GitspaceAccessTypeUserCredentials:
secretType = enum.PasswordSecretType
case gitnessenum.GitspaceAccessTypeJWTToken:
secretType = enum.JWTSecretType
case gitnessenum.GitspaceAccessTypeSSHKey:
secretType = enum.SSHSecretType
}
return secretType
}

View File

@ -22,6 +22,7 @@ import (
"github.com/harness/gitness/app/gitspace/platformconnector"
"github.com/harness/gitness/app/gitspace/scm"
"github.com/harness/gitness/app/gitspace/secret"
"github.com/harness/gitness/app/store"
"github.com/google/wire"
)
@ -35,20 +36,22 @@ func ProvideOrchestrator(
scm *scm.SCM,
platformConnector platformconnector.PlatformConnector,
infraProvisioner infrastructure.InfraProvisioner,
containerOrchestrator container.Orchestrator,
containerOrchestratorFactor container.Factory,
reporter *events.Reporter,
config *Config,
ideFactory ide.Factory,
secretResolverFactory *secret.ResolverFactory,
gitspaceInstanceStore store.GitspaceInstanceStore,
) Orchestrator {
return NewOrchestrator(
scm,
platformConnector,
infraProvisioner,
containerOrchestrator,
containerOrchestratorFactor,
reporter,
config,
ideFactory,
secretResolverFactory,
gitspaceInstanceStore,
)
}

View File

@ -57,6 +57,7 @@ func (s *Service) handleGitspaceInfraResumeEvent(
}
defer func() {
// TODO: Update would not be needed for provision, stop and deprovision. Needs to be removed later.
updateErr := s.gitspaceSvc.UpdateInstance(ctxWithTimedOut, instance)
if updateErr != nil {
log.Err(updateErr).Msgf("failed to update gitspace instance")

View File

@ -0,0 +1,153 @@
// 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 gitspaceoperationsevent
import (
"context"
"fmt"
"time"
gitspaceEvents "github.com/harness/gitness/app/events/gitspace"
gitspaceOperationsEvents "github.com/harness/gitness/app/events/gitspaceoperations"
"github.com/harness/gitness/app/gitspace/orchestrator/container/response"
"github.com/harness/gitness/events"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
func (s *Service) handleGitspaceOperationsEvent(
ctx context.Context,
event *events.Event[*gitspaceOperationsEvents.GitspaceOperationsEventPayload],
) error {
logr := log.With().Str("event", string(event.Payload.Type)).Logger()
logr.Debug().Msg("Received gitspace operations event")
payload := event.Payload
ctxWithTimedOut, cancel := context.WithTimeout(ctx, time.Duration(s.config.TimeoutInMins)*time.Minute)
defer cancel()
config, fetchErr := s.getConfig(
ctxWithTimedOut, payload.Infra.SpacePath, payload.Infra.GitspaceConfigIdentifier)
if fetchErr != nil {
return fetchErr
}
instance := config.GitspaceInstance
if payload.Infra.GitspaceInstanceIdentifier != "" {
gitspaceInstance, err := s.gitspaceSvc.FindInstanceByIdentifier(
ctxWithTimedOut,
payload.Infra.GitspaceInstanceIdentifier,
payload.Infra.SpacePath,
)
if err != nil {
return fmt.Errorf("failed to fetch gitspace instance: %w", err)
}
instance = gitspaceInstance
config.GitspaceInstance = instance
}
defer func() {
updateErr := s.gitspaceSvc.UpdateInstance(ctxWithTimedOut, instance)
if updateErr != nil {
log.Err(updateErr).Msgf("failed to update gitspace instance")
}
}()
var err error
switch payload.Type {
case enum.GitspaceOperationsEventStart:
if config.GitspaceInstance.Identifier != payload.Infra.GitspaceInstanceIdentifier {
return fmt.Errorf("gitspace instance is not latest, stopping provisioning")
}
startResponse, ok := payload.Response.(*response.StartResponse)
if !ok {
return fmt.Errorf("failed to cast start response")
}
updatedInstance, handleResumeStartErr := s.orchestrator.FinishResumeStartGitspace(
ctxWithTimedOut,
*config,
payload.Infra,
startResponse,
)
if handleResumeStartErr != nil {
s.emitGitspaceConfigEvent(ctxWithTimedOut, config, enum.GitspaceEventTypeGitspaceActionStartFailed)
updatedInstance.ErrorMessage = handleResumeStartErr.ErrorMessage
err = fmt.Errorf("failed to finish resume start gitspace: %w", handleResumeStartErr.Error)
}
instance = &updatedInstance
case enum.GitspaceOperationsEventStop:
finishStopErr := s.orchestrator.FinishStopGitspaceContainer(ctxWithTimedOut, *config, payload.Infra)
if finishStopErr != nil {
s.emitGitspaceConfigEvent(ctxWithTimedOut, config, enum.GitspaceEventTypeGitspaceActionStopFailed)
instance.ErrorMessage = finishStopErr.ErrorMessage
err = fmt.Errorf("failed to finish trigger start gitspace: %w", finishStopErr.Error)
}
case enum.GitspaceOperationsEventDelete:
deleteResponse, ok := payload.Response.(*response.DeleteResponse)
if !ok {
return fmt.Errorf("failed to cast delete response")
}
finishStopAndRemoveErr := s.orchestrator.FinishStopAndRemoveGitspaceContainer(
ctxWithTimedOut,
*config,
payload.Infra,
deleteResponse.CanDeleteUserData,
)
if finishStopAndRemoveErr != nil {
s.emitGitspaceConfigEvent(ctxWithTimedOut, config, enum.GitspaceEventTypeGitspaceActionStopFailed)
instance.ErrorMessage = finishStopAndRemoveErr.ErrorMessage
err = fmt.Errorf("failed to finish trigger start gitspace: %w", finishStopAndRemoveErr.Error)
}
default:
return fmt.Errorf("unknown event type: %s", event.Payload.Type)
}
if err != nil {
log.Err(err).Msgf("error while handling gitspace operations event")
}
return nil
}
func (s *Service) getConfig(
ctx context.Context,
spaceRef string,
identifier string,
) (*types.GitspaceConfig, error) {
config, err := s.gitspaceSvc.FindWithLatestInstance(ctx, spaceRef, 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 gitspaceoperationsevent
import (
"context"
"fmt"
"time"
gitspaceevents "github.com/harness/gitness/app/events/gitspace"
gitspaceoperationsevents "github.com/harness/gitness/app/events/gitspaceoperations"
"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 groupGitspaceOperationsEvents = "gitness:gitspaceoperations"
type Service struct {
config *gitspaceevent.Config
orchestrator orchestrator.Orchestrator
gitspaceSvc *gitspace.Service
eventReporter *gitspaceevents.Reporter
}
func NewService(
ctx context.Context,
config *gitspaceevent.Config,
gitspaceOperationsEventReaderFactory *events.ReaderFactory[*gitspaceoperationsevents.Reader],
orchestrator orchestrator.Orchestrator,
gitspaceSvc *gitspace.Service,
eventReporter *gitspaceevents.Reporter,
) (*Service, error) {
if err := config.Sanitize(); err != nil {
return nil, fmt.Errorf("provided gitspace operations event service config is invalid: %w", err)
}
service := &Service{
config: config,
orchestrator: orchestrator,
gitspaceSvc: gitspaceSvc,
eventReporter: eventReporter,
}
_, err := gitspaceOperationsEventReaderFactory.Launch(ctx, groupGitspaceOperationsEvents, config.EventReaderName,
func(r *gitspaceoperationsevents.Reader) error {
var idleTimeout = time.Duration(config.TimeoutInMins) * time.Minute
r.Configure(
stream.WithConcurrency(config.Concurrency),
stream.WithHandlerOptions(
stream.WithIdleTimeout(idleTimeout),
stream.WithMaxRetries(config.MaxRetries),
))
_ = r.RegisterGitspaceOperationsEvent(service.handleGitspaceOperationsEvent)
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to launch gitspace operations 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 gitspaceoperationsevent
import (
"context"
gitspaceevents "github.com/harness/gitness/app/events/gitspace"
gitspaceoperationsevents "github.com/harness/gitness/app/events/gitspaceoperations"
"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[*gitspaceoperationsevents.Reader],
orchestrator orchestrator.Orchestrator,
gitspaceSvc *gitspace.Service,
eventReporter *gitspaceevents.Reporter,
) (*Service, error) {
return NewService(
ctx,
config,
gitspaceInfraEventReaderFactory,
orchestrator,
gitspaceSvc,
eventReporter,
)
}

View File

@ -17,6 +17,7 @@ package gitspaceservice
import (
"github.com/harness/gitness/app/services/gitspace"
"github.com/harness/gitness/app/services/gitspaceinfraevent"
"github.com/harness/gitness/app/services/gitspaceoperationsevent"
"github.com/harness/gitness/app/services/infraprovider"
"github.com/google/wire"
@ -26,4 +27,5 @@ var WireSet = wire.NewSet(
gitspace.WireSet,
gitspaceinfraevent.WireSet,
infraprovider.WireSet,
gitspaceoperationsevent.WireSet,
)

View File

@ -19,6 +19,7 @@ import (
"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/gitspaceoperationsevent"
"github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/services/instrument"
"github.com/harness/gitness/app/services/keywordsearch"
@ -57,10 +58,11 @@ type Services struct {
}
type GitspaceServices struct {
GitspaceEvent *gitspaceevent.Service
infraProvider *infraprovider.Service
gitspace *gitspace.Service
gitspaceInfraEventSvc *gitspaceinfraevent.Service
GitspaceEvent *gitspaceevent.Service
infraProvider *infraprovider.Service
gitspace *gitspace.Service
gitspaceInfraEventSvc *gitspaceinfraevent.Service
gitspaceOperationsEventSvc *gitspaceoperationsevent.Service
}
func ProvideGitspaceServices(
@ -68,12 +70,14 @@ func ProvideGitspaceServices(
infraProviderSvc *infraprovider.Service,
gitspaceSvc *gitspace.Service,
gitspaceInfraEventSvc *gitspaceinfraevent.Service,
gitspaceOperationsEventSvc *gitspaceoperationsevent.Service,
) *GitspaceServices {
return &GitspaceServices{
GitspaceEvent: gitspaceEventSvc,
infraProvider: infraProviderSvc,
gitspace: gitspaceSvc,
gitspaceInfraEventSvc: gitspaceInfraEventSvc,
GitspaceEvent: gitspaceEventSvc,
infraProvider: infraProviderSvc,
gitspace: gitspaceSvc,
gitspaceInfraEventSvc: gitspaceInfraEventSvc,
gitspaceOperationsEventSvc: gitspaceOperationsEventSvc,
}
}

View File

@ -733,6 +733,7 @@ type (
Find(ctx context.Context, id int64) (*types.GitspaceInstance, error)
// FindByIdentifier returns a gitspace instance given a gitspace instance identifier from the datastore.
// TODO: Fix this. It needs to use space ID as well.
FindByIdentifier(ctx context.Context, identifier string) (*types.GitspaceInstance, error)
// FindLatestByGitspaceConfigID returns the latest gitspace instance given a gitspace config ID from the datastore.

View File

@ -0,0 +1 @@
ALTER TABLE delegate_provision_details DROP COLUMN dpdeta_task_details;

View File

@ -0,0 +1 @@
ALTER TABLE delegate_provision_details ADD COLUMN dpdeta_task_details jsonb;

View File

@ -0,0 +1,21 @@
DROP TABLE delegate_provision_details;
CREATE TABLE delegate_provision_details
(
dpdeta_id INTEGER PRIMARY KEY AUTOINCREMENT,
dpdeta_task_id TEXT NOT NULL,
dpdeta_action_type TEXT NOT NULL,
dpdeta_gitspace_instance_id INTEGER NOT NULL,
dpdeta_space_id INTEGER NOT NULL,
dpdeta_agent_port INTEGER NOT NULL,
dpdeta_created BIGINT NOT NULL,
dpdeta_updated BIGINT NOT NULL,
CONSTRAINT fk_dpdeta_gitspace_instance_id FOREIGN KEY (dpdeta_gitspace_instance_id)
REFERENCES gitspaces (gits_id) MATCH SIMPLE
ON UPDATE NO ACTION
CONSTRAINT fk_dpdeta_space_id FOREIGN KEY (dpdeta_space_id)
REFERENCES spaces (space_id) MATCH SIMPLE
ON UPDATE NO ACTION
);
CREATE UNIQUE INDEX delegate_provision_details_task_id_space_id ON delegate_provision_details (dpdeta_task_id, dpdeta_space_id);

View File

@ -0,0 +1 @@
ALTER TABLE delegate_provision_details ADD COLUMN dpdeta_task_details TEXT;

View File

@ -56,6 +56,7 @@ import (
gitevents "github.com/harness/gitness/app/events/git"
gitspaceevents "github.com/harness/gitness/app/events/gitspace"
gitspaceinfraevents "github.com/harness/gitness/app/events/gitspaceinfra"
gitspaceoperationsevents "github.com/harness/gitness/app/events/gitspaceoperations"
pipelineevents "github.com/harness/gitness/app/events/pipeline"
pullreqevents "github.com/harness/gitness/app/events/pullreq"
repoevents "github.com/harness/gitness/app/events/repo"
@ -270,6 +271,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
ide.WireSet,
gitspaceinfraevents.WireSet,
gitspaceservice.WireSet,
gitspaceoperationsevents.WireSet,
cliserver.ProvideGitspaceInfraProvisionerConfig,
cliserver.ProvideIDEVSCodeConfig,
cliserver.ProvideIDEJetBrainsConfig,

View File

@ -42,11 +42,12 @@ import (
"github.com/harness/gitness/app/auth/authz"
"github.com/harness/gitness/app/bootstrap"
"github.com/harness/gitness/app/connector"
events7 "github.com/harness/gitness/app/events/git"
events8 "github.com/harness/gitness/app/events/git"
events3 "github.com/harness/gitness/app/events/gitspace"
events4 "github.com/harness/gitness/app/events/gitspaceinfra"
events5 "github.com/harness/gitness/app/events/pipeline"
events6 "github.com/harness/gitness/app/events/pullreq"
events5 "github.com/harness/gitness/app/events/gitspaceoperations"
events6 "github.com/harness/gitness/app/events/pipeline"
events7 "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"
@ -76,6 +77,7 @@ import (
"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/gitspaceoperationsevent"
"github.com/harness/gitness/app/services/importer"
infraprovider2 "github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/services/instrument"
@ -121,7 +123,7 @@ import (
"github.com/harness/gitness/pubsub"
api2 "github.com/harness/gitness/registry/app/api"
"github.com/harness/gitness/registry/app/api/router"
events8 "github.com/harness/gitness/registry/app/events"
events9 "github.com/harness/gitness/registry/app/events"
"github.com/harness/gitness/registry/app/pkg"
"github.com/harness/gitness/registry/app/pkg/docker"
"github.com/harness/gitness/registry/app/pkg/filemanager"
@ -332,7 +334,12 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
if err != nil {
return nil, err
}
containerOrchestrator := container.ProvideEmbeddedDockerOrchestrator(dockerClientFactory, statefulLogger, runargProvider)
reporter3, err := events5.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
embeddedDockerOrchestrator := container.ProvideEmbeddedDockerOrchestrator(dockerClientFactory, statefulLogger, runargProvider, reporter3)
containerFactory := container.ProvideContainerOrchestratorFactory(embeddedDockerOrchestrator)
orchestratorConfig := server.ProvideGitspaceOrchestratorConfig(config)
vsCodeConfig := server.ProvideIDEVSCodeConfig(config)
vsCode := ide.ProvideVSCodeService(vsCodeConfig)
@ -343,15 +350,15 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
ideFactory := ide.ProvideIDEFactory(vsCode, vsCodeWeb, v)
passwordResolver := secret.ProvidePasswordResolver()
resolverFactory := secret.ProvideResolverFactory(passwordResolver)
orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, platformConnector, infraProvisioner, containerOrchestrator, eventsReporter, orchestratorConfig, ideFactory, resolverFactory)
orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, platformConnector, infraProvisioner, containerFactory, eventsReporter, orchestratorConfig, ideFactory, resolverFactory, gitspaceInstanceStore)
gitspaceService := gitspace.ProvideGitspace(transactor, gitspaceConfigStore, gitspaceInstanceStore, eventsReporter, gitspaceEventStore, spaceFinder, infraproviderService, orchestratorOrchestrator, scmSCM, config)
usageMetricStore := database.ProvideUsageMetricStore(db)
spaceController := space.ProvideController(config, transactor, provider, streamer, spaceIdentifier, authorizer, spacePathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore, listService, spaceFinder, repository, exporterRepository, resourceLimiter, publicaccessService, auditService, gitspaceService, labelService, instrumentService, executionStore, rulesService, usageMetricStore, repoIdentifier)
reporter3, err := events5.ProvideReporter(eventsSystem)
reporter4, err := events6.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
pipelineController := pipeline.ProvideController(triggerStore, authorizer, pipelineStore, reporter3, repoFinder)
pipelineController := pipeline.ProvideController(triggerStore, authorizer, pipelineStore, reporter4, repoFinder)
secretController := secret2.ProvideController(encrypter, secretStore, authorizer, spaceFinder)
triggerController := trigger.ProvideController(authorizer, triggerStore, pipelineStore, repoFinder)
scmService := connector.ProvideSCMConnectorHandler(secretStore)
@ -365,25 +372,25 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
pullReqReviewerStore := database.ProvidePullReqReviewerStore(db, principalInfoCache)
userGroupReviewersStore := database.ProvideUserGroupReviewerStore(db, principalInfoCache, userGroupStore)
pullReqFileViewStore := database.ProvidePullReqFileViewStore(db)
reporter4, err := events6.ProvideReporter(eventsSystem)
reporter5, err := events7.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
migrator := codecomments.ProvideMigrator(gitInterface)
readerFactory, err := events7.ProvideReaderFactory(eventsSystem)
readerFactory, err := events8.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
eventsReaderFactory, err := events6.ProvideReaderFactory(eventsSystem)
eventsReaderFactory, err := events7.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
pullreqService, err := pullreq.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter4, gitInterface, repoFinder, repoStore, pullReqStore, pullReqActivityStore, principalInfoCache, codeCommentView, migrator, pullReqFileViewStore, pubSub, provider, streamer)
pullreqService, err := pullreq.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter5, gitInterface, repoFinder, repoStore, pullReqStore, pullReqActivityStore, principalInfoCache, codeCommentView, migrator, pullReqFileViewStore, pubSub, provider, streamer)
if err != nil {
return nil, err
}
pullReq := migrate.ProvidePullReqImporter(provider, gitInterface, principalStore, spaceStore, repoStore, pullReqStore, pullReqActivityStore, labelStore, labelValueStore, pullReqLabelAssignmentStore, repoFinder, transactor, mutexManager)
pullreqController := pullreq2.ProvideController(transactor, provider, authorizer, auditService, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, userGroupStore, userGroupReviewersStore, principalInfoCache, pullReqFileViewStore, membershipStore, checkStore, gitInterface, repoFinder, reporter4, migrator, pullreqService, listService, protectionManager, streamer, codeownersService, lockerLocker, pullReq, labelService, instrumentService, searchService)
pullreqController := pullreq2.ProvideController(transactor, provider, authorizer, auditService, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, userGroupStore, userGroupReviewersStore, principalInfoCache, pullReqFileViewStore, membershipStore, checkStore, gitInterface, repoFinder, reporter5, migrator, pullreqService, listService, protectionManager, streamer, codeownersService, lockerLocker, pullReq, labelService, instrumentService, searchService)
webhookConfig := server.ProvideWebhookConfig(config)
webhookStore := database.ProvideWebhookStore(db)
webhookExecutionStore := database.ProvideWebhookExecutionStore(db)
@ -395,7 +402,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
}
preprocessor := webhook2.ProvidePreprocessor()
webhookController := webhook2.ProvideController(authorizer, spaceFinder, repoFinder, webhookService, encrypter, preprocessor)
reporter5, err := events7.ProvideReporter(eventsSystem)
reporter6, err := events8.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
@ -412,7 +419,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
return nil, err
}
lfsObjectStore := database.ProvideLFSObjectStore(db)
githookController := githook.ProvideController(authorizer, principalStore, repoStore, repoFinder, reporter5, reporter, gitInterface, pullReqStore, provider, protectionManager, clientFactory, resourceLimiter, settingsService, preReceiveExtender, updateExtender, postReceiveExtender, streamer, lfsObjectStore)
githookController := githook.ProvideController(authorizer, principalStore, repoStore, repoFinder, reporter6, reporter, gitInterface, pullReqStore, provider, protectionManager, clientFactory, resourceLimiter, settingsService, preReceiveExtender, updateExtender, postReceiveExtender, streamer, lfsObjectStore)
serviceaccountController := serviceaccount.NewController(principalUID, authorizer, principalStore, spaceStore, repoStore, tokenStore)
principalController := principal.ProvideController(principalStore, authorizer)
usergroupController := usergroup2.ProvideController(userGroupStore, spaceStore, authorizer, searchService)
@ -457,11 +464,11 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
layerRepository := database2.ProvideLayerDao(db, mediaTypesRepository)
eventReporter := docker.ProvideReporter()
ociImageIndexMappingRepository := database2.ProvideOCIImageIndexMappingDao(db)
reporter6, err := events8.ProvideArtifactReporter(eventsSystem)
reporter7, err := events9.ProvideArtifactReporter(eventsSystem)
if err != nil {
return nil, err
}
manifestService := docker.ManifestServiceProvider(registryRepository, manifestRepository, blobRepository, mediaTypesRepository, manifestReferenceRepository, tagRepository, imageRepository, artifactRepository, layerRepository, gcService, transactor, eventReporter, spaceFinder, ociImageIndexMappingRepository, reporter6, provider)
manifestService := docker.ManifestServiceProvider(registryRepository, manifestRepository, blobRepository, mediaTypesRepository, manifestReferenceRepository, tagRepository, imageRepository, artifactRepository, layerRepository, gcService, transactor, eventReporter, spaceFinder, ociImageIndexMappingRepository, reporter7, provider)
registryBlobRepository := database2.ProvideRegistryBlobDao(db)
bandwidthStatRepository := database2.ProvideBandwidthStatDao(db)
downloadStatRepository := database2.ProvideDownloadStatDao(db)
@ -481,7 +488,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
cleanupPolicyRepository := database2.ProvideCleanupPolicyDao(db, transactor)
webhooksRepository := database2.ProvideWebhookDao(db)
webhooksExecutionRepository := database2.ProvideWebhookExecutionDao(db)
readerFactory2, err := events8.ProvideReaderFactory(eventsSystem)
readerFactory2, err := events9.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
@ -513,7 +520,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
serverServer := server2.ProvideServer(config, routerRouter)
publickeyService := publickey.ProvidePublicKey(publicKeyStore, principalInfoCache)
sshServer := ssh.ProvideServer(config, publickeyService, repoController, lfsController)
executionManager := manager.ProvideExecutionManager(config, executionStore, pipelineStore, provider, streamer, fileService, converterService, logStore, logStream, checkStore, repoStore, schedulerScheduler, secretStore, stageStore, stepStore, principalStore, publicaccessService, reporter3)
executionManager := manager.ProvideExecutionManager(config, executionStore, pipelineStore, provider, streamer, fileService, converterService, logStore, logStream, checkStore, repoStore, schedulerScheduler, secretStore, stageStore, stepStore, principalStore, publicaccessService, reporter4)
client := manager.ProvideExecutionClient(executionManager, provider, config)
resolverManager := resolver.ProvideResolver(config, pluginStore, templateStore, executionStore, repoStore)
runtimeRunner, err := runner.ProvideExecutionRunner(config, client, resolverManager)
@ -576,7 +583,15 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
if err != nil {
return nil, err
}
gitspaceServices := services.ProvideGitspaceServices(gitspaceeventService, infraproviderService, gitspaceService, gitspaceinfraeventService)
readerFactory6, err := events5.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
gitspaceoperationseventService, err := gitspaceoperationsevent.ProvideService(ctx, gitspaceeventConfig, readerFactory6, orchestratorOrchestrator, gitspaceService, eventsReporter)
if err != nil {
return nil, err
}
gitspaceServices := services.ProvideGitspaceServices(gitspaceeventService, infraproviderService, gitspaceService, gitspaceinfraeventService, gitspaceoperationseventService)
consumer, err := instrument.ProvideGitConsumer(ctx, config, readerFactory, repoStore, principalInfoCache, instrumentService)
if err != nil {
return nil, err

View File

@ -20,6 +20,8 @@ import (
"encoding/gob"
"fmt"
"time"
"github.com/harness/gitness/app/gitspace/orchestrator/container/response"
)
// GenericReporter represents an event reporter that supports sending typesafe messages
@ -46,6 +48,8 @@ func ReporterSendEvent[T interface{}](reporter *GenericReporter, ctx context.Con
buff := &bytes.Buffer{}
encoder := gob.NewEncoder(buff)
gob.Register((*response.StartResponse)(nil))
gob.Register((*response.DeleteResponse)(nil))
if err := encoder.Encode(&event); err != nil {
return "", fmt.Errorf("failed to encode payload: %w", err)

View File

@ -59,7 +59,6 @@ func (d DockerProvider) Provision(
_ int,
requiredGitspacePorts []types.GitspacePort,
inputParameters []types.InfraProviderParameter,
_ map[string]any,
) error {
dockerClient, err := d.dockerClientFactory.NewDockerClient(ctx, types.Infrastructure{
ProviderType: enum.InfraProviderTypeDocker,
@ -125,11 +124,7 @@ func (d DockerProvider) Find(
spaceID int64,
spacePath string,
gitspaceConfigIdentifier string,
_ string,
_ int,
_ []types.GitspacePort,
inputParameters []types.InfraProviderParameter,
_ map[string]any,
) (*types.Infrastructure, error) {
dockerClient, err := d.dockerClientFactory.NewDockerClient(ctx, types.Infrastructure{
ProviderType: enum.InfraProviderTypeDocker,
@ -160,6 +155,13 @@ func (d DockerProvider) Find(
return infrastructure, nil
}
func (d DockerProvider) FindInfraStatus(_ context.Context,
_ string,
_ string,
_ []types.InfraProviderParameter) (*enum.InfraStatus, error) {
return nil, nil //nolint:nilnil
}
// Stop is NOOP as this provider uses already running docker engine. It does not stop the docker engine.
func (d DockerProvider) Stop(ctx context.Context, infra types.Infrastructure) error {
infra.Status = enum.InfraStatusDestroyed

View File

@ -32,7 +32,6 @@ type InfraProvider interface {
agentPort int,
requiredGitspacePorts []types.GitspacePort,
inputParameters []types.InfraProviderParameter,
configMetadata map[string]any,
) error
// Find finds infrastructure provisioned against a gitspace.
@ -41,13 +40,16 @@ type InfraProvider interface {
spaceID int64,
spacePath string,
gitspaceConfigIdentifier string,
gitspaceInstanceIdentifier string,
agentPort int,
requiredGitspacePorts []types.GitspacePort,
inputParameters []types.InfraProviderParameter,
configMetadata map[string]any,
) (*types.Infrastructure, error)
FindInfraStatus(
ctx context.Context,
gitspaceConfigIdentifier string,
gitspaceInstanceIdentifier string,
inputParameters []types.InfraProviderParameter,
) (*enum.InfraStatus, error)
// Stop frees up the resources allocated against a gitspace, which can be freed.
Stop(ctx context.Context, infra types.Infrastructure) error

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 GitspaceOperationsEvent string
func (GitspaceOperationsEvent) Enum() []interface{} {
return toInterfaceSlice(gitspaceOperationsEvent)
}
var gitspaceOperationsEvent = []GitspaceOperationsEvent{
GitspaceOperationsEventStart, GitspaceOperationsEventStop, GitspaceOperationsEventDelete,
}
const (
GitspaceOperationsEventStart GitspaceOperationsEvent = "start"
GitspaceOperationsEventStop GitspaceOperationsEvent = "stop"
GitspaceOperationsEventDelete GitspaceOperationsEvent = "delete"
)

View File

@ -48,6 +48,10 @@ type InstanceInfo struct {
PoolName string `json:"pool_name"`
Zone string `json:"zone"`
StorageIdentifier string `json:"storage_identifier"`
CAKey []byte `json:"ca_key"`
CACert []byte `json:"ca_cert"`
TLSKey []byte `json:"tls_key"`
TLSCert []byte `json:"tls_cert"`
}
type Infrastructure struct {
@ -65,6 +69,8 @@ type Infrastructure struct {
ProviderType enum.InfraProviderType
// InputParameters which are required by the provider to provision the infra.
InputParameters []InfraProviderParameter
// ConfigMetadata contains the infra config metadata required by the infra provider to provision the infra.
ConfigMetadata map[string]any
// Status of the infra.
Status enum.InfraStatus