lambda-microvms 0.1.0 → 0.2.0

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: 296c088486e240241e9e84b8932be4b07dd929aa4168b3b88d96347c5f6e9173
4
- data.tar.gz: 8b3b9880d86869ef123247fb635d3a09bbc812bc6512ea6a45e6983c2414c04a
3
+ metadata.gz: c2278501b187e57ed03eacd396649c19e09bd5c6e07e890f5ce0403588c8f2fb
4
+ data.tar.gz: c8f240355cdc41e80e5d1d31a231e31cac3e6fd77d488f584e1027df0a47db0a
5
5
  SHA512:
6
- metadata.gz: 114c31806d2c30c3682b9f33a79ddc2b3b114a5c4898f48f1fa07edf5ecf5e61bdd2cdc9d49150ca415715bb8e1a911335bd44a59f6277adb8e50ca424235a23
7
- data.tar.gz: 713a3dabdfeac0e9dad4ea3212fa556295e6b77ee9929daf919ec56c6f01c8cce1e384220548a17fff6bb2e900ffe4903a21650edcfbe7929f7400b420c8eaee
6
+ metadata.gz: 22bc5c257c1650f571cdf560a4c32af34cd119341776cb42a707104620255bbd0e26091b4967acc88462ca873e8319c5109aa9ee46fa26ceb0634207c32526bd
7
+ data.tar.gz: 942370b040e49ece5f159226f0da4094f05b054c7636210150f2858d768c863e9deb3997d72dff212c707542812134a230850f2ebef06b8478c9af089c288f72
data/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.0 Unreleased
3
+ ## Unreleased
4
+
5
+ ## 0.2.0
6
+
7
+ - Added `lambda-microvms sdk-contract` and doctor output for the experimental MicroVM SDK operation contract.
8
+ - Added an adapter boundary for MicroVM SDK operations.
9
+ - Added `Lambda::MicroVMs::FunctionClient` and `lambda-microvms function-invoke` for standard Lambda function APIs.
10
+ - Made MicroVM deploy/run fail before packaging or uploading when the installed `aws-sdk-lambda` lacks MicroVM operations.
11
+
12
+ ## 0.1.0
4
13
 
5
14
  - Initial Ruby development kit for AWS Lambda MicroVMs.
6
15
  - Client wrapper over `aws-sdk-lambda`.
