Module: Foobara::AWS
- Defined in:
- lib/foobara/aws.rb,
lib/foobara/aws/plan.rb,
lib/foobara/aws/check.rb,
lib/foobara/aws/error.rb,
lib/foobara/aws/lambda.rb,
lib/foobara/aws/handler.rb,
lib/foobara/aws/version.rb,
lib/foobara/aws/packager.rb,
lib/foobara/aws/authorizer.rb,
lib/foobara/aws/cdk/service.rb
Overview
Run Foobara commands on AWS Lambda, with the topology read out of the manifest rather than restated in infrastructure code.
Three concerns, deliberately separable because they run in different places:
Foobara::AWS.plan(manifest) WHAT to deploy. Plain data. Needs neither
aws-cdk-lib nor Foobara.
Foobara::AWS::CDK::Service the AWS resources. Synth time; needs
aws-cdk-lib, and no application.
Foobara::AWS::Handler serving a request. Runtime, inside the
Foobara::AWS::Authorizer Lambda; needs neither of the above.
A Lambda bundle requires only "foobara/aws/handler" (or ".../authorizer"), which loads no CDK and no planning code — cold start is on the critical path of every request, and a deployment tool has no business being there.
Defined Under Namespace
Modules: CDK, Lambda Classes: Authorizer, Check, Error, Handler, Packager, Plan, Unit, Unverified
Constant Summary collapse
- DEFAULT_EXCLUDE =
Foobara's own commands — its auth domain and anything else it registers — are infrastructure, not the application, and deploying them is never what anyone means. Matched on the command's full name, which is where that namespace actually shows up.
NOT matched on the organization: an app that declares none is filed under "global_organization", which is most apps, and excluding it would exclude everything.
["Foobara::"].freeze
- VERSION =
"0.3.0"
Class Attribute Summary collapse
-
.caller_builder ⇒ Object
Turns the authorizer's verified claims into whatever the application wants as its caller.
Class Method Summary collapse
-
.current_caller ⇒ Object
WHO IS CALLING, for the duration of one invocation.
-
.current_caller=(value) ⇒ Object
Not an endless def: Ruby does not allow a setter to be one.
-
.plan(manifest, mount: "/run", granularity: :domain, exclude: DEFAULT_EXCLUDE) ⇒ Object
Build a Plan from a Foobara manifest.
-
.plan_from_connector(connector) ⇒ Object
Build a Plan by inspecting a live connector instead of a manifest.
Class Attribute Details
.caller_builder ⇒ Object
49 50 51 |
# File 'lib/foobara/aws/handler.rb', line 49 def caller_builder @caller_builder end |
Class Method Details
.current_caller ⇒ Object
WHO IS CALLING, for the duration of one invocation.
Foobara authenticates only commands declaring requires_authentication,
which answers "may this caller in?" but not "who is this?". A command
that is public AND viewer-aware — one that marks your own posts editable
— needs the second without the first, and Foobara has nowhere to put it.
So the handler puts it here, and an application reads it from its connector's authenticator and from any command that needs the viewer as data. A thread-local is not elegant; it is the smallest thing that works until Foobara grows a notion of optional identity.
37 |
# File 'lib/foobara/aws/handler.rb', line 37 def current_caller = Thread.current[:foobara_aws_caller] |
.current_caller=(value) ⇒ Object
Not an endless def: Ruby does not allow a setter to be one.
40 41 42 |
# File 'lib/foobara/aws/handler.rb', line 40 def current_caller=(value) Thread.current[:foobara_aws_caller] = value end |
.plan(manifest, mount: "/run", granularity: :domain, exclude: DEFAULT_EXCLUDE) ⇒ Object
Build a Plan from a Foobara manifest.
manifest the parsed manifest, as served at /manifest by a connector
mount the connector's path prefix ("/run" for the Rack connector)
granularity :domain (default), :organization or :command
A connector's manifest, not Foobara.manifest: requires_authentication
only exists once commands are connected, and it is the field the public
list comes from.
75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/foobara/aws/plan.rb', line 75 def plan(manifest, mount: "/run", granularity: :domain, exclude: DEFAULT_EXCLUDE) commands = app_commands(manifest, exclude) units = case granularity when :domain then group_units(commands, "domain", mount) when :organization then group_units(commands, "organization", mount) when :command then command_units(commands, mount) else raise ArgumentError, "unknown granularity #{granularity.inspect}" end Plan.new(mount: mount, granularity: granularity, units: units.sort_by(&:name)) end |
.plan_from_connector(connector) ⇒ Object
Build a Plan by inspecting a live connector instead of a manifest.
The same information by a shorter route: no HTTP, no running server, and no snapshot on disk to go stale. It needs the application loaded, so it belongs in a build step rather than in a CDK app — which is the whole reason a Plan can also travel as JSON.
A CONNECTOR, not a set of command classes. requires_authentication is
decided at connect time and lives on the transformed command, so the
command classes alone cannot say which commands are public — which is the
one thing a deployment most needs to know.
It adapts each command into the shape plan already reads, so there is one implementation and the two routes cannot drift.
102 103 104 105 106 107 108 |
# File 'lib/foobara/aws/plan.rb', line 102 def plan_from_connector(connector, **) commands = connector.command_registry.all_transformed_command_classes.to_h do |transformed| [transformed.command_class.full_command_name, describe_command(transformed)] end plan({ "command" => commands }, **) end |