You've already forked golang-saas-starter-kit
mirror of
https://github.com/raseels-repos/golang-saas-starter-kit.git
synced 2025-08-10 22:41:25 +02:00
remwork tools
This commit is contained in:
@@ -1,149 +0,0 @@
|
||||
|
||||
1. Create new policy `saas-starter-kit-deploy` with the following permissions.
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "ServiceDeployPermissions",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"acm:ListCertificates",
|
||||
"acm:RequestCertificate",
|
||||
"acm:DescribeCertificate",
|
||||
"ec2:DescribeSubnets",
|
||||
"ec2:DescribeSecurityGroups",
|
||||
"ec2:CreateSecurityGroup",
|
||||
"ec2:AuthorizeSecurityGroupIngress",
|
||||
"ec2:DescribeNetworkInterfaces",
|
||||
"ec2:DescribeVpcs",
|
||||
"ec2:CreateVpc",
|
||||
"ec2:CreateSubnet",
|
||||
"ec2:DescribeVpcs",
|
||||
"ec2:DescribeInternetGateways",
|
||||
"ec2:CreateInternetGateway",
|
||||
"ec2:CreateTags",
|
||||
"ec2:CreateRouteTable",
|
||||
"ec2:DescribeRouteTables",
|
||||
"ec2:CreateRoute",
|
||||
"ec2:AttachInternetGateway",
|
||||
"ec2:DescribeAccountAttributes",
|
||||
"elasticache:DescribeCacheClusters",
|
||||
"elasticache:CreateCacheCluster",
|
||||
"elasticache:DescribeCacheParameterGroups",
|
||||
"elasticache:CreateCacheParameterGroup",
|
||||
"elasticache:ModifyCacheCluster",
|
||||
"elasticache:ModifyCacheParameterGroup",
|
||||
"elasticloadbalancing:DescribeLoadBalancers",
|
||||
"elasticloadbalancing:CreateLoadBalancer",
|
||||
"elasticloadbalancing:CreateListener",
|
||||
"elasticloadbalancing:DescribeTargetGroups",
|
||||
"elasticloadbalancing:CreateTargetGroup",
|
||||
"elasticloadbalancing:DescribeListeners",
|
||||
"elasticloadbalancing:ModifyTargetGroupAttributes",
|
||||
"ecs:CreateCluster",
|
||||
"ecs:CreateService",
|
||||
"ecs:DeleteService",
|
||||
"ecs:DescribeClusters",
|
||||
"ecs:DescribeServices",
|
||||
"ecs:UpdateService",
|
||||
"ecs:RegisterTaskDefinition",
|
||||
"ecs:ListTaskDefinitions",
|
||||
"ecr:BatchCheckLayerAvailability",
|
||||
"ecr:BatchDeleteImage",
|
||||
"ecr:GetAuthorizationToken",
|
||||
"ecr:DescribeImages",
|
||||
"ecr:DescribeRepositories",
|
||||
"ecs:DescribeTasks",
|
||||
"ecr:CreateRepository",
|
||||
"ecr:ListImages",
|
||||
"ecs:ListTasks",
|
||||
"ecr:PutImage",
|
||||
"ecr:InitiateLayerUpload",
|
||||
"ecr:UploadLayerPart",
|
||||
"ecr:CompleteLayerUpload",
|
||||
"logs:DescribeLogGroups",
|
||||
"logs:CreateLogGroup",
|
||||
"lambda:ListFunctions",
|
||||
"lambda:CreateFunction",
|
||||
"lambda:UpdateFunctionCode",
|
||||
"lambda:UpdateFunctionConfiguration",
|
||||
"iam:GetRole",
|
||||
"iam:PassRole",
|
||||
"iam:CreateRole",
|
||||
"iam:CreateServiceLinkedRole",
|
||||
"iam:CreatePolicy",
|
||||
"iam:PutRolePolicy",
|
||||
"iam:TagRole",
|
||||
"iam:AttachRolePolicy",
|
||||
"iam:ListPolicies",
|
||||
"iam:GetPolicyVersion",
|
||||
"iam:CreatePolicyVersion",
|
||||
"logs:DescribeLogGroups",
|
||||
"logs:CreateLogGroup",
|
||||
"logs:DescribeLogStreams",
|
||||
"logs:CreateExportTask",
|
||||
"logs:DescribeExportTasks",
|
||||
"rds:CreateDBCluster",
|
||||
"rds:CreateDBInstance",
|
||||
"rds:DescribeDBClusters",
|
||||
"rds:DescribeDBInstances",
|
||||
"s3:CreateBucket",
|
||||
"s3:DeleteObject",
|
||||
"s3:DeleteObjectVersion",
|
||||
"s3:GetBucketPublicAccessBlock",
|
||||
"s3:GetBucketAcl",
|
||||
"s3:HeadBucket",
|
||||
"s3:ListObjects",
|
||||
"s3:ListBucket",
|
||||
"s3:GetObject",
|
||||
"s3:PutLifecycleConfiguration",
|
||||
"s3:PutBucketCORS",
|
||||
"s3:PutBucketPolicy",
|
||||
"s3:PutBucketPublicAccessBlock",
|
||||
"route53:CreateHostedZone",
|
||||
"route53:ChangeResourceRecordSets",
|
||||
"route53:ListHostedZones",
|
||||
"secretsmanager:CreateSecret",
|
||||
"secretsmanager:ListSecrets",
|
||||
"secretsmanager:GetSecretValue",
|
||||
"secretsmanager:UpdateSecret",
|
||||
"secretsmanager:RestoreSecret",
|
||||
"secretsmanager:DeleteSecret",
|
||||
"servicediscovery:ListNamespaces",
|
||||
"servicediscovery:CreatePrivateDnsNamespace",
|
||||
"servicediscovery:GetOperation",
|
||||
"servicediscovery:ListServices",
|
||||
"servicediscovery:CreateService",
|
||||
"servicediscovery:GetService"
|
||||
],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Action": "iam:CreateServiceLinkedRole",
|
||||
"Effect": "Allow",
|
||||
"Resource": "arn:aws:iam::*:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS",
|
||||
"Condition": {
|
||||
"StringLike": {
|
||||
"iam:AWSServiceName":"rds.amazonaws.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
2. Create new user `saas-starter-kit-deploy` with _Programmatic Access_ and _Attach existing policies directly_ with the policy created from step 1 `saas-starter-kit-deploy`
|
||||
|
||||
3. Try running the deploy
|
||||
```bash
|
||||
go run main.go deploy -service=web-api -env=dev
|
||||
```
|
||||
|
||||
Or
|
||||
```bash
|
||||
go run main.go deploy -service=web-api -env=dev -enable_https=true -primary_host=eproc.tech -host_names=www.eproc.tech -host_names=api.eproc.tech -recreate_service=false
|
||||
```
|
||||
|
||||
|
||||
|
@@ -1,155 +0,0 @@
|
||||
package devops
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// findProjectGoModFile finds the project root directory from the current working directory.
|
||||
func findProjectGoModFile() (string, error) {
|
||||
var err error
|
||||
projectRoot, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", errors.WithMessage(err, "failed to get current working directory")
|
||||
}
|
||||
|
||||
// Try to find the project root for looking for the go.mod file in a parent directory.
|
||||
var goModFile string
|
||||
testDir := projectRoot
|
||||
for i := 0; i < 3; i++ {
|
||||
if goModFile != "" {
|
||||
testDir = filepath.Join(testDir, "../")
|
||||
}
|
||||
goModFile = filepath.Join(testDir, "go.mod")
|
||||
ok, _ := exists(goModFile)
|
||||
if ok {
|
||||
projectRoot = testDir
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the go.mod file was found.
|
||||
ok, err := exists(goModFile)
|
||||
if err != nil {
|
||||
return "", errors.WithMessagef(err, "failed to load go.mod for project using project root %s")
|
||||
} else if !ok {
|
||||
return "", errors.Errorf("failed to locate project go.mod in project root %s", projectRoot)
|
||||
}
|
||||
|
||||
return goModFile, nil
|
||||
}
|
||||
|
||||
// findServiceDockerFile finds the service directory.
|
||||
func findServiceDockerFile(projectRoot, targetService string) (string, error) {
|
||||
checkDirs := []string{
|
||||
filepath.Join(projectRoot, "cmd", targetService),
|
||||
filepath.Join(projectRoot, "tools", targetService),
|
||||
}
|
||||
|
||||
var dockerFile string
|
||||
for _, cd := range checkDirs {
|
||||
// Check to see if directory contains Dockerfile.
|
||||
tf := filepath.Join(cd, "Dockerfile")
|
||||
|
||||
ok, _ := exists(tf)
|
||||
if ok {
|
||||
dockerFile = tf
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if dockerFile == "" {
|
||||
return "", errors.Errorf("failed to locate Dockerfile for service %s", targetService)
|
||||
}
|
||||
|
||||
return dockerFile, nil
|
||||
}
|
||||
|
||||
// getTargetEnv checks for an env var that is prefixed with the current target env.
|
||||
func getTargetEnv(targetEnv, envName string) string {
|
||||
k := fmt.Sprintf("%s_%s", strings.ToUpper(targetEnv), envName)
|
||||
|
||||
if v := os.Getenv(k); v != "" {
|
||||
// Set the non prefixed env var with the prefixed value.
|
||||
os.Setenv(envName, v)
|
||||
return v
|
||||
}
|
||||
|
||||
return os.Getenv(envName)
|
||||
}
|
||||
|
||||
// loadGoModName parses out the module name from go.mod.
|
||||
func loadGoModName(goModFile string) (string, error) {
|
||||
ok, err := exists(goModFile)
|
||||
if err != nil {
|
||||
return "", errors.WithMessage(err, "Failed to load go.mod for project")
|
||||
} else if !ok {
|
||||
return "", errors.Errorf("Failed to locate project go.mod at %s", goModFile)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile(goModFile)
|
||||
if err != nil {
|
||||
return "", errors.WithMessagef(err, "Failed to read go.mod at %s", goModFile)
|
||||
}
|
||||
|
||||
var name string
|
||||
lines := strings.Split(string(b), "\n")
|
||||
for _, l := range lines {
|
||||
if strings.HasPrefix(l, "module ") {
|
||||
name = strings.TrimSpace(strings.Split(l, " ")[1])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// exists returns a bool as to whether a file path exists.
|
||||
func exists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
/*
|
||||
type EnvVars []string
|
||||
|
||||
// execCmds executes a set of commands.
|
||||
func execCmds(workDir string, envVars *EnvVars, cmds ...[]string) ([]string, error) {
|
||||
if envVars == nil {
|
||||
ev := EnvVars(os.Environ())
|
||||
envVars = &ev
|
||||
}
|
||||
|
||||
var results []string
|
||||
for _, cmdVals := range cmds {
|
||||
cmd := exec.Command(cmdVals[0], cmdVals[1:]...)
|
||||
cmd.Dir = workDir
|
||||
cmd.Env = *envVars
|
||||
out, err := cmd.CombinedOutput()
|
||||
|
||||
fmt.Println(string(out ))
|
||||
|
||||
if err != nil {
|
||||
return results, errors.WithMessagef(err, "failed to execute %s\n%s", strings.Join(cmdVals, " "), string(out))
|
||||
}
|
||||
results = append(results, string(out))
|
||||
|
||||
// Update the current env vars after command has been executed.
|
||||
ev := EnvVars(cmd.Env)
|
||||
envVars = &ev
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
*/
|
@@ -1,199 +0,0 @@
|
||||
package devops
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ecr"
|
||||
"github.com/aws/aws-sdk-go/service/ecs"
|
||||
"github.com/aws/aws-sdk-go/service/elasticache"
|
||||
"github.com/aws/aws-sdk-go/service/elbv2"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
"github.com/aws/aws-sdk-go/service/rds"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/servicediscovery"
|
||||
"github.com/iancoleman/strcase"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// ServiceDeployFlags defines the flags used for executing a service deployment.
|
||||
type ServiceDeployFlags struct {
|
||||
// Required flags.
|
||||
ServiceName string `validate:"required" example:"web-api"`
|
||||
Env string `validate:"oneof=dev stage prod" example:"dev"`
|
||||
|
||||
// Optional flags.
|
||||
EnableHTTPS bool `validate:"omitempty" example:"false"`
|
||||
ServiceHostPrimary string `validate:"omitempty" example:"example-project.com"`
|
||||
ServiceHostNames cli.StringSlice `validate:"omitempty" example:"subdomain.example-project.com"`
|
||||
S3BucketPrivateName string `validate:"omitempty" example:"saas-example-project-private"`
|
||||
S3BucketPublicName string `validate:"omitempty" example:"saas-example-project-public"`
|
||||
|
||||
ProjectRoot string `validate:"omitempty" example:"."`
|
||||
ProjectName string ` validate:"omitempty" example:"example-project"`
|
||||
DockerFile string `validate:"omitempty" example:"./cmd/web-api/Dockerfile"`
|
||||
EnableLambdaVPC bool `validate:"omitempty" example:"false"`
|
||||
EnableEcsElb bool `validate:"omitempty" example:"false"`
|
||||
NoBuild bool `validate:"omitempty" example:"false"`
|
||||
NoDeploy bool `validate:"omitempty" example:"false"`
|
||||
NoCache bool `validate:"omitempty" example:"false"`
|
||||
NoPush bool `validate:"omitempty" example:"false"`
|
||||
RecreateService bool `validate:"omitempty" example:"false"`
|
||||
}
|
||||
|
||||
// serviceDeployRequest defines the details needed to execute a service deployment.
|
||||
type serviceDeployRequest struct {
|
||||
ServiceName string `validate:"required"`
|
||||
ServiceDir string `validate:"required"`
|
||||
Env string `validate:"oneof=dev stage prod"`
|
||||
ProjectRoot string `validate:"required"`
|
||||
ProjectName string `validate:"required"`
|
||||
DockerFile string `validate:"required"`
|
||||
GoModFile string `validate:"required"`
|
||||
GoModName string `validate:"required"`
|
||||
|
||||
EnableHTTPS bool `validate:"omitempty"`
|
||||
ServiceHostPrimary string `validate:"omitempty,required_with=EnableHTTPS,fqdn"`
|
||||
ServiceHostNames []string `validate:"omitempty,dive,fqdn"`
|
||||
|
||||
AwsCreds awsCredentials `validate:"required,dive,required"`
|
||||
|
||||
EcrRepositoryName string `validate:"required"`
|
||||
EcrRepository *ecr.CreateRepositoryInput
|
||||
EcrRepositoryMaxImages int `validate:"omitempty"`
|
||||
|
||||
EcsClusterName string `validate:"required"`
|
||||
EcsCluster *ecs.CreateClusterInput
|
||||
|
||||
EcsServiceName string `validate:"required"`
|
||||
EcsServiceDesiredCount int64 `validate:"required"`
|
||||
EcsServiceMinimumHealthyPercent *int64 `validate:"omitempty"`
|
||||
EcsServiceMaximumPercent *int64 `validate:"omitempty"`
|
||||
EscServiceHealthCheckGracePeriodSeconds *int64 `validate:"omitempty"`
|
||||
|
||||
EcsExecutionRoleName string `validate:"required"`
|
||||
EcsExecutionRole *iam.CreateRoleInput
|
||||
EcsExecutionRolePolicyArns []string `validate:"required"`
|
||||
|
||||
EcsTaskRoleName string `validate:"required"`
|
||||
EcsTaskRole *iam.CreateRoleInput
|
||||
|
||||
EcsTaskPolicyName string `validate:"required"`
|
||||
EcsTaskPolicy *iam.CreatePolicyInput
|
||||
EcsTaskPolicyDocument IamPolicyDocument
|
||||
|
||||
Ec2SecurityGroupName string `validate:"required"`
|
||||
Ec2SecurityGroup *ec2.CreateSecurityGroupInput
|
||||
|
||||
CloudWatchLogGroupName string `validate:"required"`
|
||||
CloudWatchLogGroup *cloudwatchlogs.CreateLogGroupInput
|
||||
|
||||
S3BucketTempPrefix string `validate:"required_with=S3BucketPrivateName S3BucketPublicName"`
|
||||
S3BucketPrivateName string `validate:"omitempty"`
|
||||
S3BucketPublicName string `validate:"omitempty"`
|
||||
S3Buckets []S3Bucket
|
||||
|
||||
EnableEcsElb bool `validate:"omitempty"`
|
||||
ElbLoadBalancerName string `validate:"omitempty"`
|
||||
ElbDeregistrationDelay *int `validate:"omitempty"`
|
||||
ElbLoadBalancer *elbv2.CreateLoadBalancerInput
|
||||
|
||||
ElbTargetGroupName string `validate:"omitempty"`
|
||||
ElbTargetGroup *elbv2.CreateTargetGroupInput
|
||||
|
||||
VpcPublicName string `validate:"omitempty"`
|
||||
VpcPublic *ec2.CreateVpcInput
|
||||
VpcPublicSubnets []*ec2.CreateSubnetInput
|
||||
|
||||
EnableLambdaVPC bool `validate:"omitempty"`
|
||||
NoBuild bool `validate:"omitempty"`
|
||||
NoDeploy bool `validate:"omitempty"`
|
||||
NoCache bool `validate:"omitempty"`
|
||||
NoPush bool `validate:"omitempty"`
|
||||
RecreateService bool `validate:"omitempty"`
|
||||
|
||||
SDNamepsace *servicediscovery.CreatePrivateDnsNamespaceInput
|
||||
SDService *servicediscovery.CreateServiceInput
|
||||
|
||||
CacheCluster *elasticache.CreateCacheClusterInput
|
||||
CacheClusterParameter []*elasticache.ParameterNameValue
|
||||
|
||||
DBCluster *rds.CreateDBClusterInput
|
||||
DBInstance *rds.CreateDBInstanceInput
|
||||
|
||||
ReleaseImage string
|
||||
BuildTags []string
|
||||
flags ServiceDeployFlags
|
||||
_awsSession *session.Session
|
||||
}
|
||||
|
||||
type S3Bucket struct {
|
||||
Name string `validate:"omitempty"`
|
||||
Input *s3.CreateBucketInput
|
||||
LifecycleRules []*s3.LifecycleRule
|
||||
CORSRules []*s3.CORSRule
|
||||
PublicAccessBlock *s3.PublicAccessBlockConfiguration
|
||||
Policy string
|
||||
}
|
||||
|
||||
// DB mimics the general info needed for services used to define placeholders.
|
||||
type DB struct {
|
||||
Host string
|
||||
User string
|
||||
Pass string
|
||||
Database string
|
||||
Driver string
|
||||
DisableTLS bool
|
||||
}
|
||||
|
||||
// projectNameCamel takes a project name and returns the camel cased version.
|
||||
func (r *serviceDeployRequest) ProjectNameCamel() string {
|
||||
s := strings.Replace(r.ProjectName, "_", " ", -1)
|
||||
s = strings.Replace(s, "-", " ", -1)
|
||||
s = strcase.ToCamel(s)
|
||||
return s
|
||||
}
|
||||
|
||||
// awsSession returns the current AWS session for the serviceDeployRequest.
|
||||
func (r *serviceDeployRequest) awsSession() *session.Session {
|
||||
if r._awsSession == nil {
|
||||
r._awsSession = r.AwsCreds.Session()
|
||||
}
|
||||
|
||||
return r._awsSession
|
||||
}
|
||||
|
||||
// AwsCredentials defines AWS credentials used for deployment. Unable to use roles when deploying
|
||||
// using gitlab CI/CD pipeline.
|
||||
type awsCredentials struct {
|
||||
AccessKeyID string `validate:"required"`
|
||||
SecretAccessKey string `validate:"required"`
|
||||
Region string `validate:"required"`
|
||||
}
|
||||
|
||||
// Session returns a new AWS Session used to access AWS services.
|
||||
func (creds awsCredentials) Session() *session.Session {
|
||||
return session.New(
|
||||
&aws.Config{
|
||||
Region: aws.String(creds.Region),
|
||||
Credentials: credentials.NewStaticCredentials(creds.AccessKeyID, creds.SecretAccessKey, ""),
|
||||
})
|
||||
}
|
||||
|
||||
// IamPolicyDocument defines an AWS IAM policy used for defining access for IAM roles, users, and groups.
|
||||
type IamPolicyDocument struct {
|
||||
Version string `json:"Version"`
|
||||
Statement []IamStatementEntry `json:"Statement"`
|
||||
}
|
||||
|
||||
// IamStatementEntry defines a single statement for an IAM policy.
|
||||
type IamStatementEntry struct {
|
||||
Sid string `json:"Sid"`
|
||||
Effect string `json:"Effect"`
|
||||
Action []string `json:"Action"`
|
||||
Resource interface{} `json:"Resource"`
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user