data/README.md CHANGED
@@ -5,9 +5,9 @@
5
5
  [![Ruby Version](https://img.shields.io/badge/ruby-%3E%3D%203.2-ruby.svg)](https://www.ruby-lang.org/en/)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- A Ruby development kit for AWS Lambda MicroVMs.
8
+ A Ruby development kit for AWS Lambda MicroVM experiments and standard Lambda function workflows.
9
9
 
10
- `lambda-microvms` builds on the official `aws-sdk-lambda` gem. It provides Ruby resource objects, lifecycle helpers, endpoint calls, project scaffolding, packaging, and deployment commands for Lambda MicroVM applications.
10
+ `lambda-microvms` builds on the official `aws-sdk-lambda` gem. It provides Ruby resource objects, lifecycle helpers, endpoint calls, project scaffolding, packaging, experimental MicroVM deployment commands, and a supported Lambda function client for APIs that exist today.
11
11
 
12
12
  It gives Ruby developers a higher-level workflow:
13
13
 
@@ -77,7 +77,15 @@ gem "aws_lambda_ric"
77
77
  lambda-microvms doctor
78
78
  ```
79
79
 
80
- Checks Ruby, Docker, AWS CLI, project config, Dockerfile, deployment bucket, runtime role, and `aws_lambda_ric` presence.
80
+ Checks Ruby, Docker, AWS CLI, project config, Dockerfile, deployment bucket, runtime role, `aws_lambda_ric` presence, and whether the installed `aws-sdk-lambda` exposes the experimental MicroVM operation contract.
81
+
82
+ ## Check the MicroVM SDK contract
83
+
84
+ ```bash
85
+ lambda-microvms sdk-contract
86
+ ```
87
+
88
+ The public `aws-sdk-lambda` gem may not expose MicroVM lifecycle operations such as `create_microvm_image` or `run_microvm`. When those methods are missing, MicroVM `deploy` and `run` fail before packaging or uploading artifacts.
81
89
 
82
90
  ## Package
83
91
 
@@ -113,6 +121,30 @@ lambda-microvms run
113
121
 
114
122
  Runs the configured image ARN with the configured role ARN and runtime payload.
115
123
 
124
+ ## Standard Lambda function APIs
125
+
126
+ The gem also includes a supported path for regular Lambda function APIs available in `aws-sdk-lambda` today.
127
+
128
+ ```ruby
129
+ client = Lambda::MicroVMs::FunctionClient.new(region: "us-east-1")
130
+
131
+ client.create_function(
132
+ name: "ruby-worker",
133
+ role_arn: "arn:aws:iam::123456789012:role/lambda-runtime",
134
+ handler: "app.Handler.process",
135
+ runtime: "ruby3.4",
136
+ zip_file: "tmp/function.zip"
137
+ )
138
+
139
+ result = client.invoke(function_name: "ruby-worker", payload: { hello: "world" })
140
+ ```
141
+
142
+ You can also invoke an existing function from the CLI:
143
+
144
+ ```bash
145
+ lambda-microvms function-invoke ruby-worker '{"hello":"world"}'
146
+ ```
147
+
116
148
  ## Ruby SDK usage
117
149
 
118
150
  ```ruby
@@ -169,6 +201,7 @@ Lambda::MicroVMs::Client
169
201
  ├── MicroVM
170
202
  ├── Endpoint
171
203
  ├── Session
204
+ ├── FunctionClient
172
205
  ├── Scaffold
173
206
  ├── Packager
174
207
  └── Deployer
@@ -176,5 +209,6 @@ Lambda::MicroVMs::Client
176
209
 
177
210
  ## Status
178
211
 
179
- This is an early implementation. Lambda MicroVMs is new, so generated AWS SDK operation shapes may evolve. Unsupported low-level operations raise `Lambda::MicroVMs::UnsupportedOperationError` with an upgrade hint.
180
- give
212
+ MicroVM lifecycle support is experimental and contract-gated. The current public `aws-sdk-lambda` may not expose the MicroVM methods this gem wraps. Use `lambda-microvms sdk-contract` to verify your installed SDK.
213
+
214
+ Standard Lambda function operations are available through `Lambda::MicroVMs::FunctionClient`.
data/exe/lambda-microvms CHANGED
@@ -7,24 +7,33 @@ module Lambda
7
7
  module MicroVMs
8
8
  # Minimal CLI for the Ruby Lambda MicroVM development kit.
9
9
  class CLI
10
+ COMMANDS = {
11
+ 'version' => :version,
12
+ '--version' => :version,
13
+ '-v' => :version,
14
+ 'new' => :new_project,
15
+ 'package' => :package,
16
+ 'deploy' => :deploy,
17
+ 'run' => :run_microvm,
18
+ 'doctor' => :doctor,
19
+ 'sdk-contract' => :sdk_contract,
20
+ 'function-invoke' => :function_invoke,
21
+ 'help' => :help
22
+ }.freeze
23
+
10
24
  def initialize(argv, out: $stdout, err: $stderr)
11
25
  @argv = argv
12
26
  @out = out
13
27
  @err = err
14
28
  end
15
29
 
16
- # rubocop:disable Metrics/MethodLength
17
30
  def run
18
31
  command = @argv.shift
19
- case command
20
- when 'version', '--version', '-v' then version
21
- when 'new' then new_project
22
- when 'package' then package
23
- when 'deploy' then deploy
24
- when 'run' then run_microvm
25
- when 'doctor' then doctor
26
- when 'sdk-contract' then sdk_contract
27
- when 'help', nil then help
32
+ action = COMMANDS[command]
33
+ if action
34
+ send(action)
35
+ elsif command.nil?
36
+ help
28
37
  else
29
38
  @err.puts "unknown command: #{command}"
30
39
  help
@@ -34,7 +43,6 @@ module Lambda
34
43
  @err.puts "error: #{e.message}"
35
44
  1
36
45
  end
37
- # rubocop:enable Metrics/MethodLength
38
46
 
39
47
  private
40
48
 
@@ -93,6 +101,14 @@ module Lambda
93
101
  end
94
102
  end
95
103
 
104
+ def function_invoke
105
+ function_name = @argv.shift || raise(ArgumentError, 'usage: lambda-microvms function-invoke NAME [JSON]')
106
+ payload = @argv.empty? ? nil : JSON.parse(@argv.join(' '))
107
+ result = FunctionClient.new.invoke(function_name:, payload:)
108
+ @out.puts(result.is_a?(String) ? result : JSON.generate(result))
109
+ 0
110
+ end
111
+
96
112
  def help
97
113
  @out.puts <<~HELP
98
114
  lambda-microvms #{VERSION}
@@ -104,6 +120,8 @@ module Lambda
104
120
  deploy Package, upload to S3, and create a MicroVM image
105
121
  run Run the configured MicroVM image
106
122
  sdk-contract Check whether aws-sdk-lambda exposes MicroVM operations
123
+ function-invoke NAME [JSON]
124
+ Invoke a standard Lambda function with supported AWS APIs
107
125
  version Print version
108
126
  HELP
109
127
  0
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lambda
4
+ module MicroVMs
5
+ # Internal adapter implementations for provider-specific SDK surfaces.
6
+ module Adapters
7
+ # Adapter for the experimental Lambda MicroVM SDK operation surface.
8
+ class MicroVMSdk
9
+ # SDK method names required by the experimental MicroVM lifecycle wrapper.
10
+ REQUIRED_OPERATIONS = %i[
11
+ create_microvm_image
12
+ get_microvm_image
13
+ delete_microvm_image
14
+ run_microvm
15
+ get_microvm
16
+ list_microvms
17
+ suspend_microvm
18
+ resume_microvm
19
+ terminate_microvm
20
+ create_microvm_auth_token
21
+ ].freeze
22
+
23
+ attr_reader :sdk
24
+
25
+ def initialize(sdk)
26
+ @sdk = sdk
27
+ end
28
+
29
+ # Return MicroVM SDK operations missing from the wrapped SDK client.
30
+ #
31
+ # @return [Array<Symbol>] missing SDK operation names
32
+ def unsupported_operations
33
+ REQUIRED_OPERATIONS.reject { |operation| sdk.respond_to?(operation) }
34
+ end
35
+
36
+ # Check whether the wrapped SDK client exposes all MicroVM operations.
37
+ #
38
+ # @return [Boolean]
39
+ def supported?
40
+ unsupported_operations.empty?
41
+ end
42
+
43
+ # Dispatch a MicroVM operation to the wrapped SDK client.
44
+ #
45
+ # @param operation [Symbol] SDK method name
46
+ # @param params [Hash] SDK request parameters
47
+ # @return [Object] raw SDK response
48
+ # @raise [UnsupportedOperationError] when the SDK does not expose the operation
49
+ def call(operation, **params)
50
+ unless sdk.respond_to?(operation)
51
+ raise UnsupportedOperationError, "Aws::Lambda::Client does not expose ##{operation}; run sdk-contract"
52
+ end
53
+
54
+ sdk.public_send(operation, **params)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -11,23 +11,13 @@ module Lambda
11
11
  # Ruby wrapper over Aws::Lambda::Client for Lambda MicroVM lifecycle operations.
12
12
  class Client
13
13
  # SDK methods this wrapper expects from Aws::Lambda::Client.
14
- REQUIRED_OPERATIONS = %i[
15
- create_microvm_image
16
- get_microvm_image
17
- delete_microvm_image
18
- run_microvm
19
- get_microvm
20
- list_microvms
21
- suspend_microvm
22
- resume_microvm
23
- terminate_microvm
24
- create_microvm_auth_token
25
- ].freeze
26
-
27
- attr_reader :sdk
28
-
29
- def initialize(region: nil, profile: nil, sdk: nil, **)
14
+ REQUIRED_OPERATIONS = Adapters::MicroVMSdk::REQUIRED_OPERATIONS
15
+
16
+ attr_reader :sdk, :adapter
17
+
18
+ def initialize(region: nil, profile: nil, sdk: nil, adapter: nil, **)
30
19
  @sdk = sdk || build_sdk(region: region, profile: profile, **)
20
+ @adapter = adapter || Adapters::MicroVMSdk.new(@sdk)
31
21
  end
32
22
 
33
23
  # Return wrapper operations missing from the given SDK client.
@@ -38,7 +28,7 @@ module Lambda
38
28
  sdk ||= Aws::Lambda::Client.new(stub_responses: true) if defined?(Aws::Lambda::Client)
39
29
  return REQUIRED_OPERATIONS unless sdk
40
30
 
41
- REQUIRED_OPERATIONS.reject { |operation| sdk.respond_to?(operation) }
31
+ Adapters::MicroVMSdk.new(sdk).unsupported_operations
42
32
  end
43
33
 
44
34
  # Check whether the given SDK client exposes all MicroVM operations.
@@ -158,11 +148,7 @@ module Lambda
158
148
  # @return [Object] raw SDK response
159
149
  # @raise [UnsupportedOperationError] when the SDK does not expose the operation
160
150
  def call_sdk(operation, **params)
161
- unless @sdk.respond_to?(operation)
162
- raise UnsupportedOperationError, "Aws::Lambda::Client does not expose ##{operation}; upgrade aws-sdk-lambda"
163
- end
164
-
165
- @sdk.public_send(operation, **params)
151
+ adapter.call(operation, **params)
166
152
  end
167
153
 
168
154
  private
@@ -42,6 +42,7 @@ module Lambda
42
42
  #
43
43
  # @return [Image] created image resource
44
44
  def deploy
45
+ ensure_microvm_contract!
45
46
  artifact = package
46
47
  artifact_uri = upload(artifact)
47
48
  client.create_image(**project.create_image_params(artifact_uri: artifact_uri))
@@ -51,6 +52,7 @@ module Lambda
51
52
  #
52
53
  # @return [MicroVM] started MicroVM resource
53
54
  def run
55
+ ensure_microvm_contract!
54
56
  image_arn = project.require!('image.arn', project.image_arn)
55
57
  role_arn = project.require!('role_arn', project.role_arn)
56
58
  client.image(image_arn).run(**project.run_params, role_arn: role_arn)
@@ -64,6 +66,15 @@ module Lambda
64
66
  args = { region: project.region, profile: project.profile }.compact
65
67
  Aws::S3::Client.new(**args)
66
68
  end
69
+
70
+ def ensure_microvm_contract!
71
+ return unless client.respond_to?(:adapter)
72
+
73
+ missing = client.adapter.unsupported_operations
74
+ return if missing.empty?
75
+
76
+ raise UnsupportedOperationError, "Aws::Lambda::Client is missing MicroVM operations: #{missing.join(', ')}"
77
+ end
67
78
  end
68
79
  end
69
80
  end
@@ -27,7 +27,8 @@ module Lambda
27
27
  file_check('Dockerfile', project.dockerfile),
28
28
  config_check('role_arn', project.role_arn),
29
29
  config_check('deployment.bucket', project.s3_bucket),
30
- ric_check
30
+ ric_check,
31
+ sdk_contract_check
31
32
  ]
32
33
  end
33
34
 
@@ -62,6 +63,13 @@ module Lambda
62
63
  ok = File.exist?(gemfile) && File.read(gemfile).include?('aws_lambda_ric')
63
64
  Check.new(name: 'aws_lambda_ric', ok: ok, detail: ok ? 'present in Gemfile' : 'missing from Gemfile')
64
65
  end
66
+
67
+ def sdk_contract_check
68
+ missing = Client.unsupported_operations
69
+ ok = missing.empty?
70
+ detail = ok ? 'MicroVM operations available' : "missing: #{missing.join(', ')}"
71
+ Check.new(name: 'aws-sdk-lambda MicroVM contract', ok: ok, detail: detail)
72
+ end
65
73
  end
66
74
  end
67
75
  end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Lambda
6
+ module MicroVMs
7
+ # Thin wrapper over stable Aws::Lambda::Client function APIs.
8
+ class FunctionClient
9
+ attr_reader :sdk
10
+
11
+ def initialize(region: nil, profile: nil, sdk: nil, **)
12
+ @sdk = sdk || build_sdk(region: region, profile: profile, **)
13
+ end
14
+
15
+ # Create a Lambda function from a zip file using supported AWS APIs.
16
+ #
17
+ # @param name [String] function name
18
+ # @param role_arn [String] IAM role ARN
19
+ # @param handler [String] handler name
20
+ # @param runtime [String] Lambda runtime identifier
21
+ # @param zip_file [String] path to deployment zip
22
+ # @param params [Hash] additional create_function parameters
23
+ # @return [Object] raw SDK response
24
+ def create_function(name:, role_arn:, handler:, runtime:, zip_file:, **params) # rubocop:disable Metrics/ParameterLists
25
+ sdk.create_function(
26
+ **params,
27
+ function_name: name,
28
+ role: role_arn,
29
+ handler: handler,
30
+ runtime: runtime,
31
+ code: { zip_file: File.binread(zip_file) }
32
+ )
33
+ end
34
+
35
+ # Update Lambda function code from a zip file.
36
+ #
37
+ # @param function_name [String] function name or ARN
38
+ # @param zip_file [String] path to deployment zip
39
+ # @param params [Hash] additional update_function_code parameters
40
+ # @return [Object] raw SDK response
41
+ def update_function_code(function_name:, zip_file:, **params)
42
+ sdk.update_function_code(**params, function_name: function_name, zip_file: File.binread(zip_file))
43
+ end
44
+
45
+ # Invoke a Lambda function and parse JSON payloads when possible.
46
+ #
47
+ # @param function_name [String] function name or ARN
48
+ # @param payload [Object] request payload
49
+ # @param params [Hash] additional invoke parameters
50
+ # @return [Object] parsed response payload or raw response body
51
+ def invoke(function_name:, payload: nil, **params)
52
+ response = sdk.invoke(**params, function_name: function_name, payload: encode_payload(payload))
53
+ parse_payload(response.payload)
54
+ end
55
+
56
+ private
57
+
58
+ def build_sdk(region:, profile:, **options)
59
+ unless defined?(Aws::Lambda::Client)
60
+ raise LoadError, 'install aws-sdk-lambda to use Lambda::MicroVMs::FunctionClient'
61
+ end
62
+
63
+ args = options.dup
64
+ args[:region] = region if region
65
+ args[:profile] = profile if profile
66
+ Aws::Lambda::Client.new(**args)
67
+ end
68
+
69
+ def encode_payload(payload)
70
+ case payload
71
+ when nil
72
+ nil
73
+ when String
74
+ payload
75
+ else
76
+ JSON.generate(payload)
77
+ end
78
+ end
79
+
80
+ def parse_payload(payload)
81
+ body = payload.respond_to?(:read) ? payload.read : payload.to_s
82
+ return nil if body.empty?
83
+
84
+ JSON.parse(body)
85
+ rescue JSON::ParserError
86
+ body
87
+ end
88
+ end
89
+ end
90
+ end
@@ -3,6 +3,6 @@
3
3
  module Lambda
4
4
  module MicroVMs
5
5
  # Current gem version.
6
- VERSION = '0.1.0'
6
+ VERSION = '0.2.0'
7
7
  end
8
8
  end
@@ -5,7 +5,9 @@ require_relative 'microvms/error'
5
5
  require_relative 'microvms/util'
6
6
  require_relative 'microvms/waiter'
7
7
  require_relative 'microvms/endpoint'
8
+ require_relative 'microvms/adapters/microvm_sdk'
8
9
  require_relative 'microvms/client'
10
+ require_relative 'microvms/function_client'
9
11
  require_relative 'microvms/image'
10
12
  require_relative 'microvms/microvm'
11
13
  require_relative 'microvms/session'
@@ -29,9 +29,10 @@ module Lambda
29
29
  class Client
30
30
  REQUIRED_OPERATIONS: Array[Symbol]
31
31
  attr_reader sdk: untyped
32
+ attr_reader adapter: Adapters::MicroVMSdk
32
33
  def self.unsupported_operations: (?untyped sdk) -> Array[Symbol]
33
34
  def self.sdk_contract_supported?: (?untyped sdk) -> bool
34
- def initialize: (?region: String?, ?profile: String?, ?sdk: untyped, **untyped) -> void
35
+ def initialize: (?region: String?, ?profile: String?, ?sdk: untyped, ?adapter: Adapters::MicroVMSdk, **untyped) -> void
35
36
  def image: (String arn) -> Image
36
37
  def microvm: (String id_or_arn) -> MicroVM
37
38
  def create_image: (**untyped) -> Image
@@ -53,6 +54,31 @@ module Lambda
53
54
  def build_sdk: (region: String?, profile: String?, **untyped) -> untyped
54
55
  end
55
56
 
57
+ module Adapters
58
+ class MicroVMSdk
59
+ REQUIRED_OPERATIONS: Array[Symbol]
60
+ attr_reader sdk: untyped
61
+ def initialize: (untyped sdk) -> void
62
+ def unsupported_operations: () -> Array[Symbol]
63
+ def supported?: () -> bool
64
+ def call: (Symbol operation, **untyped) -> untyped
65
+ end
66
+ end
67
+
68
+ class FunctionClient
69
+ attr_reader sdk: untyped
70
+ def initialize: (?region: String?, ?profile: String?, ?sdk: untyped, **untyped) -> void
71
+ def create_function: (name: String, role_arn: String, handler: String, runtime: String, zip_file: String, **untyped) -> untyped
72
+ def update_function_code: (function_name: String, zip_file: String, **untyped) -> untyped
73
+ def invoke: (function_name: String, ?payload: untyped, **untyped) -> untyped
74
+
75
+ private
76
+
77
+ def build_sdk: (region: String?, profile: String?, **untyped) -> untyped
78
+ def encode_payload: (untyped payload) -> String?
79
+ def parse_payload: (untyped payload) -> untyped
80
+ end
81
+
56
82
  module Util
57
83
  def extract: (untyped value, *untyped keys) -> untyped
58
84
  def normalize_state: (untyped value) -> Symbol
@@ -198,6 +224,7 @@ module Lambda
198
224
  private
199
225
 
200
226
  def build_s3: () -> untyped
227
+ def ensure_microvm_contract!: () -> void
201
228
  end
202
229
 
203
230
  class Doctor
@@ -215,6 +242,7 @@ module Lambda
215
242
  def file_check: (String name, String path) -> untyped
216
243
  def config_check: (String name, untyped value) -> untyped
217
244
  def ric_check: () -> untyped
245
+ def sdk_contract_check: () -> untyped
218
246
  end
219
247
  end
220
248
  end
@@ -238,6 +266,9 @@ module FileUtils
238
266
  end
239
267
 
240
268
  module JSON
269
+ class ParserError < StandardError
270
+ end
271
+
241
272
  def self.parse: (String source) -> untyped
242
273
  def self.generate: (untyped value) -> String
243
274
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lambda-microvms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenneth C. Demanawa
@@ -65,11 +65,13 @@ files:
65
65
  - README.md
66
66
  - exe/lambda-microvms
67
67
  - lib/lambda/microvms.rb
68
+ - lib/lambda/microvms/adapters/microvm_sdk.rb
68
69
  - lib/lambda/microvms/client.rb
69
70
  - lib/lambda/microvms/deployer.rb
70
71
  - lib/lambda/microvms/doctor.rb
71
72
  - lib/lambda/microvms/endpoint.rb
72
73
  - lib/lambda/microvms/error.rb
74
+ - lib/lambda/microvms/function_client.rb
73
75
  - lib/lambda/microvms/image.rb
74
76
  - lib/lambda/microvms/microvm.rb
75
77
  - lib/lambda/microvms/packager.rb