Skip to content

Commit

Permalink
check first test
Browse files Browse the repository at this point in the history
Signed-off-by: Adrian Riobo <[email protected]>
  • Loading branch information
adrianriobo committed Dec 20, 2024
1 parent eb481ea commit 87ef140
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ SOURCES := $(shell find . -name "*.go" -not -path "./vendor/*")
ORG := github.com/redhat-developer
MODULEPATH = $(ORG)/mapt
# Linker flags
VERSION_VARIABLES := -X $(MODULEPATH)/pkg/api/serverless.maptOCI=$(IMG)
VERSION_VARIABLES := -X $(MODULEPATH)/pkg/api/serverless.OCI=$(IMG)

# https://golang.org/cmd/link/
# LDFLAGS := $(VERSION_VARIABLES) -extldflags='-static' ${GO_EXTRA_LDFLAGS}
Expand Down
10 changes: 6 additions & 4 deletions cmd/mapt/cmd/aws/hosts/constans.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package hosts

const (
spot string = "spot"
spotDesc string = "if this flag is set the host will be created only on the region set by the AWS Env (AWS_DEFAULT_REGION)"
airgap string = "airgap"
airgapDesc string = "if this flag is set the host will be created as airgap machine. Access will done through a bastion"
spot string = "spot"
spotDesc string = "if this flag is set the host will be created only on the region set by the AWS Env (AWS_DEFAULT_REGION)"
airgap string = "airgap"
airgapDesc string = "if this flag is set the host will be created as airgap machine. Access will done through a bastion"
timeout string = "timeout"
timeoutDesc string = "if timeout is set a serverless destroy actions will be set on the time according to the timeout. The Timeout value is a duration conforming to Go ParseDuration format."

vmTypes string = "vm-types"
vmTypesDescription string = "set an specific set of vm-types and ignore any CPUs, Memory, Arch parameters set. Note vm-type should match requested arch. Also if --spot flag is used set at least 3 types."
Expand Down
2 changes: 2 additions & 0 deletions cmd/mapt/cmd/aws/hosts/fedora.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func getFedoraCreate() *cobra.Command {
VMType: viper.GetStringSlice(vmTypes),
InstanceRequest: instanceRequest,
Spot: viper.IsSet(spot),
Timeout: viper.GetString(timeout),
SetupGHActionsRunner: viper.IsSet(params.InstallGHActionsRunner),
Airgap: viper.IsSet(airgap)}); err != nil {
logging.Error(err)
Expand All @@ -96,6 +97,7 @@ func getFedoraCreate() *cobra.Command {
flagSet.StringSliceP(vmTypes, "", []string{}, vmTypesDescription)
flagSet.Bool(airgap, false, airgapDesc)
flagSet.Bool(spot, false, spotDesc)
flagSet.StringP(timeout, "", "", timeout)
flagSet.AddFlagSet(params.GetGHActionsFlagset())
flagSet.AddFlagSet(params.GetCpusAndMemoryFlagset())
c.PersistentFlags().AddFlagSet(flagSet)
Expand Down
File renamed without changes.
12 changes: 12 additions & 0 deletions hacks/aws/serverless.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

#Usage ./serverless.sh ACCESS_KEY SECRET_KEY

CONTAINER_RUNTIME="${CONTAINER_RUNTIME:-"podman"}"
AWS_CLI="${CONTAINER_RUNTIME} run --rm -it -e AWS_ACCESS_KEY_ID=${1} -e AWS_SECRET_ACCESS_KEY=${2} -e AWS_DEFAULT_REGION="us-west-1" docker.io/amazon/aws-cli:latest"

aws_cmd () {
${AWS_CLI} ${1}
}

aws_cmd "ecs create-cluster --cluster-name serverless-mapt"
Empty file modified hacks/azure/azure_delete_rg_by_spot_stopped.sh
100644 → 100755
Empty file.
Empty file modified hacks/azure/azure_setup.sh
100644 → 100755
Empty file.
34 changes: 34 additions & 0 deletions pkg/provider/aws/action/fedora/fedora.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/base64"
"fmt"
"os"
"time"

"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/auto"
Expand All @@ -13,6 +14,7 @@ import (
maptContext "github.com/redhat-developer/mapt/pkg/manager/context"
infra "github.com/redhat-developer/mapt/pkg/provider"
"github.com/redhat-developer/mapt/pkg/provider/aws"
"github.com/redhat-developer/mapt/pkg/provider/aws/api/serverless"
"github.com/redhat-developer/mapt/pkg/provider/aws/data"
"github.com/redhat-developer/mapt/pkg/provider/aws/modules/bastion"
"github.com/redhat-developer/mapt/pkg/provider/aws/modules/ec2/compute"
Expand All @@ -39,6 +41,7 @@ type Request struct {
VMType []string
Spot bool
Airgap bool
Timeout string
// internal management
// For airgap scenario there is an orchestation of
// a phase with connectivity on the machine (allowing bootstraping)
Expand Down Expand Up @@ -229,6 +232,21 @@ func (r *Request) deploy(ctx *pulumi.Context) error {
pulumi.String(amiUserDefault))
ctx.Export(fmt.Sprintf("%s-%s", r.Prefix, outputHost),
c.GetHostIP(!r.Airgap))
if len(r.Timeout) > 0 {
// Need to change Timeout to a one time cron job scheduling
se, err := generateAWSScheduleExpression(r.Timeout)
if err != nil {
return err
}
destroyCommand := fmt.Sprintf("aws destroy fedora --project-name %s --backed-url %s",
maptContext.ProjectName(),
maptContext.BackedURL())
if err = serverless.Create(ctx, targetSubnet,
r.Prefix, awsFedoraDedicatedID,
destroyCommand, se); err != nil {
return err
}
}
return c.Readiness(ctx, command.CommandPing, r.Prefix, awsFedoraDedicatedID,
keyResources.PrivateKey, amiUserDefault, bastion, []pulumi.Resource{})
}
Expand Down Expand Up @@ -284,3 +302,19 @@ func (r *Request) getUserdata() (pulumi.StringPtrInput, error) {
templateConfig)
return pulumi.String(base64.StdEncoding.EncodeToString([]byte(userdata))), err
}

func generateAWSScheduleExpression(timeout string) (string, error) {
// Parse the timeout duration
duration, err := time.ParseDuration(timeout)
if err != nil {
return "", fmt.Errorf("invalid timeout format: %v", err)
}

// Calculate the target time based on the current time and duration
targetTime := time.Now().Add(duration)

// Format the target time in RFC3339 format (required for AWS Scheduler)
scheduleExpression := fmt.Sprintf("at(%s)", targetTime.Format(time.RFC3339))

return scheduleExpression, nil
}
122 changes: 110 additions & 12 deletions pkg/provider/aws/api/serverless/serverless.go
Original file line number Diff line number Diff line change
@@ -1,51 +1,68 @@
package serverless

import (
"encoding/json"
"fmt"
"strings"

"github.com/pulumi/pulumi-aws-native/sdk/go/aws/scheduler"
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ecs"
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/iam"
"github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/awsx"
awsxecs "github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ecs"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
maptServerless "github.com/redhat-developer/mapt/pkg/api/serverless"
"github.com/redhat-developer/mapt/pkg/manager/context"
"github.com/redhat-developer/mapt/pkg/provider/aws/data"
resourcesUtil "github.com/redhat-developer/mapt/pkg/util/resources"
)

type ServerlessManager struct{}

// Mapts requires the cluster to exist previously wit specific naming
// check hacks/aws/serverless.sh to
var (
region = "eu-west-1"
name = "serverless-mapt"
name = "serverless-mode-mapt"
)

func GetServerlessManager() *ServerlessManager {
return &ServerlessManager{}
}
// func GetServerlessManager() *ServerlessManager {
// return &ServerlessManager{}
// }

func (sm *ServerlessManager) Create(ctx *pulumi.Context,
func Create(ctx *pulumi.Context, subnet *ec2.Subnet,
prefix, componentID string, command, schedule string) error {
// Get the pre configured cluster to handle serverless exectucions
clusterArn, err := data.GetCluster(&region, name)
clusterArn, err := getClusterArn(ctx, prefix, componentID)
if err != nil {
return err
}
role, err := createECSTaskRole(ctx, prefix, componentID)
if err != nil {
return err
}
// Create definition of the mapt execution
fs, err := awsxecs.NewFargateService(ctx,
resourcesUtil.GetResourceName(prefix, componentID, "fgs"),
&awsxecs.FargateServiceArgs{
Cluster: pulumi.String(*clusterArn),
NetworkConfiguration: ecs.ServiceNetworkConfigurationArgs{
AssignPublicIp: pulumi.Bool(true),
Subnets: pulumi.StringArray{
subnet.ID(),
},
},
Cluster: clusterArn,
TaskDefinitionArgs: &awsxecs.FargateServiceTaskDefinitionArgs{
Container: &awsxecs.TaskDefinitionContainerDefinitionArgs{
Image: pulumi.String(maptServerless.OCI),
Command: pulumi.ToStringArray(strings.Fields(command)),
},
// May this is valid instead of auth credentials for mapt
// Do we know if setting the Role will setup ephemeral creds with env values?
// TaskRole: &awsx.DefaultRoleWithPolicyArgs{
// },
TaskRole: &awsx.DefaultRoleWithPolicyArgs{
RoleArn: role.Arn,
},
},
})

if err != nil {
return err
}
Expand All @@ -64,3 +81,84 @@ func (sm *ServerlessManager) Create(ctx *pulumi.Context,
}
return nil
}

func getClusterArn(ctx *pulumi.Context, prefix, componentID string) (*pulumi.StringOutput, error) {
clusterArn, err := data.GetCluster(name)
if err != nil {
if err == data.ECSClusterNotFound {
if cluster, err := ecs.NewCluster(ctx,
resourcesUtil.GetResourceName(prefix, componentID, "cluster"),
&ecs.ClusterArgs{
Tags: context.ResourceTags(),
Name: pulumi.String(name),
},
pulumi.RetainOnDelete(true)); err != nil {
return nil, err
} else {
return &cluster.Arn, nil
}
} else {
return nil, fmt.Errorf("error getting cluster for serverless mode. Check hacks/aws/serverless.sh: %v", err)
}
}
carn := pulumi.String(*clusterArn).ToStringOutput()
return &carn, nil
}

// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html
// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/security-iam-roles.html
func createECSTaskRole(ctx *pulumi.Context, prefix, componentID string) (*iam.Role, error) {
trustPolicyContent, err := json.Marshal(map[string]interface{}{
"Version": "2012-10-17",
"Statement": []map[string]interface{}{
{
"Effect": "Allow",
"Principal": map[string]interface{}{
"Service": "ecs-tasks.amazonaws.com",
},
"Action": "sts:AssumeRole",
},
},
})
if err != nil {
return nil, err
}
// Need to creeate policies and attach
r, err := iam.NewRole(ctx,
resourcesUtil.GetResourceName(prefix, componentID, "role"),
&iam.RoleArgs{
Name: pulumi.String(fmt.Sprintf("mapt-ecs-%s", context.RunID())),
AssumeRolePolicy: pulumi.String(string(trustPolicyContent)),
Tags: context.ResourceTags(),
})
if err != nil {
return nil, err
}
policyContent, err := json.Marshal(map[string]interface{}{
"Version": "2012-10-17",
"Statement": []map[string]interface{}{
{
"Effect": "Allow",
"Action": []string{
"s3:*",
"ec2:*",
},
"Resource": []string{
"*",
},
},
},
})
if err != nil {
return nil, err
}
if _, err = iam.NewRolePolicy(ctx,
"rolePolicy",
&iam.RolePolicyArgs{
Role: r.ID(),
Policy: pulumi.String(string(policyContent)),
}); err != nil {
return nil, err
}
return r, nil
}
20 changes: 11 additions & 9 deletions pkg/provider/aws/data/ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import (
"github.com/aws/aws-sdk-go-v2/service/ecs"
)

func GetCluster(region *string, clusterName string) (*string, error) {
var cfgOpts config.LoadOptionsFunc
if region != nil {
cfgOpts = config.WithRegion(*region)
}
cfg, err := config.LoadDefaultConfig(context.TODO(), cfgOpts)
var ECSClusterNotFound = fmt.Errorf("Cluster not found")

func GetCluster(clusterName string) (*string, error) {
// var cfgOpts config.LoadOptionsFunc
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
return nil, err
}
Expand All @@ -23,8 +22,11 @@ func GetCluster(region *string, clusterName string) (*string, error) {
listClustersOutput, err := client.ListClusters(
context.TODO(),
&ecs.ListClustersInput{})
if err != nil && len(listClustersOutput.ClusterArns) == 0 {
return nil, fmt.Errorf("error getting ecs clusters")
if err != nil {
return nil, err
}
if listClustersOutput == nil || len(listClustersOutput.ClusterArns) == 0 {
return nil, ECSClusterNotFound
}
cls, err := client.DescribeClusters(
context.TODO(),
Expand All @@ -39,5 +41,5 @@ func GetCluster(region *string, clusterName string) (*string, error) {
return c.ClusterArn, nil
}
}
return nil, fmt.Errorf("error searching for cluster")
return nil, ECSClusterNotFound
}

0 comments on commit 87ef140

Please sign in to comment.