Documentation
¶
Overview ¶
This file (package residue, colocated with residue.go and tagverbs.go for the same go:embed reason: an embed directive can only name files in its own package's directory, and live/floci-capabilities.json lives here) is the floci capability manifest: which AWS services and resource types the floci emulator this checkout pins actually implements, keyed by the image's content digest rather than its mutable tag.
The problem this closes: every batch of e2e/floci-gated work that hits an unimplemented service rediscovers the gap from scratch - a Create call that returns UnknownOperationException, a service missing from /_localstack/health, a router that dispatches one service's calls to another's handler - and writes the finding up in prose, once, in that batch's own cohort README (see live/e2e/estates/databases/README.md and live/e2e/estates/stragglers/README.md's own "Floci coverage" sections) or in a hand-written t.Skip message (internal/live/discovery's tagging_live_test.go and cloudcontrol_live_test.go). The next batch that reaches the same type pays the same discovery cost again, because nothing upstream of "read every README" could have told it the answer was already known. live/floci-capabilities.json is that answer, structured and keyed by the exact digest the finding was made against, so a test can look it up instead of a human re-deriving it, and a bumped image's stale entries are visibly stale (no entry for the new digest) rather than silently wrong.
The manifest has two grains:
- Services (botocore/AWS CLI service ids, e.g. "networkmanager", "transfer"): whether floci implements the service at all, read off floci's own /_localstack/health endpoint by tools/floci-capability-gen's default probe mode. Note the grain's coverage is its own watchlist rather than the health response: the probe re-checks every service already carrying a row and records nothing for the rest, so the four rows here sit against 82 service names the pinned image reports (#276).
- Types (Terraform provider-local resource types, e.g. "aws_redshift_cluster"), each optionally scoped to a discovery mechanism other than the ordinary create/read path ("tagging-sweep", "cloudcontrol-list", "cloudcontrol-list-scoped" - internal/live/flocitest's *CapabilityGate helpers use the same vocabulary). "cloudcontrol-list-scoped" is "cloudcontrol-list"'s counterpart for a type whose Cloud Control list handler requires scoping input (registry.Roster.EnumerationSourceScoped, the exact population EnumerationSource excludes) - tools/floci-capability-gen's -mode=cloudcontrol-scoped probes it the same way, with a synthetic placeholder scope rather than a real parent object, because floci's ListResources ignores ResourceModel scoping entirely regardless of which mechanism sent it (issue #277). This grain is finer than a health-endpoint probe can answer by itself: a service can report "running" while a specific operation it exposes is still unimplemented, or routed to the wrong handler, or reaches a handler that crashes rather than erroring cleanly. Most entries here are curated from a real `terraform apply` (or a real Cloud Control/tagging call) run against the exact pinned digest and written up once, the same hand-verification the two cohort READMEs above already did - this file just gives that verification a permanent, structured, queryable home instead of only prose a later reader has to find and re-read. tools/floci-capability-gen's -mode=cloudcontrol regenerates the "cloudcontrol-list" mechanism's entries mechanically, over every registry-ratified type, by round trip: create a resource of the type through Cloud Control, then list and look for the identifier the create just named. That round trip is the only way to tell a list that answers from one that returns - floci's ListResources answers an empty ResourceDescriptions, cleanly, for a type whose objects demonstrably exist, and an earlier sweep that recorded a bare successful call as "implemented" filled this manifest with 645 rows that said so. Re-probed as a round trip against the same image, seven of 610 hold (#279). The rest of the grain stays hand data, extended the same way tools/estate-gen/overrides.go's typeOverrides table is.
The three mechanisms are not interchangeable evidence for "does floci support this type", and reading one as a substitute for another is exactly the mistake issue #278 named:
- mechanism="" (the ordinary create/read path) is the only grain that answers what a real `tofu apply` needs: a create call that succeeds and a read/import call that returns usable properties. It is also by far the narrowest of the three - see live/floci-capabilities.json's own row counts per mechanism for the current pin, rather than a number here that would go stale - because there is no derivable minimal create recipe per type and every row is hand-curated one type at a time (issue #278's second and third options, neither attempted yet).
- "cloudcontrol-list" is the broadest grain and the weakest: its probe (tools/floci-capability-gen -mode=cloudcontrol) never creates anything and never reads a populated object. "implemented" means only that a bare ListResources call against an arbitrary (possibly empty) collection did not return UnsupportedOperation or an unparseable error - nothing about whether Create would succeed, whether the properties a real read would need come back populated, or whether the provider's own API calls (which are not Cloud Control's) work at all. Two documented cases where this grain and the ordinary path disagree: aws_athena_named_query and aws_cloudwatch_query_definition both record "implemented" here on ListResources evidence, while the API the provider itself calls for each returns UnsupportedOperation; and CloudFront's list-public-keys answers with every item's Name unset, so a "successful" list is not a usable one. Treat a "cloudcontrol-list" row as evidence for internal/live/discovery's Cloud Control fallback working, never as evidence that a plain `resource` block for that type will apply.
- "tagging-sweep" sits in between: its probe creates one real, tagged resource through the AWS CLI directly (never through Terraform or Cloud Control) and confirms it independently through that service's own native read, so "implemented" here is real evidence the type's native create/read path exists in floci - but it only ever proves that for the small, hand-curated set of types tagging.go's taggingRecipes covers, and it says nothing about whether the resourcegroupstaggingapi sweep itself (the thing this mechanism actually gates) would find a *different* type's resources.
A digest with no entry at all, a service/type with no row under a digest that does have entries, or a row recorded under a *different* mechanism than the one a caller is about to exercise, all mean "not yet investigated" for the question actually being asked - never "confirmed working". FlociServiceCapability and FlociTypeCapability report ok=false only for the first two; picking the right mechanism argument for the third is the caller's job, and FlociTypeCapability's own doc comment says which mechanism answers which question.
This file (package residue, colocated with residue.go for the reason tagverbs.go already documents: a go:embed directive can only name files in its own package's directory, and live/survey.json lives here) is issue #63's evidence-version source.
Every admitted row's import grammar, identity schema, and taggability judgment was verified against one provider version at the time tools/survey-gen last ran, recorded once in live/survey.json's header rather than per row. EvidenceVersion's doc comment is the record of why a single table-wide basis, not a per-row range, is the right answer.
survey.json is the artifact read here, of the three that carry a copy of this version (survey.json's header, import-grammar.json's header, and registry.json's pin), because it is the one this package already parses end to end for Lookup and the residue-cohort accessors: reading it a second time for one more field costs one more struct, not a second embed and a second JSON parser. import-grammar.json's provider_version header is produced by the same tools/survey-gen run and carries the identical value; registry.json's pin is a digest and an acceptance date, not a provider semver, and answers a different question ("is the CFN registry snapshot stale") rather than this one.
Package residue is the residue roster (issue #49): the named, printable set of resource types "not covered" resolves to, and why. It answers the question live/LIMITATIONS.md's untaggable list already answers for one narrow case ("which admitted types can't be swept, and why"), generalized to every type a configuration can name.
Two consumers read this package:
- tools/survey-gen renders live/LIMITATIONS.md's residue-roster span from the accessors below, and a drift test holds the doc to them.
- internal/live/lint's admission refusal calls Lookup to name a refused type's cohort, when it has one, in the refusal Detail.
Two cohorts (deprecated services and CFN-only constructs) and one roster (emulator-blocked) are hand data: no schema anywhere says a service is retired, that a CloudFormation type is a template mechanism rather than an infrastructure resource, or that an emulator gap blocks a type from e2e proof. Those three judgments are curated below, with their evidence in comments, the same way tools/survey-gen/classify.go's opsExcluded carries the credential and waiter judgments no schema can prove. (That symbol used to be cited here as living in internal/live/lint/admission.go; it moved packages, it did not go away.)
The other cohorts - unmapped (unclassified) TF types, tf-only constructs, cfn-unmodeled resources, and registry-laggard live services - are entirely computed, from the two artifacts embedded below: live/mapping.json (issue #43) and live/registry.json (issue #42). They are embedded, not copied into a hand-written table, so there is no second copy of the join to fall out of sync with the committed artifacts — a regenerated mapping.json or registry.json changes this package's answers the moment it is committed, with no separate regeneration step of its own. Issue #53's terminal taxonomy (tf-only, cfn-unmodeled, deprecated-service, alongside the original unmapped/"none") lives inside live/mapping.json's own rows (each row's via) rather than as a further cohort here of its own kind: Lookup reads a row's via directly, and TFOnlyGroups / CFNUnmodeledGroups / UnmappedGroups group live/mapping.json's rows by via the same way, one accessor per terminal class the mechanical or curated classifiers in tools/mapping-gen assign.
This file (package residue, colocated with residue.go for the same embed-directive reason: an embed directive can only name files in its own package's directory, and live/tag-verbs.json lives here) is issue #52's botocore side: internal/live/foreign/classify.go's adoptionHint used to consult a ten-row hand-written ec2Types table naming which admitted types this package knew how to write a `aws ec2 create-tags` command for, with a doc comment enumerating - by hand - the per-service tag verbs it refused to model (kms:TagResource, elasticloadbalancing:AddTags, sqs:TagQueue, ...). TagVerbForType replaces both: it joins a TF type to its CFN service the same way Lookup does (reusing the embedded mapping.json this file's sibling residue.go already parses), then looks the service up in the embedded, botocore-derived live/tag-verbs.json (tools/tagverbs-gen). A service the artifact never resolved a single tagging operation for - ambiguous (IAM, ACM, CloudWatch Logs), none (S3), or unresolved to a botocore directory at all - reports Known=true with an empty Operation and a Reason, honestly, rather than silently answering nothing.
Index ¶
- Variables
- func DeprecatedCount(service DeprecatedService) int
- func DeprecatedServiceViaCount() int
- func DeprecatedTotal() int
- func EvidenceProvider() string
- func EvidenceVersion() string
- func XformName(name string) string
- type CFNOnlyConstruct
- type Cohort
- type DeprecatedService
- type EmulatorBlockedType
- type FlociCapability
- type FlociStatus
- type LaggardType
- type NoteGroup
- type TagVerb
- type UnmappedGroup
Constants ¶
This section is empty.
Variables ¶
var CFNOnlyConstructs = []CFNOnlyConstruct{
{
Type: "AWS::CloudFormation::WaitCondition",
Reason: "a template-internal signal that a stack step finished, not an AWS resource",
},
{
Type: "AWS::CloudFormation::WaitConditionHandle",
Reason: "the pre-signed URL a WaitCondition polls, existing only to be written to",
},
{
Type: "AWS::CloudFormation::Macro",
Reason: "registers a template preprocessor for CloudFormation's own macro transform, not infrastructure",
},
{
Type: "AWS::CloudFormation::CustomResource",
Reason: "a template escape hatch to an arbitrary Lambda-backed handler, with no AWS resource of its own",
},
}
CFNOnlyConstructs is the curated list of CloudFormation Registry types that are CloudFormation's own template and stack mechanics, not AWS infrastructure — the CFN-side mirror of this fork's own logical-resource family (null_resource, local_file, random_password, time_sleep, live/LIMITATIONS.md's "Enforced today" section): a construct whose whole value is something a template-processing engine keeps track of, with no live twin any provider could read back. That is a judgment, the same way deciding null_resource has no live twin is a judgment, so this list is hand data. What is computed is the claim that goes with it: [init] checks every entry here against live/mapping.json and panics if one now has a TF counterpart, so the claim cannot go stale silently.
var DeprecatedServices = []DeprecatedService{
{
TFPrefix: "aws_pinpoint_",
CFNPrefix: "AWS::Pinpoint::",
Service: "Pinpoint",
Reason: "a service AWS is retiring (end-of-support October 30, 2026)",
},
{
TFPrefix: "aws_greengrass_",
CFNPrefix: "AWS::Greengrass::",
Service: "Greengrass V1",
Reason: "a service AWS has superseded with Greengrass V2, shipping no new features for V1",
},
{
TFPrefix: "aws_waf_",
CFNPrefix: "AWS::WAF::",
Service: "WAF Classic",
Reason: "a service AWS has superseded with the unified WAFv2 API",
},
{
TFPrefix: "aws_wafregional_",
CFNPrefix: "AWS::WAFRegional::",
Service: "WAF Classic Regional",
Reason: "a service AWS has superseded with the unified WAFv2 API, same as WAF Classic",
},
{
TFPrefix: "aws_appmesh_",
CFNPrefix: "AWS::AppMesh::",
Service: "App Mesh",
Reason: "a service AWS has closed to new customers and is winding down",
},
{
TFPrefix: "aws_appstream_",
CFNPrefix: "AWS::AppStream::",
Service: "AppStream 2.0",
Reason: "a service this fork holds out of scope by policy",
},
{
TFPrefix: "aws_dax_",
CFNPrefix: "AWS::DAX::",
Service: "DAX",
Reason: "a service (DynamoDB Accelerator) this fork holds out of scope by policy",
},
{
TFPrefix: "aws_media_store_",
CFNPrefix: "AWS::MediaStore::",
Service: "MediaStore",
Reason: "a service AWS discontinued effective November 13, 2025 (already past), which the pinned provider's own docs also flag as deprecated",
},
}
DeprecatedServices is the curated list of AWS services this fork treats as out of scope by policy: retired, end-of-life, or being wound down. Issue #49 names these seven as the anchors; membership of a *type* in the cohort (which resource types count, and how many CFN registry types the service carries) is computed by Lookup and the accessors below, against live/mapping.json and live/registry.json — only the service→deprecated judgment itself is hand data.
var EmulatorBlocked = []EmulatorBlockedType{ { Type: "aws_iam_role", Admitted: true, Reason: "floci's iam:GetRole omits Tags, so the role's own marker never reads back and every plan reports it unowned", }, { Type: "aws_s3_bucket_policy", Admitted: true, Reason: "downstream of aws_iam_role's residue: its policy document embeds the unowned role's ARN, so its own plan never settles", }, { Type: "aws_db_instance", Admitted: true, Reason: "RDS only works fully against floci when the docker socket is mounted into the emulator container, which this harness does not do (lex00/floci#28)", }, { Type: "aws_ssm_document", Admitted: false, Reason: "floci answers ssm:CreateDocument with UnsupportedOperation, so no SSM document can be created against the emulator at all (choudoufu#26)", }, }
EmulatorBlocked is the curated roster of types issue #26 names as wireable against real AWS but not provable against the floci emulator today. Which floci behavior blocks which type is read off the harness (live/e2e/run.sh) and the admission table, not derivable from any artifact, so this is hand data — the same status as DeprecatedServices and CFNOnlyConstructs.
Functions ¶
func DeprecatedCount ¶
func DeprecatedCount(service DeprecatedService) int
DeprecatedCount returns the number of CloudFormation Registry types under service's CFNPrefix.
func DeprecatedServiceViaCount ¶
func DeprecatedServiceViaCount() int
DeprecatedServiceViaCount returns the number of live/mapping.json rows carrying via:"deprecated-service" - issue #53's own TF-side mechanical count, as opposed to DeprecatedCount's CFN Registry-side count of a single service's type footprint.
func DeprecatedTotal ¶
func DeprecatedTotal() int
DeprecatedTotal returns the sum of DeprecatedCount over every DeprecatedServices entry.
func EvidenceProvider ¶
func EvidenceProvider() string
EvidenceProvider is the provider source live/survey.json's admission table was verified against - "hashicorp/aws" today, since choudoufu supports one provider (live/COVERAGE.md).
func EvidenceVersion ¶
func EvidenceVersion() string
EvidenceVersion is the provider version every admitted type's import grammar, identity schema, and taggability judgment were verified against: live/survey.json's provider_version header.
This is a single table-wide basis, not a per-row version range, by deliberate choice (issue #63's design question). Two things make a table-wide basis correct rather than merely convenient. First, tools/admission-pipeline re-verifies the whole table on every provider pin bump (see its own doc comment), so the table has never actually held two provider versions' evidence at once; a per-row range would record a distinction that has never existed in how this table is built or kept current. Second, a per-row range would need its own drift test to stay honest as rows come and go with every mapping-gen and survey-gen run, which is exactly the kind of second copy of a fact this codebase's own conventions (see residue.go's doc comment on why cohorts are computed from artifacts rather than hand-copied) argue against introducing. A single version is also the only basis simple enough for a warning read once, at plan time, without a table lookup of its own.
Types ¶
type CFNOnlyConstruct ¶
type CFNOnlyConstruct struct {
// Type is the CloudFormation Registry type name.
Type string
// Reason is the one-sentence judgment that the construct is CFN's own
// template machinery rather than an infrastructure resource, so no TF
// counterpart can exist by design rather than by omission.
Reason string
}
CFNOnlyConstruct is one curated entry in CFNOnlyConstructs.
type Cohort ¶
type Cohort string
Cohort names one of the exclusion cohorts a resource type can fall into. A type belongs to at most one cohort; Lookup resolves ties in the order the cohorts are checked, most specific first.
const ( // CohortDeprecated is a type in a service AWS has retired, deprecated, // or is winding down. See [DeprecatedServices]. CohortDeprecated Cohort = "deprecated-service" // CohortCFNOnly is a CloudFormation Registry construct with no // Terraform counterpart at all — never reachable from this package's // TF-side [Lookup], since no configuration can name a type Terraform // does not have, but still part of the roster for the doc side. See // [CFNOnlyConstructs]. CohortCFNOnly Cohort = "cfn-only" // CohortUnmapped is a TF type live/mapping.json's join found no CFN // counterpart for, and issue #53's terminal taxonomy has not (yet) // classified any further (via "none" - the "unclassified" remainder // the family sweeps burn down). CohortUnmapped Cohort = "unmapped" // CohortTFOnly is a TF type that is a provider-side construct with no // cloud resource of its own - a waiter, a validation, an // aws_ami_copy-style operation, a default_* adopter (via "tf-only", // issue #53). CohortTFOnly Cohort = "tf-only" // CohortCFNUnmodeled is a TF type naming a real, live AWS resource the // CloudFormation Registry does not model at all (via "cfn-unmodeled", // issue #53). CohortCFNUnmodeled Cohort = "cfn-unmodeled" // CohortRegistryLaggard is a TF type mapped to a CFN type whose // Registry entry ships no working handler at all, so the registry- // backed admission path (issue #40) cannot reach it. CohortRegistryLaggard Cohort = "registry-laggard" // CohortEmulatorBlocked is a type wireable against real AWS but not // provable against the floci emulator (issue #26). See // [EmulatorBlocked]. CohortEmulatorBlocked Cohort = "emulator-blocked" )
func Lookup ¶
Lookup reports which exclusion cohort tfType belongs to, and a full sentence naming it, or ok=false when the type is in no cohort — the common case, since most unadmitted types are simply not wired yet rather than excluded by any rule.
Checked in order, most specific first: a deprecated-service type is named as deprecated even when its mapping row would also read as unmapped or laggard, because "out of scope by policy" is the more actionable reason. CohortCFNOnly never matches here, since no TF configuration can name a CloudFormation-only type.
type DeprecatedService ¶
type DeprecatedService struct {
// TFPrefix is the Terraform provider-local type prefix this service's
// resources share, e.g. "aws_pinpoint_". Used by [Lookup].
TFPrefix string
// CFNPrefix is the CloudFormation Registry type-name prefix the same
// service shares, e.g. "AWS::Pinpoint::". Used to count the service's
// registry-side footprint for the doc, independent of whether every
// member has a TF counterpart at all (most of Greengrass V1 does not
// — see the entry below).
CFNPrefix string
// Service is the human-readable service name.
Service string
// Reason is the one-sentence judgment, with its evidence, that puts
// the service out of scope. This is the hand data opsExcluded-style
// judgments always are: no schema anywhere says a service is retired.
Reason string
}
DeprecatedService is one curated entry in DeprecatedServices: an AWS service prefix, on both sides of the TF/CFN naming, judged out of scope by policy.
type EmulatorBlockedType ¶
type EmulatorBlockedType struct {
// Type is the TF provider-local resource type.
Type string
// Admitted is whether this type is in the v0 admission table today.
// True for a type admitted but still carrying standing e2e residue
// (its admission is real; only the emulator proof is blocked). False
// for a type the emulator gap kept out of a wiring slice entirely —
// admitting it would be real work with nothing to prove it against.
Admitted bool
// Reason is the one-sentence account of the emulator gap.
Reason string
}
EmulatorBlockedType is one curated entry in EmulatorBlocked.
type FlociCapability ¶
type FlociCapability struct {
// Status is floci's implementation status for this digest.
Status FlociStatus
// Evidence is the concrete signal observed - an error code, a response
// shape, a health-endpoint absence - not a guess.
Evidence string
// Source cites where the finding was made: a cohort README's "Floci
// coverage" section, a Go test's own name, or "live probe" for an entry
// tools/floci-capability-gen wrote mechanically.
Source string
}
FlociCapability is one manifest entry: what happened when this repo tried to use a service or type against one specific floci image, and where that finding is written up in full.
func FlociServiceCapability ¶
func FlociServiceCapability(digest, service string) (FlociCapability, bool)
FlociServiceCapability reports what the capability manifest says about one AWS service - a botocore/AWS CLI service id such as "networkmanager" or "transfer" - against the given floci image digest (a bare "sha256:<hex>", the same form internal/live/flocitest's pinned image and FLOCI_IMAGE override resolve to). ok is false when the manifest carries no entry for this digest+service at all, which callers must treat as "not yet investigated", never as "confirmed working" or "confirmed missing" - silence here means nobody has recorded a finding.
func FlociTypeCapability ¶
func FlociTypeCapability(digest, tfType, mechanism string) (FlociCapability, bool)
FlociTypeCapability is FlociServiceCapability's finer-grained twin: a Terraform provider-local resource type (e.g. "aws_redshift_cluster"), scoped to exactly one discovery mechanism via mechanism. Same ok=false "not yet investigated" caveat as FlociServiceCapability - and here it also covers a mechanism mismatch: a row recorded under "cloudcontrol-list" is invisible to a call with mechanism="", and vice versa. That is deliberate, not a gap to work around by trying every mechanism until one returns ok=true - see this file's package doc for why (issue #278). The three values mean:
- "" - the ordinary create/read path, the one a plain `resource` block and a real `tofu apply` actually take. This is the only mechanism whose "implemented" answers "does floci support this type" in the sense most callers mean by that question. Pass this when deciding whether to attempt or skip driving floci through a type's normal lifecycle.
- "cloudcontrol-list" - internal/live/discovery's Cloud Control enumeration fallback (SourceCloudControl). Its "implemented" proves only that Cloud Control's ListResources call did not error for that type; it is not evidence the type's own create/read path works, and two types are on record disagreeing (see the package doc). Pass this only when the code under test is itself the Cloud Control discovery path, e.g. internal/live/flocitest.CloudControlListCapabilityGate.
- "tagging-sweep" - internal/live/discovery's tagging-sweep enumeration path (SourceTagging). Pass this only when the code under test is itself that path, e.g. internal/live/flocitest.TaggingSweepCapabilityGate.
A caller outside internal/live/flocitest's three named *CapabilityGate wrappers should have a specific reason to call this directly with a mechanism other than "" - and that reason should be "the code under test takes that mechanism's own path", never "that's the mechanism with a row for this type".
type FlociStatus ¶
type FlociStatus string
FlociStatus is floci's own implementation status for one AWS service or resource type, as recorded against one exact image digest.
const ( // FlociImplemented is a service or type floci implements well enough // that the finding recorded it working, possibly with caveats spelled // out in the Evidence text. FlociImplemented FlociStatus = "implemented" // FlociUnimplemented is a service or type floci's router refuses // outright (UnknownOperationException, UnsupportedOperation, or a // service missing from /_localstack/health entirely). FlociUnimplemented FlociStatus = "unimplemented" // FlociBroken is a type whose call reaches a router-recognized handler // that then fails in a way no client can recover from - floci's own // implementation bug, not an absent one (the HTML-error-page shape // live/e2e/estates/databases/README.md's "Floci coverage" section // documents for aws_docdbelastic_cluster and aws_qldb_ledger is the // running example). FlociBroken FlociStatus = "broken" // FlociPartial is a service or type that works only under a condition // this harness does not meet by default (aws_opensearch_domain's own // Docker-socket-mount requirement is the running example), or that // works for some but not all of its own operations. FlociPartial FlociStatus = "partial" // FlociUnverified is a probe that reached a real handler and got an // ordinary answer back, without that answer establishing anything: the // call returned, and nothing showed whether the service actually // answered it. tools/floci-capability-gen's cloudcontrol-list sweep // writes this when it could not create a resource of the type to then // look for in the list, which leaves an empty ResourceDescriptions // indistinguishable between "nothing exists" and "this list handler is // a stub". // // Read it exactly the way an absent row is read - not yet established, // never a clearance - which is why the *CapabilityGate helpers leave a // test running rather than skipping it. It exists as a distinct status // so a reader can tell "probed, and the probe settled nothing" from // "never probed". FlociUnverified FlociStatus = "unverified" )
type LaggardType ¶
LaggardType is one TF type in the registry-laggard cohort: mapped to a CFN type (by name, alias, service-alias, or fold) whose Registry entry ships no working handler at all.
func RegistryLaggardTypes ¶
func RegistryLaggardTypes() []LaggardType
RegistryLaggardTypes returns every TF type in the registry-laggard cohort, sorted by TF type, excluding any type already counted under DeprecatedServices (a deprecated service's own laggard registry coverage is not this cohort's news to report a second time).
type NoteGroup ¶
NoteGroup is one distinct note among live/mapping.json's rows for a given via, with the count of TF types that carry it. Issue #53 widened this from a via:"none"-only shape (UnmappedGroup, kept below as an alias - a type name older code and docs already reference) to one groupByNote can produce for any via: UnmappedGroups, TFOnlyGroups and CFNUnmodeledGroups are the same grouping applied to via:"none", via:"tf-only" and via:"cfn-unmodeled" respectively.
func CFNUnmodeledGroups ¶
CFNUnmodeledGroups returns every via:"cfn-unmodeled" row's note, grouped (issue #53).
func TFOnlyGroups ¶
TFOnlyGroups returns every via:"tf-only" row's note, grouped (issue #53).
func UnmappedGroups ¶
UnmappedGroups returns every via:"none" row's note, grouped - issue #53's "unclassified" remainder: a TF type no mapping source and no terminal classifier (curated or mechanical) could place, after every other cohort below has had a chance at it.
type TagVerb ¶
type TagVerb struct {
// Service is the CFN service segment this verdict is about (e.g.
// "EC2", "KMS") - informational, and part of a composed command's own
// wording in a diagnostic.
Service string
// Known is whether live/tag-verbs.json carries a row for Service at
// all - true whenever [TagVerbForType]'s caller should trust this
// value's other fields over falling back to "the artifact is stale,
// regenerate it" (that fallback is what false means).
Known bool
// CLIService is the AWS CLI's own top-level command name for this
// service (e.g. "ec2", "kms", "elbv2") - botocore's own data directory
// name, which the AWS CLI derives its command groups from directly.
CLIService string
// Operation is the botocore operation name that tags this service's
// resources (e.g. "CreateTags", "TagResource"), empty when none was
// found or more than one candidate was ambiguous - see Reason.
Operation string
// Ambiguous is true when the artifact found more than one candidate
// tagging operation for Service with nothing to pick one by (IAM's
// eight per-entity Tag<X> operations, ACM's AddTagsToCertificate and
// TagResource both, CloudWatch Logs' TagLogGroup and TagResource
// both).
Ambiguous bool
// Composable is whether every field below resolved cleanly enough for
// a caller to build a full adoption command: exactly one scalar
// resource argument, and a tags shape this package knows how to
// render. False (with Reason explaining why) for a service with a
// known Operation this artifact still could not safely compose for -
// Route53's and SSM's two-part ResourceType+ResourceId identity, whose
// ResourceType value is a per-type enum no generic join can supply.
Composable bool
// ResourceArg and TagsArg are the operation's own input member names,
// raw as botocore spells them (e.g. "Resources", "KeyId", "Tags") -
// [XformName] turns either into its AWS CLI flag spelling.
ResourceArg string
TagsArg string
// TagsShape is "list" (a list of a two-field key/value struct, in
// which case TagKeyField and TagValueField name the struct's own two
// members) or "map" (a flat string-to-string map, in which case both
// are empty).
TagsShape string
TagKeyField string
TagValueField string
// Reason explains why Operation is empty, Ambiguous is true, or
// Composable is false. Always empty when none of those applies.
Reason string
}
TagVerb is what live/tag-verbs.json's botocore-derived join can say about a TF type's adoption command: which CLI subcommand tags its live resources and how to spell the resource-identifier and tag-pair flags. The zero value means nothing was found; check Known before reading anything else.
func TagVerbForType ¶
TagVerbForType resolves tfType's CFN service (the same mapping.json join Lookup draws on) and looks it up in the embedded tag-verbs.json. ok is true only when tfType maps to a CFN type at all - false for a type mapping.json has no row for, or whose row's via is "none" or "fold" (no CFN service of its own to look a tag verb up for). A true ok says nothing about whether a usable verb was found; check the returned TagVerb's own Known/Operation/Composable fields for that.
type UnmappedGroup ¶
type UnmappedGroup = NoteGroup
UnmappedGroup is NoteGroup's pre-#53 name, kept as an alias: nothing outside this package constructs one by name, but the exported type name itself predates the taxonomy and several comments elsewhere still refer to "UnmappedGroups' groups" by it.