feat: [CDE-573]: refactor to reduce number of abstractions and modules. (#3203)

* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
* feat: [CDE-573]: refactor to reduce number of abstractions and modules.
BT-10437
Ansuman Satapathy 2024-12-26 08:58:41 +00:00 committed by Harness
parent d89825d317
commit cafa55b2e5
27 changed files with 325 additions and 649 deletions

View File

@ -1,70 +0,0 @@
// 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 infrastructure
import (
"context"
"fmt"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
func (i infraProvisioner) TriggerCleanupInstance(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
) error {
infraProviderEntity, err := i.getConfigFromResource(ctx, gitspaceConfig.InfraProviderResource)
if err != nil {
return err
}
infraProvider, err := i.getInfraProvider(infraProviderEntity.Type)
if err != nil {
return err
}
return infraProvider.CleanupInstanceResources(ctx, infra)
}
func (i infraProvisioner) ResumeCleanupInstance(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
cleanedInfra types.Infrastructure,
) error {
infraProvider, err := i.getInfraProvider(cleanedInfra.ProviderType)
if err != nil {
return err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew {
return i.resumeCleanupForNewProvisioning(ctx, gitspaceConfig, cleanedInfra)
}
return nil
}
func (i infraProvisioner) resumeCleanupForNewProvisioning(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
cleanedInfra types.Infrastructure,
) error {
err := i.updateInfraProvisionedRecord(ctx, gitspaceConfig, cleanedInfra)
if err != nil {
return fmt.Errorf("unable to update provisioned record after cleanup: %w", err)
}
return nil
}

View File

@ -1,116 +0,0 @@
// 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 infrastructure
import (
"context"
"fmt"
"github.com/harness/gitness/infraprovider"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
func (i infraProvisioner) TriggerDeprovision(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
canDeleteUserData bool,
) error {
infraProviderEntity, err := i.getConfigFromResource(ctx, gitspaceConfig.InfraProviderResource)
if err != nil {
return err
}
infraProvider, err := i.getInfraProvider(infraProviderEntity.Type)
if err != nil {
return err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew {
return i.triggerDeprovisionForNewProvisioning(ctx, infraProvider, gitspaceConfig, infra, canDeleteUserData)
}
return i.triggerDeprovisionForExistingProvisioning(ctx, infraProvider, infra, canDeleteUserData)
}
func (i infraProvisioner) triggerDeprovisionForNewProvisioning(
ctx context.Context,
infraProvider infraprovider.InfraProvider,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
canDeleteUserData bool,
) error {
infraProvisionedLatest, err := i.infraProvisionedStore.FindLatestByGitspaceInstanceID(
ctx, gitspaceConfig.SpaceID, gitspaceConfig.GitspaceInstance.ID)
if err != nil {
return fmt.Errorf(
"could not find latest infra provisioned entity for instance %d: %w",
gitspaceConfig.GitspaceInstance.ID, err)
}
if infraProvisionedLatest.InfraStatus == enum.InfraStatusDestroyed {
return nil
}
err = infraProvider.Deprovision(ctx, infra, canDeleteUserData)
if err != nil {
return fmt.Errorf("unable to trigger deprovision infra %+v: %w", infra, err)
}
return err
}
func (i infraProvisioner) triggerDeprovisionForExistingProvisioning(
ctx context.Context,
infraProvider infraprovider.InfraProvider,
infra types.Infrastructure,
canDeleteUserData bool,
) error {
err := infraProvider.Deprovision(ctx, infra, canDeleteUserData)
if err != nil {
return fmt.Errorf("unable to trigger deprovision infra %+v: %w", infra, err)
}
return err
}
func (i infraProvisioner) ResumeDeprovision(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra types.Infrastructure,
) error {
infraProvider, err := i.getInfraProvider(deprovisionedInfra.ProviderType)
if err != nil {
return err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew {
return i.resumeDeprovisionForNewProvisioning(ctx, gitspaceConfig, deprovisionedInfra)
}
return nil
}
func (i infraProvisioner) resumeDeprovisionForNewProvisioning(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra types.Infrastructure,
) error {
err := i.updateInfraProvisionedRecord(ctx, gitspaceConfig, deprovisionedInfra)
if err != nil {
return fmt.Errorf("unable to update provisioned record after deprovisioning: %w", err)
}
return nil
}

View File

@ -24,7 +24,8 @@ import (
"github.com/harness/gitness/types/enum"
)
func (i infraProvisioner) Find(
// Find finds the provisioned infra resources for the gitspace instance.
func (i InfraProvisioner) Find(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
requiredGitspacePorts []types.GitspacePort,
@ -71,7 +72,7 @@ func (i infraProvisioner) Find(
}
}
gitspaceScheme, err := i.getGitspaceScheme(gitspaceConfig.IDE, infraProviderResource.Metadata["gitspace_scheme"])
gitspaceScheme, err := getGitspaceScheme(gitspaceConfig.IDE, infraProviderResource.Metadata["gitspace_scheme"])
if err != nil {
return nil, fmt.Errorf("failed to get gitspace_scheme: %w", err)
}
@ -79,12 +80,12 @@ func (i infraProvisioner) Find(
return infra, nil
}
func (i infraProvisioner) paramsForProvisioningTypeNew(
func (i InfraProvisioner) paramsForProvisioningTypeNew(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
) ([]types.InfraProviderParameter, error) {
infraProvisionedLatest, err := i.infraProvisionedStore.FindLatestByGitspaceInstanceID(
ctx, gitspaceConfig.SpaceID, gitspaceConfig.GitspaceInstance.ID)
ctx, gitspaceConfig.GitspaceInstance.ID)
if err != nil {
return nil, fmt.Errorf(
"could not find latest infra provisioned entity for instance %d: %w",
@ -101,7 +102,16 @@ func (i infraProvisioner) paramsForProvisioningTypeNew(
return allParams, nil
}
func (i infraProvisioner) paramsForProvisioningTypeExisting(
func deserializeInfraProviderParams(in string) ([]types.InfraProviderParameter, error) {
var parameters []types.InfraProviderParameter
err := json.Unmarshal([]byte(in), &parameters)
if err != nil {
return nil, fmt.Errorf("unable to unmarshal infra provider params %+v: %w", in, err)
}
return parameters, nil
}
func (i InfraProvisioner) paramsForProvisioningTypeExisting(
ctx context.Context,
infraProviderResource types.InfraProviderResource,
infraProvider infraprovider.InfraProvider,
@ -114,7 +124,7 @@ func (i infraProvisioner) paramsForProvisioningTypeExisting(
return allParams, nil
}
func (i infraProvisioner) getGitspaceScheme(ideType enum.IDEType, gitspaceSchemeFromMetadata string) (string, error) {
func getGitspaceScheme(ideType enum.IDEType, gitspaceSchemeFromMetadata string) (string, error) {
switch ideType {
case enum.IDETypeVSCodeWeb:
return gitspaceSchemeFromMetadata, nil
@ -127,13 +137,12 @@ func (i infraProvisioner) getGitspaceScheme(ideType enum.IDEType, gitspaceScheme
}
}
func (i infraProvisioner) getInfraFromStoredInfo(
func (i InfraProvisioner) getInfraFromStoredInfo(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
) (*types.Infrastructure, error) {
infraProvisioned, err := i.infraProvisionedStore.FindLatestByGitspaceInstanceID(
ctx,
gitspaceConfig.SpaceID,
gitspaceConfig.GitspaceInstance.ID,
)
if err != nil {
@ -146,3 +155,103 @@ func (i infraProvisioner) getInfraFromStoredInfo(
}
return &infra, nil
}
// Methods to find infra provider resources.
func (i InfraProvisioner) getConfigFromResource(
ctx context.Context,
infraProviderResource types.InfraProviderResource,
) (*types.InfraProviderConfig, error) {
config, err := i.infraProviderConfigStore.Find(ctx, infraProviderResource.InfraProviderConfigID)
if err != nil {
return nil, fmt.Errorf(
"unable to get infra provider details for ID %d: %w",
infraProviderResource.InfraProviderConfigID, err)
}
return config, nil
}
func (i InfraProvisioner) getInfraProvider(
infraProviderType enum.InfraProviderType,
) (infraprovider.InfraProvider, error) {
infraProvider, err := i.providerFactory.GetInfraProvider(infraProviderType)
if err != nil {
return nil, fmt.Errorf("unable to get infra provider of type %v: %w", infraProviderType, err)
}
return infraProvider, nil
}
func (i InfraProvisioner) getAllParamsFromDB(
ctx context.Context,
infraProviderResource types.InfraProviderResource,
infraProvider infraprovider.InfraProvider,
) ([]types.InfraProviderParameter, error) {
var allParams []types.InfraProviderParameter
templateParams, err := i.getTemplateParams(ctx, infraProvider, infraProviderResource)
if err != nil {
return nil, err
}
allParams = append(allParams, templateParams...)
params := i.paramsFromResource(infraProviderResource, infraProvider)
allParams = append(allParams, params...)
return allParams, nil
}
func (i InfraProvisioner) getTemplateParams(
ctx context.Context,
infraProvider infraprovider.InfraProvider,
infraProviderResource types.InfraProviderResource,
) ([]types.InfraProviderParameter, error) {
var params []types.InfraProviderParameter
templateParams := infraProvider.TemplateParams()
for _, param := range templateParams {
key := param.Name
if infraProviderResource.Metadata[key] != "" {
templateIdentifier := infraProviderResource.Metadata[key]
template, err := i.infraProviderTemplateStore.FindByIdentifier(
ctx, infraProviderResource.SpaceID, templateIdentifier)
if err != nil {
return nil, fmt.Errorf("unable to get template params for ID %s: %w",
infraProviderResource.Metadata[key], err)
}
params = append(params, types.InfraProviderParameter{
Name: key,
Value: template.Data,
})
}
}
return params, nil
}
func (i InfraProvisioner) paramsFromResource(
infraProviderResource types.InfraProviderResource,
infraProvider infraprovider.InfraProvider,
) []types.InfraProviderParameter {
// NOTE: templateParamsMap is required to filter out template params since their values have already been fetched
// and we dont need the template identifiers, which are the values for template params in the resource Metadata.
templateParamsMap := make(map[string]bool)
for _, templateParam := range infraProvider.TemplateParams() {
templateParamsMap[templateParam.Name] = true
}
params := make([]types.InfraProviderParameter, 0)
for key, value := range infraProviderResource.Metadata {
if key == "" || value == "" || templateParamsMap[key] {
continue
}
params = append(params, types.InfraProviderParameter{
Name: key,
Value: value,
})
}
return params
}

View File

@ -0,0 +1,85 @@
// 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 infrastructure
import (
"context"
"encoding/json"
"fmt"
"strconv"
"time"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
// PostInfraEventComplete performs action taken on completion of the submitted infra task which can be
// success or failure. It stores the infrastructure details in the db depending on the provisioning type.
func (i InfraProvisioner) PostInfraEventComplete(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
eventType enum.InfraEvent,
) error {
infraProvider, err := i.getInfraProvider(infra.ProviderType)
if err != nil {
return err
}
if infraProvider.ProvisioningType() != enum.InfraProvisioningTypeNew {
return nil
}
switch eventType {
case enum.InfraEventProvision,
enum.InfraEventDeprovision,
enum.InfraEventStop,
enum.InfraEventCleanup:
return i.updateInfraProvisioned(ctx, gitspaceConfig.GitspaceInstance.ID, infra)
default:
return fmt.Errorf("unsupported event type: %s", eventType)
}
}
func (i InfraProvisioner) updateInfraProvisioned(
ctx context.Context,
gitspaceInstanceID int64,
infrastructure types.Infrastructure,
) error {
infraProvisionedLatest, err := i.infraProvisionedStore.FindLatestByGitspaceInstanceID(ctx, gitspaceInstanceID)
if err != nil {
return fmt.Errorf(
"could not find latest infra provisioned entity for instance %d: %w", gitspaceInstanceID, err)
}
responseMetadata, err := json.Marshal(infrastructure)
if err != nil {
return fmt.Errorf("unable to marshal infra object %+v: %w", responseMetadata, err)
}
responseMetaDataJSON := string(responseMetadata)
infraProvisionedLatest.InfraStatus = infrastructure.Status
infraProvisionedLatest.ServerHostIP = infrastructure.AgentHost
infraProvisionedLatest.ServerHostPort = strconv.Itoa(infrastructure.AgentPort)
infraProvisionedLatest.ProxyHost = infrastructure.ProxyAgentHost
infraProvisionedLatest.ProxyPort = int32(infrastructure.ProxyAgentPort)
infraProvisionedLatest.ResponseMetadata = &responseMetaDataJSON
infraProvisionedLatest.Updated = time.Now().UnixMilli()
err = i.infraProvisionedStore.Update(ctx, infraProvisionedLatest)
if err != nil {
return fmt.Errorf("unable to update infraProvisioned %d: %w", infraProvisionedLatest.ID, err)
}
return nil
}

View File

@ -1,92 +0,0 @@
// 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 infrastructure
import (
"context"
"github.com/harness/gitness/types"
)
// TODO Check if the interface can be discarded
type InfraProvisioner interface {
// TriggerProvision triggers the provisionining of infra resources using the infraProviderResource with different
// infra providers.
TriggerProvision(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
requiredGitspacePorts []types.GitspacePort,
) error
// ResumeProvision stores the provisioned infra details in the db depending on the provisioning type.
ResumeProvision(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
provisionedInfra types.Infrastructure,
) error
// TriggerStop triggers deprovisioning of those resources which can be stopped without losing the Gitspace data.
TriggerStop(
ctx context.Context,
infraProviderResource types.InfraProviderResource,
infra types.Infrastructure,
) error
// ResumeStop stores the deprovisioned infra details in the db depending on the provisioning type.
ResumeStop(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra types.Infrastructure,
) error
// TriggerDeprovision triggers deprovisionign of resources created for a Gitspace.
// canDeleteUserData = true -> triggers deprovision of all resources
// canDeleteUserData = false -> triggers deprovision of all resources except storage associated to user data.
TriggerDeprovision(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
canDeleteUserData bool,
) error
// ResumeDeprovision stores the deprovisioned infra details in the db depending on the provisioning type.
ResumeDeprovision(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra types.Infrastructure,
) error
// TriggerCleanupInstance cleans up resources exclusive for a gitspace instance
TriggerCleanupInstance(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
infra types.Infrastructure,
) error
// ResumeCleanupInstance stores the deprovisioned infra details in the db depending on the provisioning type.
ResumeCleanupInstance(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra types.Infrastructure,
) error
// Find finds the provisioned infra resources for the gitspace instance.
Find(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
requiredGitspacePorts []types.GitspacePort,
) (*types.Infrastructure, error)
}

View File

@ -1,219 +0,0 @@
// 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 infrastructure
import (
"context"
"encoding/json"
"fmt"
"strconv"
"time"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/infraprovider"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
var _ InfraProvisioner = (*infraProvisioner)(nil)
type Config struct {
AgentPort int
}
type infraProvisioner struct {
infraProviderConfigStore store.InfraProviderConfigStore
infraProviderResourceStore store.InfraProviderResourceStore
providerFactory infraprovider.Factory
infraProviderTemplateStore store.InfraProviderTemplateStore
infraProvisionedStore store.InfraProvisionedStore
config *Config
}
func NewInfraProvisionerService(
infraProviderConfigStore store.InfraProviderConfigStore,
infraProviderResourceStore store.InfraProviderResourceStore,
providerFactory infraprovider.Factory,
infraProviderTemplateStore store.InfraProviderTemplateStore,
infraProvisionedStore store.InfraProvisionedStore,
config *Config,
) InfraProvisioner {
return &infraProvisioner{
infraProviderConfigStore: infraProviderConfigStore,
infraProviderResourceStore: infraProviderResourceStore,
providerFactory: providerFactory,
infraProviderTemplateStore: infraProviderTemplateStore,
infraProvisionedStore: infraProvisionedStore,
config: config,
}
}
func (i infraProvisioner) getConfigFromResource(
ctx context.Context,
infraProviderResource types.InfraProviderResource,
) (*types.InfraProviderConfig, error) {
config, err := i.infraProviderConfigStore.Find(ctx, infraProviderResource.InfraProviderConfigID)
if err != nil {
return nil, fmt.Errorf(
"unable to get infra provider details for ID %d: %w",
infraProviderResource.InfraProviderConfigID, err)
}
return config, nil
}
func (i infraProvisioner) getInfraProvider(
infraProviderType enum.InfraProviderType,
) (infraprovider.InfraProvider, error) {
infraProvider, err := i.providerFactory.GetInfraProvider(infraProviderType)
if err != nil {
return nil, fmt.Errorf("unable to get infra provider of type %v: %w", infraProviderType, err)
}
return infraProvider, nil
}
func (i infraProvisioner) getTemplateParams(
ctx context.Context,
infraProvider infraprovider.InfraProvider,
infraProviderResource types.InfraProviderResource,
) ([]types.InfraProviderParameter, error) {
var params []types.InfraProviderParameter
templateParams := infraProvider.TemplateParams()
for _, param := range templateParams {
key := param.Name
if infraProviderResource.Metadata[key] != "" {
templateIdentifier := infraProviderResource.Metadata[key]
template, err := i.infraProviderTemplateStore.FindByIdentifier(
ctx, infraProviderResource.SpaceID, templateIdentifier)
if err != nil {
return nil, fmt.Errorf("unable to get template params for ID %s: %w",
infraProviderResource.Metadata[key], err)
}
params = append(params, types.InfraProviderParameter{
Name: key,
Value: template.Data,
})
}
}
return params, nil
}
func (i infraProvisioner) paramsFromResource(
infraProviderResource types.InfraProviderResource,
infraProvider infraprovider.InfraProvider,
) []types.InfraProviderParameter {
// NOTE: templateParamsMap is required to filter out template params since their values have already been fetched
// and we dont need the template identifiers, which are the values for template params in the resource Metadata.
templateParamsMap := make(map[string]bool)
for _, templateParam := range infraProvider.TemplateParams() {
templateParamsMap[templateParam.Name] = true
}
params := make([]types.InfraProviderParameter, 0)
for key, value := range infraProviderResource.Metadata {
if key == "" || value == "" || templateParamsMap[key] {
continue
}
params = append(params, types.InfraProviderParameter{
Name: key,
Value: value,
})
}
return params
}
func serializeInfraProviderParams(in []types.InfraProviderParameter) (string, error) {
output, err := json.Marshal(in)
if err != nil {
return "", fmt.Errorf("unable to marshal infra provider params: %w", err)
}
return string(output), nil
}
func deserializeInfraProviderParams(in string) ([]types.InfraProviderParameter, error) {
var parameters []types.InfraProviderParameter
err := json.Unmarshal([]byte(in), &parameters)
if err != nil {
return nil, fmt.Errorf("unable to unmarshal infra provider params %+v: %w", in, err)
}
return parameters, nil
}
func (i infraProvisioner) responseMetadata(infra types.Infrastructure) (string, error) {
output, err := json.Marshal(infra)
if err != nil {
return "", fmt.Errorf("unable to marshal infra object %+v: %w", infra, err)
}
return string(output), nil
}
func (i infraProvisioner) getAllParamsFromDB(
ctx context.Context,
infraProviderResource types.InfraProviderResource,
infraProvider infraprovider.InfraProvider,
) ([]types.InfraProviderParameter, error) {
var allParams []types.InfraProviderParameter
templateParams, err := i.getTemplateParams(ctx, infraProvider, infraProviderResource)
if err != nil {
return nil, err
}
allParams = append(allParams, templateParams...)
params := i.paramsFromResource(infraProviderResource, infraProvider)
allParams = append(allParams, params...)
return allParams, nil
}
func (i infraProvisioner) updateInfraProvisionedRecord(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
deprovisionedInfra types.Infrastructure,
) error {
infraProvisionedLatest, err := i.infraProvisionedStore.FindLatestByGitspaceInstanceID(
ctx, gitspaceConfig.SpaceID, gitspaceConfig.GitspaceInstance.ID)
if err != nil {
return fmt.Errorf(
"could not find latest infra provisioned entity for instance %d: %w",
gitspaceConfig.GitspaceInstance.ID, err)
}
responseMetadata, err := i.responseMetadata(deprovisionedInfra)
if err != nil {
return err
}
infraProvisionedLatest.InfraStatus = deprovisionedInfra.Status
infraProvisionedLatest.ServerHostIP = deprovisionedInfra.AgentHost
infraProvisionedLatest.ServerHostPort = strconv.Itoa(deprovisionedInfra.AgentPort)
infraProvisionedLatest.ProxyHost = deprovisionedInfra.ProxyAgentHost
infraProvisionedLatest.ProxyPort = int32(deprovisionedInfra.ProxyAgentPort)
infraProvisionedLatest.ResponseMetadata = &responseMetadata
infraProvisionedLatest.Updated = time.Now().UnixMilli()
err = i.infraProvisionedStore.Update(ctx, infraProvisionedLatest)
if err != nil {
return fmt.Errorf("unable to update infraProvisioned %d: %w", infraProvisionedLatest.ID, err)
}
return nil
}

View File

@ -1,76 +0,0 @@
// 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 infrastructure
import (
"context"
"fmt"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
func (i infraProvisioner) TriggerStop(
ctx context.Context,
infraProviderResource types.InfraProviderResource,
infra types.Infrastructure,
) error {
infraProviderEntity, err := i.getConfigFromResource(ctx, infraProviderResource)
if err != nil {
return err
}
infraProvider, err := i.getInfraProvider(infraProviderEntity.Type)
if err != nil {
return err
}
err = infraProvider.Stop(ctx, infra)
if err != nil {
return fmt.Errorf("unable to trigger stop infra %+v: %w", infra, err)
}
return nil
}
func (i infraProvisioner) ResumeStop(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
stoppedInfra types.Infrastructure,
) error {
infraProvider, err := i.getInfraProvider(stoppedInfra.ProviderType)
if err != nil {
return err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew {
return i.resumeStopForNewProvisioning(ctx, gitspaceConfig, stoppedInfra)
}
return nil
}
func (i infraProvisioner) resumeStopForNewProvisioning(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
stoppedInfra types.Infrastructure,
) error {
err := i.updateInfraProvisionedRecord(ctx, gitspaceConfig, stoppedInfra)
if err != nil {
return fmt.Errorf("unable to update provisioned record after stopping: %w", err)
}
return nil
}

View File

@ -16,10 +16,11 @@ package infrastructure
import (
"context"
"encoding/json"
"fmt"
"strconv"
"time"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/infraprovider"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
@ -27,10 +28,66 @@ import (
"github.com/rs/zerolog/log"
)
func (i infraProvisioner) TriggerProvision(
type Config struct {
AgentPort int
}
type InfraEventOpts struct {
RequiredGitspacePorts []types.GitspacePort
CanDeleteUserData bool
}
type InfraProvisioner struct {
infraProviderConfigStore store.InfraProviderConfigStore
infraProviderResourceStore store.InfraProviderResourceStore
providerFactory infraprovider.Factory
infraProviderTemplateStore store.InfraProviderTemplateStore
infraProvisionedStore store.InfraProvisionedStore
config *Config
}
func NewInfraProvisionerService(
infraProviderConfigStore store.InfraProviderConfigStore,
infraProviderResourceStore store.InfraProviderResourceStore,
providerFactory infraprovider.Factory,
infraProviderTemplateStore store.InfraProviderTemplateStore,
infraProvisionedStore store.InfraProvisionedStore,
config *Config,
) InfraProvisioner {
return InfraProvisioner{
infraProviderConfigStore: infraProviderConfigStore,
infraProviderResourceStore: infraProviderResourceStore,
providerFactory: providerFactory,
infraProviderTemplateStore: infraProviderTemplateStore,
infraProvisionedStore: infraProvisionedStore,
config: config,
}
}
// TriggerInfraEvent an interaction with the infrastructure, and once completed emits event in an asynchronous manner.
func (i InfraProvisioner) TriggerInfraEvent(
ctx context.Context,
eventType enum.InfraEvent,
gitspaceConfig types.GitspaceConfig,
requiredGitspacePorts []types.GitspacePort,
infra *types.Infrastructure,
) error {
opts := InfraEventOpts{CanDeleteUserData: false}
return i.TriggerInfraEventWithOpts(ctx, eventType, gitspaceConfig, infra, opts)
}
// TriggerInfraEventWithOpts triggers the provisionining of infra resources using the
// infraProviderResource with different infra providers.
// Stop event deprovisions those resources which can be stopped without losing the Gitspace data.
// CleanupInstance event cleans up resources exclusive for a gitspace instance
// Deprovision triggers deprovisioning of resources created for a Gitspace.
// canDeleteUserData = true -> deprovision of all resources
// canDeleteUserData = false -> deprovision of all resources except storage associated to user data.
func (i InfraProvisioner) TriggerInfraEventWithOpts(
ctx context.Context,
eventType enum.InfraEvent,
gitspaceConfig types.GitspaceConfig,
infra *types.Infrastructure,
opts InfraEventOpts,
) error {
infraProviderEntity, err := i.getConfigFromResource(ctx, gitspaceConfig.InfraProviderResource)
if err != nil {
@ -42,23 +99,41 @@ func (i infraProvisioner) TriggerProvision(
return err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew {
return i.triggerProvisionForNewProvisioning(
ctx, infraProvider, infraProviderEntity.Type, gitspaceConfig, requiredGitspacePorts)
switch eventType {
case enum.InfraEventProvision:
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew {
return i.provisionNewInfrastructure(ctx, infraProvider, infraProviderEntity.Type,
gitspaceConfig, opts.RequiredGitspacePorts)
}
return i.provisionExistingInfrastructure(ctx, infraProvider, gitspaceConfig, opts.RequiredGitspacePorts)
case enum.InfraEventDeprovision:
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew {
return i.deprovisionNewInfrastructure(ctx, infraProvider, gitspaceConfig, *infra, opts.CanDeleteUserData)
}
return infraProvider.Deprovision(ctx, *infra, opts.CanDeleteUserData)
case enum.InfraEventCleanup:
return infraProvider.CleanupInstanceResources(ctx, *infra)
case enum.InfraEventStop:
return infraProvider.Stop(ctx, *infra)
default:
return fmt.Errorf("unsupported event type: %s", eventType)
}
return i.triggerProvisionForExistingProvisioning(
ctx, infraProvider, gitspaceConfig, requiredGitspacePorts)
}
func (i infraProvisioner) triggerProvisionForNewProvisioning(
func (i InfraProvisioner) provisionNewInfrastructure(
ctx context.Context,
infraProvider infraprovider.InfraProvider,
infraProviderType enum.InfraProviderType,
gitspaceConfig types.GitspaceConfig,
requiredGitspacePorts []types.GitspacePort,
) error {
// Logic for new provisioning...
infraProvisionedLatest, _ := i.infraProvisionedStore.FindLatestByGitspaceInstanceID(
ctx, gitspaceConfig.SpaceID, gitspaceConfig.GitspaceInstance.ID)
ctx, gitspaceConfig.GitspaceInstance.ID)
if infraProvisionedLatest != nil &&
infraProvisionedLatest.InfraStatus == enum.InfraStatusPending &&
@ -119,9 +194,9 @@ func (i infraProvisioner) triggerProvisionForNewProvisioning(
if err != nil {
infraProvisioned.InfraStatus = enum.InfraStatusUnknown
infraProvisioned.Updated = time.Now().UnixMilli()
err2 := i.infraProvisionedStore.Update(ctx, infraProvisioned)
if err2 != nil {
log.Err(err2).Msgf("unable to update infraProvisioned Entry for %d", infraProvisioned.ID)
updateErr := i.infraProvisionedStore.Update(ctx, infraProvisioned)
if updateErr != nil {
log.Err(updateErr).Msgf("unable to update infraProvisioned Entry for %d", infraProvisioned.ID)
}
return fmt.Errorf(
@ -134,7 +209,7 @@ func (i infraProvisioner) triggerProvisionForNewProvisioning(
return nil
}
func (i infraProvisioner) triggerProvisionForExistingProvisioning(
func (i InfraProvisioner) provisionExistingInfrastructure(
ctx context.Context,
infraProvider infraprovider.InfraProvider,
gitspaceConfig types.GitspaceConfig,
@ -171,53 +246,37 @@ func (i infraProvisioner) triggerProvisionForExistingProvisioning(
return nil
}
func (i infraProvisioner) ResumeProvision(
func (i InfraProvisioner) deprovisionNewInfrastructure(
ctx context.Context,
infraProvider infraprovider.InfraProvider,
gitspaceConfig types.GitspaceConfig,
provisionedInfra types.Infrastructure,
) error {
infraProvider, err := i.getInfraProvider(provisionedInfra.ProviderType)
if err != nil {
return err
}
if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew {
return i.resumeProvisionForNewProvisioning(ctx, gitspaceConfig, provisionedInfra)
}
return nil
}
func (i infraProvisioner) resumeProvisionForNewProvisioning(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
provisionedInfra types.Infrastructure,
infra types.Infrastructure,
canDeleteUserData bool,
) error {
infraProvisionedLatest, err := i.infraProvisionedStore.FindLatestByGitspaceInstanceID(
ctx, gitspaceConfig.SpaceID, gitspaceConfig.GitspaceInstance.ID)
ctx, gitspaceConfig.GitspaceInstance.ID)
if err != nil {
return fmt.Errorf(
"could not find latest infra provisioned entity for instance %d: %w",
gitspaceConfig.GitspaceInstance.ID, err)
}
responseMetadata, err := i.responseMetadata(provisionedInfra)
if err != nil {
return err
if infraProvisionedLatest.InfraStatus == enum.InfraStatusDestroyed {
return nil
}
infraProvisionedLatest.InfraStatus = provisionedInfra.Status
infraProvisionedLatest.ServerHostIP = provisionedInfra.AgentHost
infraProvisionedLatest.ServerHostPort = strconv.Itoa(provisionedInfra.AgentPort)
infraProvisionedLatest.ProxyHost = provisionedInfra.ProxyAgentHost
infraProvisionedLatest.ProxyPort = int32(provisionedInfra.ProxyAgentPort)
infraProvisionedLatest.ResponseMetadata = &responseMetadata
infraProvisionedLatest.Updated = time.Now().UnixMilli()
err = i.infraProvisionedStore.Update(ctx, infraProvisionedLatest)
err = infraProvider.Deprovision(ctx, infra, canDeleteUserData)
if err != nil {
return fmt.Errorf("unable to update infraProvisioned Entry %d", infraProvisionedLatest.ID)
return fmt.Errorf("unable to trigger deprovision infra %+v: %w", infra, err)
}
return nil
return err
}
func serializeInfraProviderParams(in []types.InfraProviderParameter) (string, error) {
output, err := json.Marshal(in)
if err != nil {
return "", fmt.Errorf("unable to marshal infra provider params: %w", err)
}
return string(output), nil
}

View File

@ -86,7 +86,7 @@ func (o Orchestrator) ResumeStartGitspace(
idePort := ideSvc.Port()
err = o.infraProvisioner.ResumeProvision(ctx, gitspaceConfig, provisionedInfra)
err = o.infraProvisioner.PostInfraEventComplete(ctx, gitspaceConfig, provisionedInfra, enum.InfraEventProvision)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
@ -271,7 +271,7 @@ func (o Orchestrator) ResumeStopGitspace(
) (enum.GitspaceInstanceStateType, *types.GitspaceError) {
instanceState := enum.GitspaceInstanceStateError
err := o.infraProvisioner.ResumeStop(ctx, gitspaceConfig, stoppedInfra)
err := o.infraProvisioner.PostInfraEventComplete(ctx, gitspaceConfig, stoppedInfra, enum.InfraEventStop)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
infraStopErr := fmt.Errorf("cannot stop provisioned infrastructure with ID %s: %w",
@ -313,7 +313,7 @@ func (o Orchestrator) ResumeDeleteGitspace(
) (enum.GitspaceInstanceStateType, error) {
instanceState := enum.GitspaceInstanceStateError
err := o.infraProvisioner.ResumeDeprovision(ctx, gitspaceConfig, deprovisionedInfra)
err := o.infraProvisioner.PostInfraEventComplete(ctx, gitspaceConfig, deprovisionedInfra, enum.InfraEventDeprovision)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraDeprovisioningFailed)
return instanceState, fmt.Errorf(
@ -346,7 +346,7 @@ func (o Orchestrator) ResumeCleanupInstanceResources(
) (enum.GitspaceInstanceStateType, error) {
instanceState := enum.GitspaceInstanceStateError
err := o.infraProvisioner.ResumeCleanupInstance(ctx, gitspaceConfig, cleanedUpInfra)
err := o.infraProvisioner.PostInfraEventComplete(ctx, gitspaceConfig, cleanedUpInfra, enum.InfraEventCleanup)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraCleanupFailed)

View File

@ -124,7 +124,8 @@ func (o Orchestrator) TriggerStartGitspace(
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningStart)
err = o.infraProvisioner.TriggerProvision(ctx, gitspaceConfig, requiredGitspacePorts)
opts := infrastructure.InfraEventOpts{RequiredGitspacePorts: requiredGitspacePorts}
err = o.infraProvisioner.TriggerInfraEventWithOpts(ctx, enum.InfraEventProvision, gitspaceConfig, nil, opts)
if err != nil {
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
return &types.GitspaceError{
@ -166,7 +167,7 @@ func (o Orchestrator) TriggerStopGitspace(
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopStart)
err = o.infraProvisioner.TriggerStop(ctx, gitspaceConfig.InfraProviderResource, *infra)
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",
@ -268,7 +269,7 @@ func (o Orchestrator) TriggerCleanupInstanceResources(ctx context.Context, gitsp
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraCleanupStart)
err = o.infraProvisioner.TriggerCleanupInstance(ctx, gitspaceConfig, *infra)
err = o.infraProvisioner.TriggerInfraEvent(ctx, enum.InfraEventCleanup, gitspaceConfig, infra)
if err != nil {
return fmt.Errorf("cannot trigger cleanup infrastructure with ID %s: %w",
gitspaceConfig.InfraProviderResource.UID,
@ -312,7 +313,8 @@ func (o Orchestrator) TriggerDeleteGitspace(
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraResetStart)
}
err = o.infraProvisioner.TriggerDeprovision(ctx, gitspaceConfig, *infra, canDeleteUserData)
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)

View File

@ -24,11 +24,11 @@ import (
)
const (
templatesDir = "templates"
ScriptTemplatesDir = "script_templates"
)
var (
//go:embed templates/*
//go:embed script_templates/*
files embed.FS
scriptTemplates map[string]*template.Template
)
@ -43,7 +43,7 @@ func init() {
func LoadTemplates() error {
scriptTemplates = make(map[string]*template.Template)
tmplFiles, err := fs.ReadDir(files, templatesDir)
tmplFiles, err := fs.ReadDir(files, ScriptTemplatesDir)
if err != nil {
return fmt.Errorf("error reading script templates: %w", err)
}
@ -53,7 +53,7 @@ func LoadTemplates() error {
continue
}
textTemplate, parsingErr := template.ParseFS(files, path.Join(templatesDir, tmpl.Name()))
textTemplate, parsingErr := template.ParseFS(files, path.Join(ScriptTemplatesDir, tmpl.Name()))
if parsingErr != nil {
return fmt.Errorf("error parsing template %s: %w", tmpl.Name(), parsingErr)
}

View File

@ -1262,11 +1262,7 @@ type (
InfraProvisionedStore interface {
Find(ctx context.Context, id int64) (*types.InfraProvisioned, error)
FindAllLatestByGateway(ctx context.Context, gatewayHost string) ([]*types.InfraProvisionedGatewayView, error)
FindLatestByGitspaceInstanceID(
ctx context.Context,
spaceID int64,
gitspaceInstanceID int64,
) (*types.InfraProvisioned, error)
FindLatestByGitspaceInstanceID(ctx context.Context, gitspaceInstanceID int64) (*types.InfraProvisioned, error)
FindLatestByGitspaceInstanceIdentifier(
ctx context.Context,
spaceID int64,

View File

@ -153,14 +153,12 @@ func (i infraProvisionedStore) FindAllLatestByGateway(
func (i infraProvisionedStore) FindLatestByGitspaceInstanceID(
ctx context.Context,
spaceID int64,
gitspaceInstanceID int64,
) (*types.InfraProvisioned, error) {
stmt := database.Builder.
Select(infraProvisionedSelectColumns).
From(infraProvisionedTable).
Where("iprov_gitspace_id = ?", gitspaceInstanceID).
Where("iprov_space_id = ?", spaceID).
OrderBy("iprov_created DESC")
sql, args, err := stmt.ToSql()

View File

@ -21,7 +21,7 @@ func (InfraEvent) Enum() []interface{} {
}
var infraEvents = []InfraEvent{
InfraEventProvision, InfraEventStop, InfraEventDeprovision,
InfraEventProvision, InfraEventStop, InfraEventDeprovision, InfraEventCleanup,
}
const (