scout-camp 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de2b027b60ec3f0c33cb643258e365f129b217368040cc49d6df0b7232d643f9
4
- data.tar.gz: a89e3ed2424d5eb99f107314bab8f6406297b1e2961d6b7fb084f652abcb4705
3
+ metadata.gz: aca4938597e0fc0bed97dbb0aa2b88821a71c27dfd3b4d96ec9876acaee294be
4
+ data.tar.gz: c6d270e7f0b8fb479f6032cb39643b54c4e7182444746b52eb78e0875b7355f0
5
5
  SHA512:
6
- metadata.gz: 30a2f0f6b5f1c28dfb6b2c364c78e8efa10c1dca04ad5a53ca651c62607c41ec74981a4729e885b778954e67dd5be4fcd6c27b12ea976bfc71854c55f97a15f7
7
- data.tar.gz: 5c598b2cc4295153b2c2ad8cd7105c7d9b4dfb37b6a176065520523159e8de67167b5a211d06bcdef8322bd3f59b3414734ef1ac380fd80996ebf1fe07a49600
6
+ metadata.gz: b178c0cf9038d614f0a0c4f19a8d03ea3b5f18194c803d13eb98ee3e06fa818568e0796d094c37402ae8396ddfb861d15fb9a91aef184cd1ce6180daa95618c8
7
+ data.tar.gz: db7cb1136f29a209b8e64ef2953132bc0de7f87a5484efe2d9f3f59eb263020c8e7ceff53f51f919568981cf9ffc5691fe4e8880dc59b55ecc6fdfbcb4925bdb
data/.vimproject CHANGED
@@ -47,10 +47,22 @@ scout-camp=/$PWD filter="*" {
47
47
  share=share {
48
48
  terraform=terraform {
49
49
  aws=aws {
50
+ event_bridge=event_bridge{
51
+ main.tf
52
+ data.tf
53
+ variables.tf
54
+ }
55
+
56
+ lambda=lambda {
57
+ main.tf
58
+ variables.tf
59
+ }
60
+
50
61
  fargate=fargate{
51
62
  main.tf
52
63
  variables.tf
53
64
  locals.tf
65
+ output.tf
54
66
  }
55
67
 
56
68
  efs_host=efs_host{
@@ -82,13 +94,9 @@ scout-camp=/$PWD filter="*" {
82
94
  variables.tf
83
95
  }
84
96
 
85
- lambda=lambda {
86
- main.tf
87
- variables.tf
88
- }
89
-
90
97
  container_lambda=container_lambda{
91
98
  main.tf
99
+ data.tf
92
100
  locals.tf
93
101
  variables.tf
94
102
  }
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.10
1
+ 0.1.12
data/lib/scout/aws/s3.rb CHANGED
@@ -21,14 +21,18 @@ module Open
21
21
  uri.start_with? 's3://'
22
22
  end
23
23
 
24
- def self.claim(uri, ...)
24
+ def self.claim_uri(uri)
25
25
  if Path === uri and not uri.located?
26
- is_s3? uri.find
26
+ is_s3?(uri.find)
27
27
  else
28
28
  is_s3? uri
29
29
  end
30
30
  end
31
31
 
32
+ def self.claim(uri, uri2=nil, ...)
33
+ claim_uri(uri) || (String === uri2 && claim_uri(uri2))
34
+ end
35
+
32
36
  def self.parse_s3_uri(uri)
33
37
  uri = uri.find if Path === uri and not uri.located?
34
38
  uri = uri.sub(%r{^s3://}, '')
@@ -66,13 +70,12 @@ module Open
66
70
  end
67
71
  end
68
72
 
69
- def self.glob(uri, pattern="**/*")
73
+ def self.glob(uri, pattern="*")
70
74
  bucket, prefix = parse_s3_uri(uri)
71
75
  s3 = Aws::S3::Client.new
72
76
  matches = []
73
77
  continuation_token = nil
74
78
 
75
- Log.debug "Glob: #{uri} #{pattern}"
76
79
  loop do
77
80
  resp = s3.list_objects_v2(
78
81
  bucket: bucket,
@@ -156,20 +159,29 @@ module Open
156
159
 
157
160
  def self.cp(source, target)
158
161
  if is_s3?(target)
159
- source_bucket, source_key = parse_s3_uri(source)
160
- target_bucket, target_key = parse_s3_uri(target)
161
-
162
- s3 = Aws::S3::Client.new
163
- s3.copy_object({
164
- copy_source: "#{source_bucket}/#{source_key}",
165
- bucket: target_bucket,
166
- key: target_key
167
- })
162
+ if is_s3?(source)
163
+ source_bucket, source_key = parse_s3_uri(source)
164
+ target_bucket, target_key = parse_s3_uri(target)
165
+
166
+ s3 = Aws::S3::Client.new
167
+ s3.copy_object({
168
+ copy_source: "#{source_bucket}/#{source_key}",
169
+ bucket: target_bucket,
170
+ key: target_key
171
+ })
172
+ else
173
+ self.write(target, Open.get_stream(source))
174
+ end
168
175
  else
169
176
  Open.sensible_write(target, get_stream(source))
170
177
  end
171
178
  end
172
179
 
180
+ def self.mv(source, target)
181
+ self.cp(source, target)
182
+ Open.rm_rf source
183
+ end
184
+
173
185
  def self.file_exists?(uri)
174
186
  bucket, key = parse_s3_uri(uri)
175
187
  return false if key.empty? # Can't check existence of bucket this way
@@ -185,6 +197,7 @@ module Open
185
197
  bucket, key = parse_s3_uri(uri)
186
198
  return false if key.empty? # Can't check existence of bucket this way
187
199
 
200
+ key += '/' unless key.end_with?('/')
188
201
  s3 = Aws::S3::Client.new
189
202
  response = s3.list_objects_v2({
190
203
  bucket: bucket,
@@ -224,6 +237,68 @@ module Open
224
237
  def self.ln_s(source, target, options = {})
225
238
  cp(source, target)
226
239
  end
240
+
241
+ def self.sync(source, target, options = {})
242
+ excludes, files, hard_link, test, print, delete, other = IndiferentHash.process_options options,
243
+ :excludes, :files, :hard_link, :test, :print, :delete, :other
244
+
245
+ excludes ||= %w(.save .crap .source tmp filecache open-remote)
246
+ excludes = excludes.split(/,\s*/) if excludes.is_a?(String) and not excludes.include?("--exclude")
247
+
248
+ if File.directory?(source) || source.end_with?("/")
249
+ source += "/" unless source.end_with? '/'
250
+ target += "/" unless target.end_with? '/'
251
+ end
252
+
253
+ if source == target
254
+ Log.warn "Asking to sync with itself"
255
+ return
256
+ end
257
+
258
+ Log.low "Migrating #{source} #{files.length} files to #{target} - #{Misc.fingerprint(files)}}" if files
259
+
260
+ sync_args = %w()
261
+ sync_args << excludes.collect{|s| "--exclude '#{s}'" } if excludes and excludes.any?
262
+ sync_args << "-nv" if test
263
+
264
+ if files
265
+ tmp_files = TmpFile.tmp_file 's3_sync_files-'
266
+ Open.write(tmp_files, files * "\n")
267
+ sync_args << "--files-from='#{tmp_files}'"
268
+ end
269
+
270
+ if Open.directory?(source)
271
+ cmd = "aws s3 sync #{sync_args * " "} #{source} #{target}"
272
+ else
273
+ cmd = "aws s3 cp #{source} #{target}"
274
+ end
275
+ case other
276
+ when String
277
+ cmd << " " << other
278
+ when Array
279
+ cmd << " " << other * " "
280
+ end
281
+ cmd << " && rm -Rf #{source}" if delete && ! files
282
+
283
+ if print
284
+ cmd
285
+ else
286
+ CMD.cmd_log(cmd, :log => Log::HIGH)
287
+
288
+ if delete && files
289
+ remove_files = files.collect{|f| File.join(source, f) }
290
+ dirs = remove_files.select{|f| File.directory? f }
291
+ remove_files.each do |file|
292
+ next if dirs.include? file
293
+ Open.rm file
294
+ end
295
+
296
+ dirs.each do |dir|
297
+ FileUtils.rmdir dir if Dir.glob(dir).empty?
298
+ end
299
+ end
300
+ end
301
+ end
227
302
  end
228
303
  end
229
304
 
@@ -11,7 +11,7 @@ module Resource
11
11
  resource = path.pkgdir if resource.nil? and path.is_a?(Path) and path.pkgdir.is_a?(Resource)
12
12
  resource = Resource.default_resource if resource.nil?
13
13
 
14
- if File.exist?(path)
14
+ if Path.located?(path)
15
15
  real_paths = [path]
16
16
  else
17
17
  path = Path.setup(path, pkgdir: resource) unless path.is_a?(Path)
data/scout-camp.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: scout-camp 0.1.10 ruby lib
5
+ # stub: scout-camp 0.1.12 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "scout-camp".freeze
9
- s.version = "0.1.10".freeze
9
+ s.version = "0.1.12".freeze
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Miguel Vazquez".freeze]
14
- s.date = "2025-04-16"
14
+ s.date = "1980-01-02"
15
15
  s.description = "Functionalities to deploy and use scouts in remote servers like AWS".freeze
16
16
  s.email = "mikisvaz@gmail.com".freeze
17
17
  s.executables = ["scout-camp".freeze]
@@ -72,8 +72,12 @@ Gem::Specification.new do |s|
72
72
  "share/terraform/aws/efs_host/main.tf",
73
73
  "share/terraform/aws/efs_host/output.tf",
74
74
  "share/terraform/aws/efs_host/variables.tf",
75
+ "share/terraform/aws/event_bridge/data.tf",
76
+ "share/terraform/aws/event_bridge/main.tf",
77
+ "share/terraform/aws/event_bridge/variables.tf",
75
78
  "share/terraform/aws/fargate/locals.tf",
76
79
  "share/terraform/aws/fargate/main.tf",
80
+ "share/terraform/aws/fargate/output.tf",
77
81
  "share/terraform/aws/fargate/variables.tf",
78
82
  "share/terraform/aws/host/locals.tf",
79
83
  "share/terraform/aws/host/main.tf",
@@ -112,7 +116,7 @@ Gem::Specification.new do |s|
112
116
  ]
113
117
  s.homepage = "http://github.com/mikisvaz/scout-camp".freeze
114
118
  s.licenses = ["MIT".freeze]
115
- s.rubygems_version = "3.6.6".freeze
119
+ s.rubygems_version = "3.6.7".freeze
116
120
  s.summary = "Deploy you scouts".freeze
117
121
 
118
122
  s.specification_version = 4
data/scout_commands/sync CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'scout'
4
4
  require 'scout/offsite/resource'
5
+ require 'scout/aws/s3'
5
6
 
6
7
  $0 = "scout #{$previous_commands.any? ? $previous_commands*" " + " " : "" }#{ File.basename(__FILE__) }" if $previous_commands
7
8
 
@@ -14,6 +14,7 @@ $ #{$0} [<options>] <workflow> <task> [<other|->]*
14
14
  --prefix* Prefix, defaults to Scout
15
15
  --queue Queue job
16
16
  --clean Clean job
17
+ --info Return job info
17
18
  --recursive_clean Clean job recursively
18
19
  EOF
19
20
  workflow, task_name = ARGV
@@ -27,9 +28,9 @@ if workflow.nil? && options[:help]
27
28
  exit 0
28
29
  end
29
30
 
30
- raise ParamterException, "No workflow specified" if workflow.nil?
31
+ raise ParameterException, "No workflow specified" if workflow.nil?
31
32
 
32
- prefix, clean, recursive_clean, queue = IndiferentHash.process_options options, :prefix, :clean, :recursive_clean, :queue,
33
+ prefix, clean, recursive_clean, queue, info = IndiferentHash.process_options options, :prefix, :clean, :recursive_clean, :queue, :info,
33
34
  prefix: "Scout"
34
35
 
35
36
  require 'aws-sdk-lambda'
@@ -116,6 +117,8 @@ res = case task_name
116
117
  exit 0
117
118
  end
118
119
 
120
+ payload["info"] = true if info
121
+
119
122
  aws_lambda(lambda_handler, payload)
120
123
  end
121
124
 
@@ -7,8 +7,13 @@ def lambda_handler(event:, context:)
7
7
  require 'scout/workflow'
8
8
  require 'scout/aws/s3'
9
9
 
10
- workflow, task_name, jobname, inputs, clean, queue = IndiferentHash.process_options event,
11
- :workflow, :task_name, :jobname, :inputs, :clean, :queue
10
+ TmpFile.tmpdir = Path.setup('/tmp')
11
+ Open.sensible_write_dir = Path.setup('/tmp/sensible_write')
12
+
13
+ Log.info "Payload: #{Log.fingerprint(event)}"
14
+
15
+ workflow, task_name, jobname, inputs, clean, queue, info = IndiferentHash.process_options event,
16
+ :workflow, :task_name, :jobname, :inputs, :clean, :queue, :info
12
17
 
13
18
  raise ParameterException, "No workflow specified" if workflow.nil?
14
19
 
@@ -21,6 +26,8 @@ def lambda_handler(event:, context:)
21
26
  raise ParameterException, "No task_name specified" if task_name.nil?
22
27
  return workflow.task_info(inputs["task_name"])
23
28
  else
29
+ Workflow.job_cache.clear
30
+
24
31
  job = workflow.job(task_name, jobname, inputs)
25
32
 
26
33
  case clean
@@ -30,7 +37,11 @@ def lambda_handler(event:, context:)
30
37
  job.recursive_clean
31
38
  end
32
39
 
33
- if job.done?
40
+ if info
41
+ info = job.info.dup
42
+ info["path"] = job.path
43
+ info
44
+ elsif job.done?
34
45
  job.load
35
46
  elsif job.error?
36
47
  raise job.exception
@@ -40,8 +51,8 @@ def lambda_handler(event:, context:)
40
51
  body: job.path
41
52
  }
42
53
  elsif queue
43
- save_inputs = Scout.var.queue[workflow.to_s][task_name][job.name].find
44
- job.save_inputs(save_inputs)
54
+ save_inputs = Scout.var.queue[workflow.to_s][task_name][job.name].find :bucket
55
+ job.save_input_bundle(save_inputs) unless save_inputs.exists?
45
56
  {
46
57
  statusCode: 202,
47
58
  body: job.path
@@ -0,0 +1,10 @@
1
+ data "aws_vpc" "default" {
2
+ default = true
3
+ }
4
+
5
+ data "aws_subnets" "default" {
6
+ filter {
7
+ name = "vpc-id"
8
+ values = [data.aws_vpc.default.id]
9
+ }
10
+ }
@@ -0,0 +1,85 @@
1
+ # IAM Role for EventBridge to trigger ECS task
2
+ resource "aws_iam_role" "eventbridge_invoke_ecs" {
3
+ name = "eventbridge_invoke_ecs"
4
+
5
+ assume_role_policy = jsonencode({
6
+ Version = "2012-10-17",
7
+ Statement = [
8
+ {
9
+ Effect = "Allow",
10
+ Principal = {
11
+ Service = "events.amazonaws.com"
12
+ },
13
+ Action = "sts:AssumeRole"
14
+ }
15
+ ]
16
+ })
17
+ }
18
+
19
+ # Permissions for EventBridge to run the task
20
+ resource "aws_iam_role_policy" "ecs_task_invoke_policy" {
21
+ role = aws_iam_role.eventbridge_invoke_ecs.name
22
+
23
+ policy = jsonencode({
24
+ Version = "2012-10-17",
25
+ Statement = [
26
+ {
27
+ Effect = "Allow",
28
+ Action = [
29
+ "ecs:RunTask"
30
+ ],
31
+ Resource = "*"
32
+ },
33
+ {
34
+ Effect = "Allow",
35
+ Action = [
36
+ "iam:PassRole"
37
+ ],
38
+ Resource = "*"
39
+ }
40
+ ]
41
+ })
42
+ }
43
+
44
+ # EventBridge rule triggered on S3 put event
45
+ resource "aws_cloudwatch_event_rule" "s3_put_event" {
46
+ name = "s3-put-to-uploads"
47
+ description = "Triggers Fargate task on S3 file upload"
48
+ event_pattern = jsonencode({
49
+ source = ["aws.s3"],
50
+ "detail-type" = ["Object Created"],
51
+ detail = {
52
+ bucket = {
53
+ name = [var.bucket]
54
+ },
55
+ object = {
56
+ key = [{
57
+ prefix = var.directory
58
+ }]
59
+ }
60
+ }
61
+ })
62
+ }
63
+
64
+ # Target: ECS Fargate task
65
+ resource "aws_cloudwatch_event_target" "run_fargate" {
66
+ rule = aws_cloudwatch_event_rule.s3_put_event.name
67
+ arn = var.cluster_arn # Replace with your ECS Cluster ARN
68
+ role_arn = aws_iam_role.eventbridge_invoke_ecs.arn
69
+
70
+ ecs_target {
71
+ task_definition_arn = var.task_arn
72
+ launch_type = "FARGATE"
73
+ network_configuration {
74
+ assign_public_ip = true
75
+ subnets = data.aws_subnets.default.ids
76
+ }
77
+ }
78
+ }
79
+
80
+ # Allow S3 to send events to EventBridge
81
+ #resource "aws_s3_bucket_notification" "s3_event" {
82
+ # bucket = var.bucket_name
83
+ #
84
+ # eventbridge = true
85
+ #}
@@ -0,0 +1,19 @@
1
+ # Replace with your actual bucket
2
+ variable "bucket" {
3
+ type = string
4
+ }
5
+
6
+ variable "directory" {
7
+ type = string
8
+ }
9
+
10
+ variable "task_arn" {
11
+ type = string
12
+ }
13
+
14
+ variable "cluster_arn" {
15
+ type = string
16
+ }
17
+
18
+
19
+
@@ -0,0 +1,10 @@
1
+ output "task_arn" {
2
+ description = "Task arn"
3
+ value = aws_ecs_task_definition.this.arn
4
+ }
5
+
6
+ output "cluster_arn" {
7
+ description = "Task arn"
8
+ value = aws_ecs_cluster.this.arn
9
+ }
10
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout-camp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-16 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: scout-essentials
@@ -84,8 +84,12 @@ files:
84
84
  - share/terraform/aws/efs_host/main.tf
85
85
  - share/terraform/aws/efs_host/output.tf
86
86
  - share/terraform/aws/efs_host/variables.tf
87
+ - share/terraform/aws/event_bridge/data.tf
88
+ - share/terraform/aws/event_bridge/main.tf
89
+ - share/terraform/aws/event_bridge/variables.tf
87
90
  - share/terraform/aws/fargate/locals.tf
88
91
  - share/terraform/aws/fargate/main.tf
92
+ - share/terraform/aws/fargate/output.tf
89
93
  - share/terraform/aws/fargate/variables.tf
90
94
  - share/terraform/aws/host/locals.tf
91
95
  - share/terraform/aws/host/main.tf
@@ -139,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
143
  - !ruby/object:Gem::Version
140
144
  version: '0'
141
145
  requirements: []
142
- rubygems_version: 3.6.6
146
+ rubygems_version: 3.6.7
143
147
  specification_version: 4
144
148
  summary: Deploy you scouts
145
149
  test_files: []