aws.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. package tools
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. "github.com/aws/aws-sdk-go-v2/aws"
  12. "github.com/aws/aws-sdk-go-v2/config"
  13. "github.com/aws/aws-sdk-go-v2/credentials"
  14. "github.com/aws/aws-sdk-go-v2/service/cloudformation"
  15. cftypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types"
  16. "github.com/aws/aws-sdk-go-v2/service/ec2/types"
  17. "github.com/aws/aws-sdk-go-v2/service/s3"
  18. )
  19. func AWS() *awstool {
  20. ctx := context.TODO()
  21. accessKeyID := os.Getenv("AWS_ACCESS_KEY_ID")
  22. secretAccessKey := os.Getenv("AWS_SECRET_ACCESS_KEY")
  23. sessionToken := os.Getenv("AWS_SESSION_TOKEN")
  24. staticProvider := credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, sessionToken)
  25. cfg, err := config.LoadDefaultConfig(ctx,
  26. config.WithCredentialsProvider(staticProvider),
  27. config.WithRegion(os.Getenv("AWS_REGION")),
  28. )
  29. if err != nil {
  30. log.Write([]byte(fmt.Sprintf("unable to load SDK config, %v", err)))
  31. }
  32. return &awstool{
  33. cfg: cfg,
  34. }
  35. }
  36. type (
  37. awstool struct {
  38. cfg aws.Config
  39. }
  40. awss3 struct {
  41. aws *awstool
  42. }
  43. awsec2 struct {
  44. aws *awstool
  45. }
  46. awscloudformation struct {
  47. aws *awstool
  48. }
  49. awsimagebuilder struct {
  50. aws *awstool
  51. }
  52. awsecs struct {
  53. aws *awstool
  54. }
  55. awseks struct {
  56. aws *awstool
  57. }
  58. )
  59. func (t *awstool) S3() *awss3 { return &awss3{aws: t} }
  60. func (t *awstool) EC2() *awsec2 { return &awsec2{aws: t} }
  61. func (t *awstool) CloudFormation() *awscloudformation { return &awscloudformation{aws: t} }
  62. func (t *awstool) ImageBuilder() *awsimagebuilder { return &awsimagebuilder{aws: t} }
  63. func (t *awstool) ECS() *awsecs { return &awsecs{aws: t} }
  64. func (t *awstool) EKS() *awseks { return &awseks{aws: t} }
  65. func (t *awstool) Filter(filters map[string][]string) []types.Filter {
  66. filter := []types.Filter{}
  67. for k, v := range filters {
  68. filter = append(filter, types.Filter{
  69. Name: aws.String(k),
  70. Values: v,
  71. })
  72. }
  73. return filter
  74. }
  75. func (t *awss3) Put(src, bucket, key string) error {
  76. api := s3.NewFromConfig(t.aws.cfg)
  77. f, err := os.Open(src)
  78. if err != nil {
  79. return err
  80. }
  81. defer f.Close()
  82. _, err = api.PutObject(context.TODO(), &s3.PutObjectInput{
  83. Bucket: aws.String(bucket),
  84. Key: aws.String(key),
  85. Body: f,
  86. })
  87. if err != nil {
  88. return err
  89. }
  90. return nil
  91. }
  92. func (t *awss3) Write(content []byte, bucket, key string) error {
  93. api := s3.NewFromConfig(t.aws.cfg)
  94. f := bytes.NewReader(content)
  95. _, err := api.PutObject(context.TODO(), &s3.PutObjectInput{
  96. Bucket: aws.String(bucket),
  97. Key: aws.String(key),
  98. Body: f,
  99. })
  100. if err != nil {
  101. return err
  102. }
  103. return nil
  104. }
  105. func (t *awss3) WriteString(content, bucket, key string) error {
  106. api := s3.NewFromConfig(t.aws.cfg)
  107. f := strings.NewReader(content)
  108. _, err := api.PutObject(context.TODO(), &s3.PutObjectInput{
  109. Bucket: aws.String(bucket),
  110. Key: aws.String(key),
  111. Body: f,
  112. })
  113. if err != nil {
  114. return err
  115. }
  116. return nil
  117. }
  118. func (t *awss3) PutDir(path, bucket, s3Prefix string) error {
  119. api := s3.NewFromConfig(t.aws.cfg)
  120. err := filepath.WalkDir(path, func(p string, d os.DirEntry, err error) error {
  121. if !d.IsDir() {
  122. relPath, _ := filepath.Rel(path, p)
  123. s3Key := filepath.ToSlash(filepath.Join(s3Prefix, relPath))
  124. file, err := os.Open(p)
  125. if err == nil {
  126. return err
  127. }
  128. defer file.Close()
  129. api.PutObject(context.TODO(), &s3.PutObjectInput{
  130. Bucket: aws.String(bucket),
  131. Key: aws.String(s3Key),
  132. Body: file,
  133. })
  134. }
  135. return nil
  136. })
  137. if err != nil {
  138. return err
  139. }
  140. return nil
  141. }
  142. func (t *awss3) Get(bucket, key, dst string) error {
  143. api := s3.NewFromConfig(t.aws.cfg)
  144. output, err := api.GetObject(context.TODO(), &s3.GetObjectInput{
  145. Bucket: aws.String(bucket),
  146. Key: aws.String(key),
  147. })
  148. if err != nil {
  149. return err
  150. }
  151. f, err := os.Create(dst)
  152. if err != nil {
  153. return err
  154. }
  155. _, err = io.Copy(f, output.Body)
  156. return err
  157. }
  158. func (t *awss3) Read(bucket, key string) ([]byte, error) {
  159. api := s3.NewFromConfig(t.aws.cfg)
  160. output, err := api.GetObject(context.TODO(), &s3.GetObjectInput{
  161. Bucket: aws.String(bucket),
  162. Key: aws.String(key),
  163. })
  164. if err != nil {
  165. return nil, err
  166. }
  167. return io.ReadAll(output.Body)
  168. }
  169. func (t *awss3) ListObjects(bucket, path string) error { return nil }
  170. func (t *awss3) ListBuckets(prefix string) ([]string, error) {
  171. api := s3.NewFromConfig(t.aws.cfg)
  172. output, err := api.ListBuckets(context.TODO(), &s3.ListBucketsInput{
  173. Prefix: &prefix,
  174. })
  175. if err != nil {
  176. return nil, err
  177. }
  178. buckets := []string{}
  179. for _, bucket := range output.Buckets {
  180. buckets = append(buckets, *bucket.Name)
  181. }
  182. return buckets, nil
  183. }
  184. func (t *awsec2) ListIAMRoles(filter []types.Filter) error { return nil }
  185. func (t *awsec2) FindLatestAMI(filter []types.Filter) error { return nil }
  186. func (t *awsec2) ListSubnets(filter []types.Filter) error { return nil }
  187. func (t *awsec2) ListSecurityGroups(filter []types.Filter) error { return nil }
  188. func (t *awsec2) ListVPCs(filter []types.Filter) error { return nil }
  189. func (t *awsec2) ListKeypairs(filter []types.Filter) error { return nil }
  190. func (t *awsec2) List(filter []types.Filter) error { return nil }
  191. func (t *awsec2) Create() error { return nil }
  192. func (t *awsec2) Stop() error { return nil }
  193. func (t *awsec2) Start() error { return nil }
  194. func (t *awsec2) Terminate() error { return nil }
  195. func (t *awscloudformation) CreateStack(stackName, templatePath string, params, tags map[string]string) error {
  196. ctx := context.TODO()
  197. client := cloudformation.NewFromConfig(t.aws.cfg)
  198. templateBody, err := os.ReadFile(templatePath)
  199. if err != nil {
  200. return fmt.Errorf("unable to read template file %s, %v", templatePath, err)
  201. }
  202. aparams := []cftypes.Parameter{}
  203. for k, v := range params {
  204. aparams = append(aparams, cftypes.Parameter{
  205. ParameterKey: aws.String(k),
  206. ParameterValue: aws.String(v),
  207. })
  208. }
  209. atags := []cftypes.Tag{}
  210. for k, v := range tags {
  211. atags = append(atags, cftypes.Tag{
  212. Key: aws.String(k),
  213. Value: aws.String(v),
  214. })
  215. }
  216. input := &cloudformation.CreateStackInput{
  217. StackName: aws.String(stackName),
  218. TemplateBody: aws.String(string(templateBody)),
  219. Parameters: aparams,
  220. Capabilities: []cftypes.Capability{
  221. cftypes.CapabilityCapabilityNamedIam,
  222. },
  223. Tags: atags,
  224. }
  225. result, err := client.CreateStack(ctx, input)
  226. if err != nil {
  227. return fmt.Errorf("failed to create stack %s, %v", stackName, err)
  228. }
  229. log.Write([]byte(fmt.Sprintf("Stack creation initiated. Stack ID: %s\n", aws.ToString(result.StackId))))
  230. return nil
  231. }
  232. func (t *awscloudformation) UpdateStack(stackName, templatePath string, params, tags map[string]string) error {
  233. ctx := context.TODO()
  234. client := cloudformation.NewFromConfig(t.aws.cfg)
  235. templateBody, err := os.ReadFile(templatePath)
  236. if err != nil {
  237. return fmt.Errorf("unable to read template file %s, %v", templatePath, err)
  238. }
  239. aparams := []cftypes.Parameter{}
  240. for k, v := range params {
  241. aparams = append(aparams, cftypes.Parameter{
  242. ParameterKey: aws.String(k),
  243. ParameterValue: aws.String(v),
  244. })
  245. }
  246. atags := []cftypes.Tag{}
  247. for k, v := range tags {
  248. atags = append(atags, cftypes.Tag{
  249. Key: aws.String(k),
  250. Value: aws.String(v),
  251. })
  252. }
  253. input := &cloudformation.UpdateStackInput{
  254. StackName: aws.String(stackName),
  255. TemplateBody: aws.String(string(templateBody)),
  256. Parameters: aparams,
  257. Capabilities: []cftypes.Capability{
  258. cftypes.CapabilityCapabilityNamedIam,
  259. },
  260. Tags: atags,
  261. }
  262. result, err := client.UpdateStack(ctx, input)
  263. if err != nil {
  264. return fmt.Errorf("failed to update stack %s, %v", stackName, err)
  265. }
  266. log.Write([]byte(fmt.Sprintf("Stack update initiated. Stack ID: %s\n", aws.ToString(result.StackId))))
  267. return nil
  268. }
  269. func (t *awscloudformation) DeleteStack(stackName string) error {
  270. ctx := context.TODO()
  271. client := cloudformation.NewFromConfig(t.aws.cfg)
  272. input := &cloudformation.DeleteStackInput{
  273. StackName: aws.String(stackName),
  274. }
  275. _, err := client.DeleteStack(ctx, input)
  276. if err != nil {
  277. return fmt.Errorf("failed to delete stack %s, %v", stackName, err)
  278. }
  279. return nil
  280. }
  281. func (t *awscloudformation) GetStack(stackName string) (*cftypes.Stack, error) {
  282. ctx := context.TODO()
  283. client := cloudformation.NewFromConfig(t.aws.cfg)
  284. input := &cloudformation.DescribeStacksInput{
  285. StackName: aws.String(stackName),
  286. }
  287. res, err := client.DescribeStacks(ctx, input)
  288. if err != nil {
  289. return nil, fmt.Errorf("failed to describe stack %s, %v", stackName, err)
  290. }
  291. for _, s := range res.Stacks {
  292. if s.StackName == &stackName {
  293. return &s, nil
  294. }
  295. }
  296. return nil, errors.New("stack not found")
  297. }
  298. func (t *awsimagebuilder) Component() error { return nil }
  299. func (t *awsimagebuilder) Recipe() error { return nil }
  300. func (t *awsimagebuilder) Pipeline() error { return nil }
  301. func (t *awsimagebuilder) RunPipeline() error { return nil }
  302. func (t *awsecs) Cluster() error { return nil }
  303. func (t *awsecs) Task() error { return nil }
  304. func (t *awseks) UpgradeCluster() error { return nil }