@intentius/chant-lexicon-gcp 0.124.31 → 0.124.33
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.
- package/dist/actions/index.js +45 -0
- package/dist/api/read-client.js +105 -0
- package/dist/codegen/docs-cli.js +6 -0
- package/dist/codegen/docs.js +115 -0
- package/dist/codegen/generate-cli.js +17 -0
- package/dist/codegen/generate.js +218 -0
- package/dist/codegen/naming.js +164 -0
- package/dist/codegen/package.js +43 -0
- package/dist/composites/catalog.d.ts.map +1 -1
- package/dist/composites/catalog.js +1251 -0
- package/dist/composites/cloud-function.js +65 -0
- package/dist/composites/cloud-run-service.d.ts +7 -3
- package/dist/composites/cloud-run-service.d.ts.map +1 -1
- package/dist/composites/cloud-run-service.js +75 -0
- package/dist/composites/cloud-sql-instance.js +85 -0
- package/dist/composites/gcs-bucket.js +64 -0
- package/dist/composites/gke-cluster.js +113 -0
- package/dist/composites/gke-crdb-region.js +137 -0
- package/dist/composites/gpu-node-pool.js +74 -0
- package/dist/composites/index.js +15 -0
- package/dist/composites/landing-zone.js +89 -0
- package/dist/composites/managed-certificate.js +46 -0
- package/dist/composites/memorystore-redis.js +52 -0
- package/dist/composites/multi-region-vpc.js +108 -0
- package/dist/composites/private-service.js +50 -0
- package/dist/composites/pubsub-pipeline.js +63 -0
- package/dist/composites/secure-project.js +85 -0
- package/dist/composites/vpc-network.js +113 -0
- package/dist/coverage.js +28 -0
- package/dist/deep-observe-hooks.js +152 -0
- package/dist/deep-observe.js +273 -0
- package/dist/default-labels.js +67 -0
- package/dist/describe-resources.js +264 -0
- package/dist/detect.js +16 -0
- package/dist/export-resources.js +59 -0
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/generated/index.js +1804 -0
- package/dist/generated/runtime.js +4 -0
- package/dist/governance.js +98 -0
- package/dist/health.d.ts +42 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +87 -0
- package/dist/import/generator.js +68 -0
- package/dist/import/live-export.js +73 -0
- package/dist/import/parser.js +61 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -0
- package/dist/integrity.json +5 -5
- package/dist/lint/audit-catalog.js +38 -0
- package/dist/lint/audit-lineage.js +63 -0
- package/dist/lint/post-synth/gcp-helpers.js +91 -0
- package/dist/lint/post-synth/index.js +54 -0
- package/dist/lint/post-synth/schema-registry.d.ts.map +1 -1
- package/dist/lint/post-synth/schema-registry.js +69 -0
- package/dist/lint/post-synth/wgc101.js +47 -0
- package/dist/lint/post-synth/wgc102.js +29 -0
- package/dist/lint/post-synth/wgc103.js +37 -0
- package/dist/lint/post-synth/wgc104.js +34 -0
- package/dist/lint/post-synth/wgc105.js +39 -0
- package/dist/lint/post-synth/wgc106.js +30 -0
- package/dist/lint/post-synth/wgc107.js +33 -0
- package/dist/lint/post-synth/wgc108.js +34 -0
- package/dist/lint/post-synth/wgc109.js +33 -0
- package/dist/lint/post-synth/wgc110.js +32 -0
- package/dist/lint/post-synth/wgc111.js +47 -0
- package/dist/lint/post-synth/wgc112.js +46 -0
- package/dist/lint/post-synth/wgc113.js +35 -0
- package/dist/lint/post-synth/wgc201.js +30 -0
- package/dist/lint/post-synth/wgc202.js +33 -0
- package/dist/lint/post-synth/wgc203.js +35 -0
- package/dist/lint/post-synth/wgc204.js +33 -0
- package/dist/lint/post-synth/wgc301.js +28 -0
- package/dist/lint/post-synth/wgc302.js +28 -0
- package/dist/lint/post-synth/wgc303.js +29 -0
- package/dist/lint/post-synth/wgc401.js +50 -0
- package/dist/lint/post-synth/wgc402.js +46 -0
- package/dist/lint/post-synth/wgc403.js +74 -0
- package/dist/lint/post-synth/wgc501.js +63 -0
- package/dist/lint/post-synth/wgc502.js +37 -0
- package/dist/lint/post-synth/wgc503.js +49 -0
- package/dist/lint/rules/hardcoded-project.js +51 -0
- package/dist/lint/rules/hardcoded-region.js +51 -0
- package/dist/lint/rules/index.js +3 -0
- package/dist/lint/rules/public-iam.js +37 -0
- package/dist/lsp/completions.d.ts.map +1 -1
- package/dist/lsp/completions.js +15 -0
- package/dist/lsp/hover.d.ts.map +1 -1
- package/dist/lsp/hover.js +46 -0
- package/dist/manifest.json +1 -1
- package/dist/meta.json +1848 -481
- package/dist/okf/types/API.md +2 -0
- package/dist/okf/types/APIConfig.md +3 -0
- package/dist/okf/types/APIQuotaAdjusterSettings.md +2 -0
- package/dist/okf/types/APIQuotaPreference.md +2 -0
- package/dist/okf/types/AccessBoundaryPolicy.md +2 -0
- package/dist/okf/types/AccessLevel.md +2 -0
- package/dist/okf/types/AccessLevelCondition.md +1 -0
- package/dist/okf/types/AccessPolicy.md +4 -0
- package/dist/okf/types/AddonsConfig.md +1 -0
- package/dist/okf/types/AgentPool.md +2 -0
- package/dist/okf/types/AiplatformModel.md +2 -0
- package/dist/okf/types/AistreamsCluster.md +2 -0
- package/dist/okf/types/AlertPolicy.md +2 -0
- package/dist/okf/types/AlloydbBackup.md +9 -0
- package/dist/okf/types/AlloydbCluster.md +5 -0
- package/dist/okf/types/AlloydbInstance.md +10 -0
- package/dist/okf/types/AnalyticsAccount.md +2 -0
- package/dist/okf/types/AndroidApp.md +4 -0
- package/dist/okf/types/AnywhereCache.md +2 -0
- package/dist/okf/types/ApigatewayGateway.md +3 -0
- package/dist/okf/types/ApigeeEnvironment.md +5 -0
- package/dist/okf/types/ApigeeInstance.md +2 -0
- package/dist/okf/types/ApihubDeployment.md +2 -0
- package/dist/okf/types/ApikeysKey.md +2 -0
- package/dist/okf/types/AppConnection.md +1 -0
- package/dist/okf/types/AppConnector.md +2 -0
- package/dist/okf/types/AppGateway.md +3 -0
- package/dist/okf/types/AppProfile.md +3 -0
- package/dist/okf/types/Application.md +2 -0
- package/dist/okf/types/ArtifactRegistryRepository.md +4 -0
- package/dist/okf/types/Assignment.md +2 -0
- package/dist/okf/types/Attestor.md +2 -0
- package/dist/okf/types/AuthorizationPolicy.md +4 -0
- package/dist/okf/types/AuthorizedView.md +2 -0
- package/dist/okf/types/AutokeyConfig.md +2 -0
- package/dist/okf/types/Automation.md +2 -0
- package/dist/okf/types/Autoscaler.md +3 -0
- package/dist/okf/types/AutoscalingPolicy.md +2 -0
- package/dist/okf/types/BQJob.md +3 -0
- package/dist/okf/types/BackendBucket.md +3 -0
- package/dist/okf/types/BackendBucketSignedURLKey.md +1 -0
- package/dist/okf/types/BackendService.md +5 -0
- package/dist/okf/types/BackendServiceSignedURLKey.md +1 -0
- package/dist/okf/types/BackupPlanAssociation.md +2 -0
- package/dist/okf/types/BackupPolicy.md +2 -0
- package/dist/okf/types/BackupdrBackupPlan.md +2 -0
- package/dist/okf/types/BackupdrBackupVault.md +2 -0
- package/dist/okf/types/Batch.md +2 -0
- package/dist/okf/types/BatchJob.md +2 -0
- package/dist/okf/types/BatchTask.md +3 -0
- package/dist/okf/types/BigLakeCatalog.md +2 -0
- package/dist/okf/types/BigLakeDatabase.md +2 -0
- package/dist/okf/types/BigLakeTable.md +2 -0
- package/dist/okf/types/BigQueryDataPolicy.md +2 -0
- package/dist/okf/types/BigQueryDataset.md +6 -0
- package/dist/okf/types/BigQueryExport.md +2 -0
- package/dist/okf/types/BigQueryTable.md +11 -0
- package/dist/okf/types/BigqueryconnectionConnection.md +2 -0
- package/dist/okf/types/BigquerydatatransferConfig.md +2 -0
- package/dist/okf/types/BigqueryreservationReservation.md +2 -0
- package/dist/okf/types/BigtableInstance.md +1 -0
- package/dist/okf/types/BigtableTable.md +2 -0
- package/dist/okf/types/BillingAccount.md +2 -0
- package/dist/okf/types/BinaryauthorizationPolicy.md +3 -0
- package/dist/okf/types/Brand.md +2 -0
- package/dist/okf/types/BtBackup.md +2 -0
- package/dist/okf/types/BtCluster.md +2 -0
- package/dist/okf/types/Bucket.md +2 -0
- package/dist/okf/types/BucketAccessControl.md +3 -0
- package/dist/okf/types/Budget.md +2 -0
- package/dist/okf/types/CAPool.md +1 -0
- package/dist/okf/types/CapacityCommitment.md +5 -0
- package/dist/okf/types/CertificateAuthority.md +7 -0
- package/dist/okf/types/CertificateIssuanceConfig.md +2 -0
- package/dist/okf/types/CertificateMap.md +3 -0
- package/dist/okf/types/CertificateMapEntry.md +4 -0
- package/dist/okf/types/CertificateTemplate.md +3 -0
- package/dist/okf/types/CertificatemanagerCertificate.md +1 -0
- package/dist/okf/types/ClientConnectorService.md +2 -0
- package/dist/okf/types/ClientTLSPolicy.md +3 -0
- package/dist/okf/types/CloudBatchResourceAllowance.md +2 -0
- package/dist/okf/types/CloudFunction.md +4 -0
- package/dist/okf/types/CloudRunJob.md +13 -0
- package/dist/okf/types/CloudRunService.md +13 -0
- package/dist/okf/types/CloudbuildTrigger.md +4 -0
- package/dist/okf/types/ClouddmsPrivateConnection.md +2 -0
- package/dist/okf/types/CloudidentityGroup.md +5 -0
- package/dist/okf/types/CloudidentityMembership.md +6 -0
- package/dist/okf/types/CloudidsEndpoint.md +1 -0
- package/dist/okf/types/CloudschedulerJob.md +5 -0
- package/dist/okf/types/ComposerEnvironment.md +2 -0
- package/dist/okf/types/ComputeAddress.md +4 -0
- package/dist/okf/types/ComputeDisk.md +9 -0
- package/dist/okf/types/ComputeFirewallPolicy.md +7 -0
- package/dist/okf/types/ComputeHealthCheck.md +4 -0
- package/dist/okf/types/ComputeInstance.md +8 -0
- package/dist/okf/types/ComputeNetworkPeering.md +3 -0
- package/dist/okf/types/ComputeNodeGroup.md +3 -0
- package/dist/okf/types/ComputeReservation.md +6 -0
- package/dist/okf/types/ComputeRoute.md +3 -0
- package/dist/okf/types/ComputeSnapshot.md +7 -0
- package/dist/okf/types/ConfigcontrollerInstance.md +3 -0
- package/dist/okf/types/ConnectionProfile.md +2 -0
- package/dist/okf/types/ConnectivityTest.md +2 -0
- package/dist/okf/types/Connector.md +3 -0
- package/dist/okf/types/ConsentStore.md +1 -0
- package/dist/okf/types/ConsumerGroup.md +2 -0
- package/dist/okf/types/ConsumerQuotaOverride.md +2 -0
- package/dist/okf/types/Contact.md +2 -0
- package/dist/okf/types/ContainerattachedCluster.md +8 -0
- package/dist/okf/types/ConversionWorkspace.md +2 -0
- package/dist/okf/types/CryptoKeyVersion.md +5 -0
- package/dist/okf/types/CustomClass.md +2 -0
- package/dist/okf/types/CustomConstraint.md +2 -0
- package/dist/okf/types/CustomRole.md +3 -0
- package/dist/okf/types/CustomTargetType.md +2 -0
- package/dist/okf/types/DICOMStore.md +2 -0
- package/dist/okf/types/DNSAuthorization.md +2 -0
- package/dist/okf/types/DNSManagedZone.md +3 -0
- package/dist/okf/types/DNSRecordSet.md +1 -0
- package/dist/okf/types/Dashboard.md +2 -0
- package/dist/okf/types/DataExchange.md +2 -0
- package/dist/okf/types/DataLabelingJob.md +2 -0
- package/dist/okf/types/DataPolicy.md +2 -0
- package/dist/okf/types/DataStore.md +2 -0
- package/dist/okf/types/DataStoreTargetSite.md +2 -0
- package/dist/okf/types/Database.md +2 -0
- package/dist/okf/types/DatacatalogEntryGroup.md +2 -0
- package/dist/okf/types/DataflowJob.md +4 -0
- package/dist/okf/types/DataformRepository.md +2 -0
- package/dist/okf/types/DatafusionInstance.md +10 -0
- package/dist/okf/types/DataplexEntryGroup.md +2 -0
- package/dist/okf/types/DataplexTask.md +2 -0
- package/dist/okf/types/DataprocCluster.md +2 -0
- package/dist/okf/types/DataprocJob.md +2 -0
- package/dist/okf/types/DataprocNodeGroup.md +2 -0
- package/dist/okf/types/DataprocSession.md +2 -0
- package/dist/okf/types/DatasetAccess.md +2 -0
- package/dist/okf/types/DatastoreIndex.md +2 -0
- package/dist/okf/types/DatastreamPrivateConnection.md +2 -0
- package/dist/okf/types/DatastreamRoute.md +2 -0
- package/dist/okf/types/DefaultObjectAccessControl.md +5 -0
- package/dist/okf/types/DefaultSupportedIDPConfig.md +2 -0
- package/dist/okf/types/DeidentifyTemplate.md +4 -0
- package/dist/okf/types/DeliveryPipeline.md +2 -0
- package/dist/okf/types/DenyPolicy.md +2 -0
- package/dist/okf/types/DeployPolicy.md +2 -0
- package/dist/okf/types/DeploymentResourcePool.md +2 -0
- package/dist/okf/types/DeploymentmanagerDeployment.md +4 -0
- package/dist/okf/types/Device.md +8 -0
- package/dist/okf/types/DeviceRegistry.md +1 -0
- package/dist/okf/types/DevicestreamingSession.md +2 -0
- package/dist/okf/types/DialogflowAgent.md +2 -0
- package/dist/okf/types/DialogflowEntityType.md +2 -0
- package/dist/okf/types/DialogflowIntent.md +3 -0
- package/dist/okf/types/DialogflowcxAgent.md +3 -0
- package/dist/okf/types/DialogflowcxEntityType.md +2 -0
- package/dist/okf/types/DialogflowcxIntent.md +2 -0
- package/dist/okf/types/DiscoveredService.md +2 -0
- package/dist/okf/types/DiscoveredWorkload.md +2 -0
- package/dist/okf/types/DiskResourcePolicyAttachment.md +1 -0
- package/dist/okf/types/DnsPolicy.md +1 -0
- package/dist/okf/types/Document.md +2 -0
- package/dist/okf/types/DomainMapping.md +2 -0
- package/dist/okf/types/EdgeCacheKeyset.md +1 -0
- package/dist/okf/types/EdgeCacheOrigin.md +1 -0
- package/dist/okf/types/EdgeCacheService.md +1 -0
- package/dist/okf/types/EdgecontainerCluster.md +9 -0
- package/dist/okf/types/EdgecontainerNodePool.md +4 -0
- package/dist/okf/types/EdgenetworkNetwork.md +4 -0
- package/dist/okf/types/EndpointAttachment.md +2 -0
- package/dist/okf/types/EndpointPolicy.md +3 -0
- package/dist/okf/types/Engine.md +2 -0
- package/dist/okf/types/Enrollment.md +2 -0
- package/dist/okf/types/Entitlement.md +2 -0
- package/dist/okf/types/Entry.md +2 -0
- package/dist/okf/types/EntryType.md +2 -0
- package/dist/okf/types/Envgroup.md +2 -0
- package/dist/okf/types/EnvgroupAttachment.md +2 -0
- package/dist/okf/types/EventarcChannel.md +2 -0
- package/dist/okf/types/EventarcTrigger.md +5 -0
- package/dist/okf/types/ExampleStore.md +2 -0
- package/dist/okf/types/ExternalAccessRule.md +2 -0
- package/dist/okf/types/ExternalAddress.md +2 -0
- package/dist/okf/types/ExternalVPNGateway.md +3 -0
- package/dist/okf/types/FHIRStore.md +2 -0
- package/dist/okf/types/Feature.md +4 -0
- package/dist/okf/types/FeatureMembership.md +1 -0
- package/dist/okf/types/Featurestore.md +2 -0
- package/dist/okf/types/FeaturestoreEntityType.md +5 -0
- package/dist/okf/types/FeaturestoreEntityTypeFeature.md +5 -0
- package/dist/okf/types/Federation.md +2 -0
- package/dist/okf/types/Feed.md +2 -0
- package/dist/okf/types/Field.md +2 -0
- package/dist/okf/types/FilestoreBackup.md +7 -0
- package/dist/okf/types/FilestoreInstance.md +5 -0
- package/dist/okf/types/FilestoreSnapshot.md +4 -0
- package/dist/okf/types/FirebaseProject.md +3 -0
- package/dist/okf/types/FirebasedatabaseInstance.md +4 -0
- package/dist/okf/types/FirebasehostingChannel.md +2 -0
- package/dist/okf/types/FirestoreBackupSchedule.md +2 -0
- package/dist/okf/types/FirestoreIndex.md +2 -0
- package/dist/okf/types/Firewall.md +3 -0
- package/dist/okf/types/FirewallPolicyAssociation.md +2 -0
- package/dist/okf/types/FirewallPolicyRule.md +4 -0
- package/dist/okf/types/FirewallRule.md +1 -0
- package/dist/okf/types/FlexTemplateJob.md +4 -0
- package/dist/okf/types/FlexibleAppVersion.md +2 -0
- package/dist/okf/types/Flow.md +2 -0
- package/dist/okf/types/FolderFeed.md +3 -0
- package/dist/okf/types/ForwardingRule.md +10 -0
- package/dist/okf/types/Fulfillment.md +2 -0
- package/dist/okf/types/Function.md +5 -0
- package/dist/okf/types/FutureReservation.md +2 -0
- package/dist/okf/types/GCPServiceAccount.md +5 -0
- package/dist/okf/types/GCPUserAccessBinding.md +2 -0
- package/dist/okf/types/GCPolicy.md +1 -0
- package/dist/okf/types/GKECluster.md +8 -0
- package/dist/okf/types/GRPCRoute.md +4 -0
- package/dist/okf/types/GcsFolder.md +2 -0
- package/dist/okf/types/GkebackupBackup.md +2 -0
- package/dist/okf/types/GkebackupBackupPlan.md +2 -0
- package/dist/okf/types/GkehubMembership.md +6 -0
- package/dist/okf/types/GkehubNamespace.md +2 -0
- package/dist/okf/types/GlobalNetworkEndpoint.md +1 -0
- package/dist/okf/types/GlobalNetworkEndpointGroup.md +2 -0
- package/dist/okf/types/GoogleChannelConfig.md +2 -0
- package/dist/okf/types/GuestPolicy.md +4 -0
- package/dist/okf/types/HL7V2Store.md +2 -0
- package/dist/okf/types/HMACKey.md +5 -0
- package/dist/okf/types/HTTPHealthCheck.md +3 -0
- package/dist/okf/types/HTTPRoute.md +4 -0
- package/dist/okf/types/HTTPSHealthCheck.md +3 -0
- package/dist/okf/types/HealthcareDataset.md +2 -0
- package/dist/okf/types/Hub.md +5 -0
- package/dist/okf/types/IAMAuditConfig.md +1 -0
- package/dist/okf/types/IAMPolicy.md +1 -0
- package/dist/okf/types/IAMPolicyMember.md +1 -0
- package/dist/okf/types/IdentityAwareProxyClient.md +2 -0
- package/dist/okf/types/IdentityplatformConfig.md +2 -0
- package/dist/okf/types/Image.md +5 -0
- package/dist/okf/types/ImportJob.md +2 -0
- package/dist/okf/types/InboundSAMLConfig.md +1 -0
- package/dist/okf/types/IndexEndpoint.md +6 -0
- package/dist/okf/types/InspectTemplate.md +4 -0
- package/dist/okf/types/InstanceAttachment.md +2 -0
- package/dist/okf/types/InstanceConfig.md +2 -0
- package/dist/okf/types/InstanceEndpoint.md +1 -0
- package/dist/okf/types/InstanceGroup.md +3 -0
- package/dist/okf/types/InstanceGroupManager.md +8 -0
- package/dist/okf/types/InstanceGroupNamedPort.md +1 -0
- package/dist/okf/types/InstanceTemplate.md +5 -0
- package/dist/okf/types/InterceptDeployment.md +2 -0
- package/dist/okf/types/InterceptEndpointGroup.md +2 -0
- package/dist/okf/types/Interconnect.md +2 -0
- package/dist/okf/types/InterconnectAttachment.md +9 -0
- package/dist/okf/types/InternalRange.md +2 -0
- package/dist/okf/types/JobTrigger.md +5 -0
- package/dist/okf/types/KMSCryptoKey.md +2 -0
- package/dist/okf/types/KMSKeyRing.md +2 -0
- package/dist/okf/types/KeyHandle.md +2 -0
- package/dist/okf/types/KeyRingImportJob.md +4 -0
- package/dist/okf/types/LBRouteExtension.md +2 -0
- package/dist/okf/types/Lake.md +2 -0
- package/dist/okf/types/Lien.md +3 -0
- package/dist/okf/types/Link.md +2 -0
- package/dist/okf/types/Listing.md +2 -0
- package/dist/okf/types/LocationTagBinding.md +3 -0
- package/dist/okf/types/LogBucket.md +4 -0
- package/dist/okf/types/LogExclusion.md +3 -0
- package/dist/okf/types/LogMetric.md +3 -0
- package/dist/okf/types/LogSink.md +2 -0
- package/dist/okf/types/LogView.md +3 -0
- package/dist/okf/types/LogicalView.md +3 -0
- package/dist/okf/types/Machine.md +2 -0
- package/dist/okf/types/MachineImage.md +2 -0
- package/dist/okf/types/ManagedFolder.md +2 -0
- package/dist/okf/types/ManagedSSLCertificate.md +1 -0
- package/dist/okf/types/ManagedkafkaCluster.md +2 -0
- package/dist/okf/types/ManagedkafkaTopic.md +2 -0
- package/dist/okf/types/ManagementServer.md +2 -0
- package/dist/okf/types/MaterializedView.md +3 -0
- package/dist/okf/types/MembershipBinding.md +2 -0
- package/dist/okf/types/MemcacheInstance.md +4 -0
- package/dist/okf/types/MemorystoreInstance.md +2 -0
- package/dist/okf/types/Mesh.md +4 -0
- package/dist/okf/types/MetadataStore.md +2 -0
- package/dist/okf/types/MetastoreBackup.md +2 -0
- package/dist/okf/types/MetastoreService.md +2 -0
- package/dist/okf/types/MetricDescriptor.md +2 -0
- package/dist/okf/types/MigrationJob.md +2 -0
- package/dist/okf/types/MlengineModel.md +1 -0
- package/dist/okf/types/MonGroup.md +1 -0
- package/dist/okf/types/MonService.md +1 -0
- package/dist/okf/types/MonitoredProject.md +2 -0
- package/dist/okf/types/MuteConfig.md +2 -0
- package/dist/okf/types/NATAddress.md +3 -0
- package/dist/okf/types/NetappBackupVault.md +2 -0
- package/dist/okf/types/NetworkAttachment.md +2 -0
- package/dist/okf/types/NetworkEdgeSecurityService.md +2 -0
- package/dist/okf/types/NetworkEndpoint.md +1 -0
- package/dist/okf/types/NetworkEndpointGroup.md +3 -0
- package/dist/okf/types/NetworkFirewallPolicy.md +7 -0
- package/dist/okf/types/NetworkFirewallPolicyAssociation.md +2 -0
- package/dist/okf/types/NetworkFirewallPolicyRule.md +3 -0
- package/dist/okf/types/NetworkPeeringRoutesConfig.md +1 -0
- package/dist/okf/types/NetworkPolicy.md +2 -0
- package/dist/okf/types/NetworkservicesGateway.md +4 -0
- package/dist/okf/types/Node.md +2 -0
- package/dist/okf/types/NodePool.md +2 -0
- package/dist/okf/types/NodeTemplate.md +4 -0
- package/dist/okf/types/Note.md +3 -0
- package/dist/okf/types/NotebookInstance.md +2 -0
- package/dist/okf/types/NotebooksEnvironment.md +2 -0
- package/dist/okf/types/Notification.md +3 -0
- package/dist/okf/types/NotificationChannel.md +3 -0
- package/dist/okf/types/NotificationConfig.md +3 -0
- package/dist/okf/types/OAuthIDPConfig.md +1 -0
- package/dist/okf/types/OSPolicyAssignment.md +9 -0
- package/dist/okf/types/Occurrence.md +5 -0
- package/dist/okf/types/Organization.md +10 -0
- package/dist/okf/types/OrganizationFeed.md +2 -0
- package/dist/okf/types/OrganizationSecurityPolicy.md +3 -0
- package/dist/okf/types/OrganizationSecurityPolicyAssociation.md +2 -0
- package/dist/okf/types/OrganizationSecurityPolicyRule.md +1 -0
- package/dist/okf/types/OrgpolicyPolicy.md +2 -0
- package/dist/okf/types/PacketMirroring.md +4 -0
- package/dist/okf/types/Page.md +2 -0
- package/dist/okf/types/Parameter.md +2 -0
- package/dist/okf/types/ParameterVersion.md +2 -0
- package/dist/okf/types/PartialPolicy.md +1 -0
- package/dist/okf/types/PatchDeployment.md +5 -0
- package/dist/okf/types/PeeredDNSDomain.md +2 -0
- package/dist/okf/types/PerInstanceConfig.md +1 -0
- package/dist/okf/types/PhraseSet.md +2 -0
- package/dist/okf/types/PlatformPolicy.md +2 -0
- package/dist/okf/types/PolicyTag.md +3 -0
- package/dist/okf/types/PrivateCloud.md +2 -0
- package/dist/okf/types/PrivatecaCertificate.md +5 -0
- package/dist/okf/types/Processor.md +2 -0
- package/dist/okf/types/ProcessorDefaultVersion.md +1 -0
- package/dist/okf/types/ProcessorVersion.md +2 -0
- package/dist/okf/types/ProjectDefaultConfig.md +2 -0
- package/dist/okf/types/ProjectFeed.md +2 -0
- package/dist/okf/types/ProjectMetadata.md +1 -0
- package/dist/okf/types/PubSubSnapshot.md +2 -0
- package/dist/okf/types/PubSubSubscription.md +1 -0
- package/dist/okf/types/PubSubTopic.md +1 -0
- package/dist/okf/types/PubsubliteReservation.md +1 -0
- package/dist/okf/types/PubsubliteTopic.md +1 -0
- package/dist/okf/types/RecaptchaenterpriseFirewallPolicy.md +2 -0
- package/dist/okf/types/RecaptchaenterpriseKey.md +2 -0
- package/dist/okf/types/Recognizer.md +2 -0
- package/dist/okf/types/RedisCluster.md +2 -0
- package/dist/okf/types/RedisInstance.md +8 -0
- package/dist/okf/types/RegionAutoscaler.md +3 -0
- package/dist/okf/types/RegionDiskResourcePolicyAttachment.md +1 -0
- package/dist/okf/types/RegionNetworkEndpointGroup.md +2 -0
- package/dist/okf/types/RegionPerInstanceConfig.md +1 -0
- package/dist/okf/types/RegionSSLPolicy.md +4 -0
- package/dist/okf/types/RegionalEndpoint.md +2 -0
- package/dist/okf/types/ResourceBundle.md +2 -0
- package/dist/okf/types/ResourcePolicy.md +3 -0
- package/dist/okf/types/ResourcemanagerFolder.md +5 -0
- package/dist/okf/types/ResourcemanagerPolicy.md +3 -0
- package/dist/okf/types/ResourcemanagerProject.md +2 -0
- package/dist/okf/types/ResponsePolicy.md +1 -0
- package/dist/okf/types/ResponsePolicyRule.md +1 -0
- package/dist/okf/types/Restore.md +2 -0
- package/dist/okf/types/RestorePlan.md +2 -0
- package/dist/okf/types/Router.md +3 -0
- package/dist/okf/types/RouterInterface.md +1 -0
- package/dist/okf/types/RouterNAT.md +1 -0
- package/dist/okf/types/RouterPeer.md +2 -0
- package/dist/okf/types/Routine.md +3 -0
- package/dist/okf/types/Runtime.md +2 -0
- package/dist/okf/types/RuntimeTemplate.md +2 -0
- package/dist/okf/types/SQLDatabase.md +2 -0
- package/dist/okf/types/SQLInstance.md +10 -0
- package/dist/okf/types/SQLUser.md +1 -0
- package/dist/okf/types/SSHPublicKey.md +2 -0
- package/dist/okf/types/SSLCert.md +8 -0
- package/dist/okf/types/SSLCertificate.md +5 -0
- package/dist/okf/types/SSLPolicy.md +4 -0
- package/dist/okf/types/SavedQuery.md +2 -0
- package/dist/okf/types/Schema.md +1 -0
- package/dist/okf/types/Scope.md +5 -0
- package/dist/okf/types/ScopeRBACRoleBinding.md +2 -0
- package/dist/okf/types/SecretCiphertext.md +2 -0
- package/dist/okf/types/SecretManagerSecret.md +3 -0
- package/dist/okf/types/SecretManagerSecretVersion.md +6 -0
- package/dist/okf/types/SecuresourcemanagerInstance.md +2 -0
- package/dist/okf/types/SecuresourcemanagerRepository.md +2 -0
- package/dist/okf/types/SecurityPolicy.md +3 -0
- package/dist/okf/types/ServerTLSPolicy.md +3 -0
- package/dist/okf/types/ServiceAccountKey.md +6 -0
- package/dist/okf/types/ServiceAttachment.md +5 -0
- package/dist/okf/types/ServiceBinding.md +2 -0
- package/dist/okf/types/ServiceConnectionPolicy.md +2 -0
- package/dist/okf/types/ServiceIdentity.md +2 -0
- package/dist/okf/types/ServiceLevelObjective.md +4 -0
- package/dist/okf/types/ServicePerimeter.md +4 -0
- package/dist/okf/types/ServicePerimeterResource.md +1 -0
- package/dist/okf/types/ServiceProjectAttachment.md +2 -0
- package/dist/okf/types/ServiceSplitTraffic.md +1 -0
- package/dist/okf/types/ServicedirectoryEndpoint.md +2 -0
- package/dist/okf/types/ServicedirectoryNamespace.md +2 -0
- package/dist/okf/types/ServicedirectoryService.md +2 -0
- package/dist/okf/types/ServicenetworkingConnection.md +2 -0
- package/dist/okf/types/ServiceusageService.md +1 -0
- package/dist/okf/types/Settings.md +2 -0
- package/dist/okf/types/SharedVPCHostProject.md +1 -0
- package/dist/okf/types/SharedVPCServiceProject.md +1 -0
- package/dist/okf/types/Site.md +3 -0
- package/dist/okf/types/Source.md +2 -0
- package/dist/okf/types/SourcerepoRepository.md +3 -0
- package/dist/okf/types/SpannerBackupSchedule.md +2 -0
- package/dist/okf/types/SpannerDatabase.md +2 -0
- package/dist/okf/types/SpannerInstance.md +3 -0
- package/dist/okf/types/Spoke.md +5 -0
- package/dist/okf/types/StandardAppVersion.md +2 -0
- package/dist/okf/types/StorageBucket.md +3 -0
- package/dist/okf/types/StoragetransferJob.md +5 -0
- package/dist/okf/types/StoredInfoType.md +1 -0
- package/dist/okf/types/Stream.md +3 -0
- package/dist/okf/types/Subnet.md +5 -0
- package/dist/okf/types/Subnetwork.md +8 -0
- package/dist/okf/types/Subscription.md +1 -0
- package/dist/okf/types/SyncAuthorization.md +2 -0
- package/dist/okf/types/TCPRoute.md +4 -0
- package/dist/okf/types/TLSRoute.md +4 -0
- package/dist/okf/types/Tag.md +2 -0
- package/dist/okf/types/TagBinding.md +3 -0
- package/dist/okf/types/TagKey.md +6 -0
- package/dist/okf/types/TagTemplate.md +2 -0
- package/dist/okf/types/TagValue.md +6 -0
- package/dist/okf/types/Target.md +2 -0
- package/dist/okf/types/TargetGRPCProxy.md +5 -0
- package/dist/okf/types/TargetHTTPProxy.md +4 -0
- package/dist/okf/types/TargetHTTPSProxy.md +5 -0
- package/dist/okf/types/TargetInstance.md +3 -0
- package/dist/okf/types/TargetPool.md +2 -0
- package/dist/okf/types/TargetSSLProxy.md +4 -0
- package/dist/okf/types/TargetTCPProxy.md +5 -0
- package/dist/okf/types/TargetVPNGateway.md +4 -0
- package/dist/okf/types/TasksQueue.md +2 -0
- package/dist/okf/types/Taxonomy.md +3 -0
- package/dist/okf/types/Tenant.md +1 -0
- package/dist/okf/types/TenantDefaultSupportedIDPConfig.md +2 -0
- package/dist/okf/types/TenantInboundSAMLConfig.md +1 -0
- package/dist/okf/types/TenantOAuthIDPConfig.md +1 -0
- package/dist/okf/types/Tensorboard.md +6 -0
- package/dist/okf/types/URLMap.md +5 -0
- package/dist/okf/types/UptimeCheckConfig.md +1 -0
- package/dist/okf/types/User.md +2 -0
- package/dist/okf/types/VPCNetwork.md +3 -0
- package/dist/okf/types/VPNGateway.md +2 -0
- package/dist/okf/types/VPNTunnel.md +7 -0
- package/dist/okf/types/VertexaiDataset.md +1 -0
- package/dist/okf/types/VertexaiEndpoint.md +1 -0
- package/dist/okf/types/VertexaiIndex.md +1 -0
- package/dist/okf/types/VirtualMachine.md +2 -0
- package/dist/okf/types/VmwareengineNetwork.md +2 -0
- package/dist/okf/types/VmwareengineNetworkPeering.md +2 -0
- package/dist/okf/types/VpnConnection.md +3 -0
- package/dist/okf/types/WasmPlugin.md +2 -0
- package/dist/okf/types/WebApp.md +3 -0
- package/dist/okf/types/Webhook.md +3 -0
- package/dist/okf/types/WorkerPool.md +2 -0
- package/dist/okf/types/Workflow.md +2 -0
- package/dist/okf/types/WorkflowTemplate.md +4 -0
- package/dist/okf/types/WorkflowsExecution.md +2 -0
- package/dist/okf/types/WorkforcePool.md +3 -0
- package/dist/okf/types/WorkforcePoolProvider.md +2 -0
- package/dist/okf/types/Workload.md +2 -0
- package/dist/okf/types/WorkloadIdentityPool.md +2 -0
- package/dist/okf/types/WorkloadIdentityPoolProvider.md +2 -0
- package/dist/okf/types/Workstation.md +2 -0
- package/dist/okf/types/WorkstationCluster.md +2 -0
- package/dist/okf/types/WorkstationConfig.md +2 -0
- package/dist/okf/types/Zone.md +2 -0
- package/dist/op/activities/floci-gcp.js +49 -0
- package/dist/op/activities/gcp-apply.js +618 -0
- package/dist/op/activities/index.js +10 -0
- package/dist/op/builders.js +50 -0
- package/dist/ownership.js +38 -0
- package/dist/package-cli.js +20 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +377 -0
- package/dist/pseudo.js +15 -0
- package/dist/rules/schema-registry.ts +2 -1
- package/dist/serializer.d.ts.map +1 -1
- package/dist/serializer.js +247 -0
- package/dist/spec/fetch.js +107 -0
- package/dist/spec/parse.d.ts +1 -1
- package/dist/spec/parse.js +339 -0
- package/dist/types/index.d.ts +1367 -0
- package/dist/validate-cli.js +11 -0
- package/dist/validate.js +24 -0
- package/dist/variables.js +15 -0
- package/package.json +8 -8
- package/src/attributes.test.ts +16 -0
- package/src/codegen/generate.ts +8 -3
- package/src/codegen/package.ts +2 -2
- package/src/composites/catalog.ts +7 -1
- package/src/composites/cloud-run-service.ts +12 -5
- package/src/composites/composites.test.ts +17 -0
- package/src/generated/index.d.ts +1367 -0
- package/src/generated/index.ts +487 -487
- package/src/generated/lexicon-gcp.json +1848 -481
- package/src/health.test.ts +59 -0
- package/src/health.ts +123 -0
- package/src/index.ts +3 -0
- package/src/lint/post-synth/schema-registry.ts +2 -1
- package/src/lsp/completions.ts +2 -1
- package/src/lsp/hover.ts +2 -1
- package/src/plugin.ts +8 -0
- package/src/serializer-outputs.test.ts +26 -0
- package/src/serializer.ts +21 -3
- package/src/spec/parse.test.ts +42 -2
- package/src/spec/parse.ts +17 -1
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { parseYAML } from "@intentius/chant/yaml";
|
|
3
|
+
import { sleep } from "@intentius/chant/op";
|
|
4
|
+
import { hasOwnershipMarker, OWNERSHIP_MANAGED_BY_VALUE } from "@intentius/chant/ownership";
|
|
5
|
+
import { GCP_RESOURCE_OWNERSHIP_KEYS } from "../../ownership.js";
|
|
6
|
+
import { applyResult, } from "@intentius/chant/apply";
|
|
7
|
+
const PROJECT_ID_ANNOTATION = "cnrm.cloud.google.com/project-id";
|
|
8
|
+
/**
|
|
9
|
+
* The GCP labels chant stamps on resources it creates.
|
|
10
|
+
*
|
|
11
|
+
* Only the managed-by marker, not stack/env: this applier has no ownership
|
|
12
|
+
* marker to hand — the serializer stamps those from project config onto the
|
|
13
|
+
* Config Connector object. Same shape the fly serializer uses when no ownership
|
|
14
|
+
* context is set.
|
|
15
|
+
*/
|
|
16
|
+
export function chantOwnershipLabels() {
|
|
17
|
+
return { [GCP_RESOURCE_OWNERSHIP_KEYS.managedBy]: OWNERSHIP_MANAGED_BY_VALUE };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* True when a live resource's labels carry chant's ownership marker.
|
|
21
|
+
*
|
|
22
|
+
* Resolves through core's `hasOwnershipMarker` against the lexicon's declared
|
|
23
|
+
* GCP-resource channel (#1446) rather than comparing a string literal inline,
|
|
24
|
+
* so the stamp and the prune filter cannot drift. The key itself is unchanged
|
|
25
|
+
* and deliberately GCP-valid — see `../../ownership.ts` for why this surface
|
|
26
|
+
* cannot use core's `LABEL_OWNERSHIP_KEYS`.
|
|
27
|
+
*/
|
|
28
|
+
export function isChantOwned(labels) {
|
|
29
|
+
return hasOwnershipMarker(labels ?? undefined, GCP_RESOURCE_OWNERSHIP_KEYS);
|
|
30
|
+
}
|
|
31
|
+
/** Merge the ownership marker into a create/update body's `labels`. */
|
|
32
|
+
function stampOwnership(body) {
|
|
33
|
+
const existing = body.labels ?? {};
|
|
34
|
+
return { ...body, labels: { ...existing, ...chantOwnershipLabels() } };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A standard `google.longrunning` operation spec: the create response carries an
|
|
38
|
+
* operation `name` (`projects/…/operations/…`), polled at `{base}/{version}/{name}`
|
|
39
|
+
* until `done: true`. Reused by every service that follows the pattern.
|
|
40
|
+
*/
|
|
41
|
+
export function longRunningOperation(version) {
|
|
42
|
+
return {
|
|
43
|
+
pollUrl(createResponseBody, { base }) {
|
|
44
|
+
const opName = createResponseBody?.name;
|
|
45
|
+
if (!opName || !opName.includes("/operations/"))
|
|
46
|
+
return undefined;
|
|
47
|
+
return `${base}/${version}/${opName}`;
|
|
48
|
+
},
|
|
49
|
+
isDone(operationBody) {
|
|
50
|
+
return operationBody?.done === true;
|
|
51
|
+
},
|
|
52
|
+
error(operationBody) {
|
|
53
|
+
return operationBody?.error?.message;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Map a CNRM StorageBucket to a GCS Buckets:insert body. Pure. CNRM mirrors the
|
|
59
|
+
* Terraform google provider which mirrors the GCS API, so most fields are
|
|
60
|
+
* field-for-field; the renames are `uniformBucketLevelAccess` →
|
|
61
|
+
* `iamConfiguration.uniformBucketLevelAccess.enabled` and `lifecycleRule` →
|
|
62
|
+
* `lifecycle.rule`.
|
|
63
|
+
*/
|
|
64
|
+
export function bucketInsertBody(cnrm) {
|
|
65
|
+
const name = cnrm.metadata?.name;
|
|
66
|
+
if (!name)
|
|
67
|
+
throw new Error("StorageBucket has no metadata.name");
|
|
68
|
+
const spec = cnrm.spec ?? {};
|
|
69
|
+
const body = { name };
|
|
70
|
+
if (spec.location)
|
|
71
|
+
body.location = spec.location;
|
|
72
|
+
if (spec.storageClass)
|
|
73
|
+
body.storageClass = spec.storageClass;
|
|
74
|
+
if (spec.uniformBucketLevelAccess !== undefined) {
|
|
75
|
+
body.iamConfiguration = { uniformBucketLevelAccess: { enabled: spec.uniformBucketLevelAccess } };
|
|
76
|
+
}
|
|
77
|
+
if (spec.versioning?.enabled !== undefined) {
|
|
78
|
+
body.versioning = { enabled: spec.versioning.enabled };
|
|
79
|
+
}
|
|
80
|
+
if (spec.lifecycleRule?.length) {
|
|
81
|
+
body.lifecycle = {
|
|
82
|
+
rule: spec.lifecycleRule.map((r) => ({
|
|
83
|
+
action: r.action ?? {},
|
|
84
|
+
...(r.condition ? { condition: r.condition } : {}),
|
|
85
|
+
})),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return body;
|
|
89
|
+
}
|
|
90
|
+
/** Map a CNRM PubSubTopic to a Pub/Sub Topic body. Pure. Name travels in the URL. */
|
|
91
|
+
export function pubSubTopicBody(resource) {
|
|
92
|
+
const spec = (resource.spec ?? {});
|
|
93
|
+
const body = {};
|
|
94
|
+
const labels = resource.metadata?.labels;
|
|
95
|
+
if (labels && Object.keys(labels).length)
|
|
96
|
+
body.labels = labels;
|
|
97
|
+
if (spec.messageRetentionDuration)
|
|
98
|
+
body.messageRetentionDuration = spec.messageRetentionDuration;
|
|
99
|
+
return body;
|
|
100
|
+
}
|
|
101
|
+
export const storageBucketMapper = {
|
|
102
|
+
kind: "StorageBucket",
|
|
103
|
+
defaultHost: "https://storage.googleapis.com",
|
|
104
|
+
plan(resource, { base, project }) {
|
|
105
|
+
const body = stampOwnership(bucketInsertBody(resource));
|
|
106
|
+
const url = `${base}/storage/v1/b/${encodeURIComponent(body.name)}`;
|
|
107
|
+
// Reconcile in place with a PATCH of the desired mutable fields (the name is
|
|
108
|
+
// immutable and travels in the URL).
|
|
109
|
+
const { name: _name, ...patch } = body;
|
|
110
|
+
return {
|
|
111
|
+
getUrl: url,
|
|
112
|
+
create: { method: "POST", url: `${base}/storage/v1/b?project=${encodeURIComponent(project)}`, body },
|
|
113
|
+
update: { method: "PATCH", url, body: patch },
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
list: {
|
|
117
|
+
url: ({ base, project }) => `${base}/storage/v1/b?project=${encodeURIComponent(project)}`,
|
|
118
|
+
items: (body) => (body?.items ?? []),
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
export const pubSubTopicMapper = {
|
|
122
|
+
kind: "PubSubTopic",
|
|
123
|
+
defaultHost: "https://pubsub.googleapis.com",
|
|
124
|
+
plan(resource, { base, project }) {
|
|
125
|
+
const topic = resource.metadata?.name;
|
|
126
|
+
if (!topic)
|
|
127
|
+
throw new Error("PubSubTopic has no metadata.name");
|
|
128
|
+
// Pub/Sub creates a topic with an idempotent PUT to its resource URL; GET the
|
|
129
|
+
// same URL for the existence check.
|
|
130
|
+
const url = `${base}/v1/projects/${encodeURIComponent(project)}/topics/${encodeURIComponent(topic)}`;
|
|
131
|
+
const body = stampOwnership(pubSubTopicBody(resource));
|
|
132
|
+
// UpdateTopic uses the {topic, updateMask} envelope — the mask lists the
|
|
133
|
+
// fields being set (labels, messageRetentionDuration).
|
|
134
|
+
const update = {
|
|
135
|
+
method: "PATCH",
|
|
136
|
+
url,
|
|
137
|
+
body: { topic: { name: `projects/${project}/topics/${topic}`, ...body }, updateMask: Object.keys(body).join(",") },
|
|
138
|
+
};
|
|
139
|
+
return { getUrl: url, create: { method: "PUT", url, body }, update };
|
|
140
|
+
},
|
|
141
|
+
list: {
|
|
142
|
+
url: ({ base, project }) => `${base}/v1/projects/${encodeURIComponent(project)}/topics`,
|
|
143
|
+
items: (body) => (body?.topics ?? []).map((t) => ({ name: t.name.split("/").pop() ?? t.name, labels: t.labels })),
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
/** Map a CNRM RunService to a Cloud Run v2 Service body. Pure. */
|
|
147
|
+
export function cloudRunServiceBody(resource) {
|
|
148
|
+
const spec = (resource.spec ?? {});
|
|
149
|
+
const body = {};
|
|
150
|
+
if (spec.template)
|
|
151
|
+
body.template = spec.template;
|
|
152
|
+
return body;
|
|
153
|
+
}
|
|
154
|
+
export const cloudRunServiceMapper = {
|
|
155
|
+
kind: "RunService",
|
|
156
|
+
defaultHost: "https://run.googleapis.com",
|
|
157
|
+
// Cloud Run create is asynchronous — it returns a google.longrunning operation.
|
|
158
|
+
operation: longRunningOperation("v2"),
|
|
159
|
+
plan(resource, { base, project }) {
|
|
160
|
+
const name = resource.metadata?.name;
|
|
161
|
+
if (!name)
|
|
162
|
+
throw new Error("RunService has no metadata.name");
|
|
163
|
+
const location = (resource.spec ?? {}).location ?? "us-central1";
|
|
164
|
+
const services = `${base}/v2/projects/${encodeURIComponent(project)}/locations/${encodeURIComponent(location)}/services`;
|
|
165
|
+
const url = `${services}/${encodeURIComponent(name)}`;
|
|
166
|
+
return {
|
|
167
|
+
getUrl: url,
|
|
168
|
+
create: {
|
|
169
|
+
method: "POST",
|
|
170
|
+
url: `${services}?serviceId=${encodeURIComponent(name)}`,
|
|
171
|
+
body: cloudRunServiceBody(resource),
|
|
172
|
+
},
|
|
173
|
+
// Cloud Run reconciles with a PATCH of the service; like create it returns
|
|
174
|
+
// a long-running operation, polled via the mapper's `operation`.
|
|
175
|
+
update: { method: "PATCH", url, body: cloudRunServiceBody(resource) },
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Map a CNRM PubSubSubscription to a Pub/Sub Subscription body, resolving the
|
|
181
|
+
* `topicRef` to a full topic path. Pure.
|
|
182
|
+
*/
|
|
183
|
+
export function pubSubSubscriptionBody(resource, project) {
|
|
184
|
+
const spec = (resource.spec ?? {});
|
|
185
|
+
const ref = spec.topicRef;
|
|
186
|
+
const topic = ref?.external ?? (ref?.name ? `projects/${project}/topics/${ref.name}` : undefined);
|
|
187
|
+
if (!topic)
|
|
188
|
+
throw new Error("PubSubSubscription has no spec.topicRef.name");
|
|
189
|
+
const body = { topic };
|
|
190
|
+
if (spec.ackDeadlineSeconds !== undefined)
|
|
191
|
+
body.ackDeadlineSeconds = spec.ackDeadlineSeconds;
|
|
192
|
+
return body;
|
|
193
|
+
}
|
|
194
|
+
export const pubSubSubscriptionMapper = {
|
|
195
|
+
kind: "PubSubSubscription",
|
|
196
|
+
defaultHost: "https://pubsub.googleapis.com",
|
|
197
|
+
plan(resource, { base, project }) {
|
|
198
|
+
const sub = resource.metadata?.name;
|
|
199
|
+
if (!sub)
|
|
200
|
+
throw new Error("PubSubSubscription has no metadata.name");
|
|
201
|
+
const url = `${base}/v1/projects/${encodeURIComponent(project)}/subscriptions/${encodeURIComponent(sub)}`;
|
|
202
|
+
return { getUrl: url, create: { method: "PUT", url, body: pubSubSubscriptionBody(resource, project) } };
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
/** Map a CNRM SecretManagerSecret to a Secret Manager create body. Pure. */
|
|
206
|
+
export function secretBody(resource) {
|
|
207
|
+
const spec = (resource.spec ?? {});
|
|
208
|
+
return { replication: spec.replication ?? { automatic: {} } };
|
|
209
|
+
}
|
|
210
|
+
export const secretManagerSecretMapper = {
|
|
211
|
+
kind: "SecretManagerSecret",
|
|
212
|
+
defaultHost: "https://secretmanager.googleapis.com",
|
|
213
|
+
plan(resource, { base, project }) {
|
|
214
|
+
const name = resource.metadata?.name;
|
|
215
|
+
if (!name)
|
|
216
|
+
throw new Error("SecretManagerSecret has no metadata.name");
|
|
217
|
+
const secrets = `${base}/v1/projects/${encodeURIComponent(project)}/secrets`;
|
|
218
|
+
const url = `${secrets}/${encodeURIComponent(name)}`;
|
|
219
|
+
const body = stampOwnership(secretBody(resource));
|
|
220
|
+
return {
|
|
221
|
+
getUrl: url,
|
|
222
|
+
create: { method: "POST", url: `${secrets}?secretId=${encodeURIComponent(name)}`, body },
|
|
223
|
+
// UpdateSecret carries the updateMask in the query; only labels are mutable here.
|
|
224
|
+
update: { method: "PATCH", url: `${url}?updateMask=labels`, body: { labels: body.labels } },
|
|
225
|
+
};
|
|
226
|
+
},
|
|
227
|
+
list: {
|
|
228
|
+
url: ({ base, project }) => `${base}/v1/projects/${encodeURIComponent(project)}/secrets`,
|
|
229
|
+
items: (body) => (body?.secrets ?? []).map((s) => ({ name: s.name.split("/").pop() ?? s.name, labels: s.labels })),
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
/** Map a CNRM IAMServiceAccount to a service-account create body. Pure. */
|
|
233
|
+
export function serviceAccountBody(resource, accountId) {
|
|
234
|
+
const spec = (resource.spec ?? {});
|
|
235
|
+
return { accountId, serviceAccount: spec.displayName ? { displayName: spec.displayName } : {} };
|
|
236
|
+
}
|
|
237
|
+
export const gcpServiceAccountMapper = {
|
|
238
|
+
kind: "IAMServiceAccount",
|
|
239
|
+
defaultHost: "https://iam.googleapis.com",
|
|
240
|
+
plan(resource, { base, project }) {
|
|
241
|
+
const accountId = resource.metadata?.name;
|
|
242
|
+
if (!accountId)
|
|
243
|
+
throw new Error("IAMServiceAccount has no metadata.name");
|
|
244
|
+
// The GCP identity is the derived email; IAM service accounts carry no labels,
|
|
245
|
+
// so there is no ownership stamping / prune for this kind.
|
|
246
|
+
const email = `${accountId}@${project}.iam.gserviceaccount.com`;
|
|
247
|
+
const accounts = `${base}/v1/projects/${encodeURIComponent(project)}/serviceAccounts`;
|
|
248
|
+
return {
|
|
249
|
+
getUrl: `${accounts}/${email}`,
|
|
250
|
+
create: { method: "POST", url: accounts, body: serviceAccountBody(resource, accountId) },
|
|
251
|
+
};
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
/** The kind → mapper dispatch table. Adding a resource type is a new entry here. */
|
|
255
|
+
export const MAPPERS = {
|
|
256
|
+
StorageBucket: storageBucketMapper,
|
|
257
|
+
PubSubTopic: pubSubTopicMapper,
|
|
258
|
+
PubSubSubscription: pubSubSubscriptionMapper,
|
|
259
|
+
SecretManagerSecret: secretManagerSecretMapper,
|
|
260
|
+
IAMServiceAccount: gcpServiceAccountMapper,
|
|
261
|
+
RunService: cloudRunServiceMapper,
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Collect the local resource names this resource references via CNRM `*Ref`
|
|
265
|
+
* fields (`topicRef: { name }`, `subnetworkRefs: [{ name }]`, …). `external`
|
|
266
|
+
* refs point outside the manifest and are ignored for ordering. Pure.
|
|
267
|
+
*/
|
|
268
|
+
export function referencedNames(resource) {
|
|
269
|
+
const names = [];
|
|
270
|
+
const visit = (v, key) => {
|
|
271
|
+
if (Array.isArray(v)) {
|
|
272
|
+
for (const x of v)
|
|
273
|
+
visit(x, key);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (v && typeof v === "object") {
|
|
277
|
+
const obj = v;
|
|
278
|
+
if (key && /Refs?$/.test(key) && typeof obj.name === "string") {
|
|
279
|
+
names.push(obj.name);
|
|
280
|
+
}
|
|
281
|
+
for (const [k, val] of Object.entries(obj))
|
|
282
|
+
visit(val, k);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
visit(resource.spec);
|
|
286
|
+
return [...new Set(names)];
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Topologically order resources so a referenced resource comes before the
|
|
290
|
+
* resource that references it (apply order; reverse for delete). Refs to names
|
|
291
|
+
* not in the manifest are left to exist already. Throws on a reference cycle.
|
|
292
|
+
* Pure — a DFS post-order.
|
|
293
|
+
*/
|
|
294
|
+
export function orderByReferences(resources) {
|
|
295
|
+
const byName = new Map();
|
|
296
|
+
for (const r of resources) {
|
|
297
|
+
const n = r.metadata?.name;
|
|
298
|
+
if (n)
|
|
299
|
+
byName.set(n, r);
|
|
300
|
+
}
|
|
301
|
+
const ordered = [];
|
|
302
|
+
const done = new Set();
|
|
303
|
+
const active = new Set();
|
|
304
|
+
const visit = (r) => {
|
|
305
|
+
if (done.has(r))
|
|
306
|
+
return;
|
|
307
|
+
if (active.has(r))
|
|
308
|
+
throw new Error(`reference cycle involving ${r.metadata?.name ?? "?"}`);
|
|
309
|
+
active.add(r);
|
|
310
|
+
for (const ref of referencedNames(r)) {
|
|
311
|
+
const dep = byName.get(ref);
|
|
312
|
+
if (dep && dep !== r)
|
|
313
|
+
visit(dep);
|
|
314
|
+
}
|
|
315
|
+
active.delete(r);
|
|
316
|
+
done.add(r);
|
|
317
|
+
ordered.push(r);
|
|
318
|
+
};
|
|
319
|
+
for (const r of resources)
|
|
320
|
+
visit(r);
|
|
321
|
+
return ordered;
|
|
322
|
+
}
|
|
323
|
+
// ── Resolution + HTTP ─────────────────────────────────────────────────────────
|
|
324
|
+
/**
|
|
325
|
+
* Resolve the endpoint override (#1449): an explicit `endpoint` arg wins, then
|
|
326
|
+
* the `GCP_ENDPOINT_URL` env — the same variable the read path honours
|
|
327
|
+
* (`describe-resources`, floci-gcp), so an apply lands wherever `--live` is
|
|
328
|
+
* already looking. `undefined` means no override: each kind falls back to its
|
|
329
|
+
* real-GCP host. The same rule the aws applier applies to `AWS_ENDPOINT_URL`
|
|
330
|
+
* (#1694) and the fly applier to `FLY_FLAPS_BASE_URL`. Pure.
|
|
331
|
+
*/
|
|
332
|
+
export function resolveGcpEndpoint(args = {}, env = process.env) {
|
|
333
|
+
return args.endpoint || env.GCP_ENDPOINT_URL || undefined;
|
|
334
|
+
}
|
|
335
|
+
/** Resolve the project: `GOOGLE_CLOUD_PROJECT` env, else the CNRM project-id annotation. Pure. */
|
|
336
|
+
export function resolveGcpProject(resource, env = process.env) {
|
|
337
|
+
const project = env.GOOGLE_CLOUD_PROJECT || resource.metadata?.annotations?.[PROJECT_ID_ANNOTATION];
|
|
338
|
+
if (!project) {
|
|
339
|
+
throw new Error(`no GCP project — set GOOGLE_CLOUD_PROJECT or the ${PROJECT_ID_ANNOTATION} annotation`);
|
|
340
|
+
}
|
|
341
|
+
return project;
|
|
342
|
+
}
|
|
343
|
+
const defaultHttp = async (method, url, body, signal) => {
|
|
344
|
+
const res = await fetch(url, {
|
|
345
|
+
method,
|
|
346
|
+
headers: body === undefined ? undefined : { "content-type": "application/json" },
|
|
347
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
348
|
+
signal,
|
|
349
|
+
});
|
|
350
|
+
return { status: res.status, text: await res.text() };
|
|
351
|
+
};
|
|
352
|
+
/**
|
|
353
|
+
* Reconcile one resource via its mapper: `GET` it; if present, PATCH it to the
|
|
354
|
+
* desired state (when the mapper supports `update`, else leave it); if absent,
|
|
355
|
+
* create it. Async create/update return an operation that is polled to
|
|
356
|
+
* completion. `http` is injectable for tests.
|
|
357
|
+
*/
|
|
358
|
+
export async function applyResource(mapper, resource, ctx, http = defaultHttp, signal) {
|
|
359
|
+
const plan = mapper.plan(resource, ctx);
|
|
360
|
+
const name = resource.metadata?.name ?? "?";
|
|
361
|
+
const get = await http("GET", plan.getUrl, undefined, signal);
|
|
362
|
+
if (get.status === 200) {
|
|
363
|
+
// Exists. Reconcile to desired if the mapper supports it; otherwise leave it.
|
|
364
|
+
if (!plan.update) {
|
|
365
|
+
return { kind: mapper.kind, name, created: false, updated: false };
|
|
366
|
+
}
|
|
367
|
+
const res = await http(plan.update.method, plan.update.url, plan.update.body, signal);
|
|
368
|
+
if (res.status >= 300) {
|
|
369
|
+
throw new Error(`${mapper.kind} ${name} update failed (${res.status}): ${res.text}`);
|
|
370
|
+
}
|
|
371
|
+
await pollIfAsync(mapper, res.text, ctx, http, signal);
|
|
372
|
+
return { kind: mapper.kind, name, created: false, updated: true };
|
|
373
|
+
}
|
|
374
|
+
const res = await http(plan.create.method, plan.create.url, plan.create.body, signal);
|
|
375
|
+
if (res.status >= 300) {
|
|
376
|
+
throw new Error(`${mapper.kind} ${name} create failed (${res.status}): ${res.text}`);
|
|
377
|
+
}
|
|
378
|
+
await pollIfAsync(mapper, res.text, ctx, http, signal);
|
|
379
|
+
return { kind: mapper.kind, name, created: true, updated: false };
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* When a mapper is async, extract the long-running operation from a create/update
|
|
383
|
+
* response and poll it to completion so the step never reports success early.
|
|
384
|
+
*/
|
|
385
|
+
async function pollIfAsync(mapper, responseText, ctx, http, signal) {
|
|
386
|
+
if (!mapper.operation)
|
|
387
|
+
return;
|
|
388
|
+
const pollUrl = mapper.operation.pollUrl(parseJson(responseText), ctx);
|
|
389
|
+
if (pollUrl) {
|
|
390
|
+
await waitForOperation(mapper.operation, pollUrl, http, signal);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function parseJson(text) {
|
|
394
|
+
try {
|
|
395
|
+
return JSON.parse(text);
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Poll a long-running operation until it reports done (or errors / times out).
|
|
403
|
+
* `http` and the interval are injectable so tests drive it without real waits.
|
|
404
|
+
*/
|
|
405
|
+
export async function waitForOperation(op, pollUrl, http = defaultHttp, signal, opts) {
|
|
406
|
+
const interval = opts?.intervalMs ?? 2000;
|
|
407
|
+
const deadline = Date.now() + (opts?.timeoutMs ?? 300000);
|
|
408
|
+
let attempt = 0;
|
|
409
|
+
while (Date.now() < deadline) {
|
|
410
|
+
if (signal?.aborted)
|
|
411
|
+
throw new Error("waitForOperation aborted");
|
|
412
|
+
attempt++;
|
|
413
|
+
const res = await http("GET", pollUrl, undefined, signal);
|
|
414
|
+
const body = res.status < 300 ? parseJson(res.text) : undefined;
|
|
415
|
+
if (body) {
|
|
416
|
+
const err = op.error(body);
|
|
417
|
+
if (err)
|
|
418
|
+
throw new Error(`operation failed: ${err}`);
|
|
419
|
+
if (op.isDone(body))
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
await sleep(interval, signal);
|
|
423
|
+
}
|
|
424
|
+
throw new Error(`operation did not complete within timeout: ${pollUrl}`);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* A manifest entry with no `kind` is malformed, not unsupported (#1447).
|
|
428
|
+
*
|
|
429
|
+
* The old guard skipped it in silence, which put a hand-written or truncated
|
|
430
|
+
* manifest in the same bucket as a kind chant simply has no mapper for. One is
|
|
431
|
+
* a bug in the input and the other is a known gap in coverage; only the second
|
|
432
|
+
* belongs in `notAttempted`. Throws so the first surfaces.
|
|
433
|
+
*/
|
|
434
|
+
function requireKind(resource, manifestPath) {
|
|
435
|
+
if (!resource.kind) {
|
|
436
|
+
const name = resource.metadata?.name;
|
|
437
|
+
throw new Error(`${manifestPath}: manifest entry has no "kind"${name ? ` (metadata.name: ${name})` : ""} — ` +
|
|
438
|
+
`a CNRM resource must declare one. This is a malformed manifest, not an unsupported kind.`);
|
|
439
|
+
}
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
/** Parse a built manifest into CNRM resource objects — YAML (multi-doc) or JSON. Pure. */
|
|
443
|
+
export function parseManifest(content, path) {
|
|
444
|
+
if (/\.json$/i.test(path)) {
|
|
445
|
+
const parsed = JSON.parse(content);
|
|
446
|
+
return (Array.isArray(parsed) ? parsed : [parsed]);
|
|
447
|
+
}
|
|
448
|
+
return content
|
|
449
|
+
.split(/^---\s*$/m)
|
|
450
|
+
.map((doc) => doc.trim())
|
|
451
|
+
.filter(Boolean)
|
|
452
|
+
.map((doc) => parseYAML(doc));
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Normalize a gcp apply/delete result into core's apply envelope (#1446).
|
|
456
|
+
*
|
|
457
|
+
* The lexicon keeps its own richer shape — `created`/`updated` per resource,
|
|
458
|
+
* the CNRM `kind` — and this projects it onto the shared tri-state so a caller
|
|
459
|
+
* can read any applier's result the same way. Core's contract is the interface;
|
|
460
|
+
* it is not a replacement for what this applier knows.
|
|
461
|
+
*/
|
|
462
|
+
export function toApplyResult(result) {
|
|
463
|
+
const applied = (result.applied ?? []).map((a) => ({
|
|
464
|
+
kind: a.kind,
|
|
465
|
+
name: a.name,
|
|
466
|
+
action: a.created ? "created" : a.updated ? "updated" : "unchanged",
|
|
467
|
+
}));
|
|
468
|
+
const notAttempted = [
|
|
469
|
+
...(result.notAttempted ?? []).map((n) => ({ kind: n.kind, name: n.name, reason: n.reason })),
|
|
470
|
+
// A kind the prune could not consider has no single resource name — the
|
|
471
|
+
// whole kind went unexamined, which `not-prunable` is the reason for.
|
|
472
|
+
...(result.notPrunable ?? []).map((n) => ({
|
|
473
|
+
kind: n.kind,
|
|
474
|
+
name: "*",
|
|
475
|
+
reason: "not-prunable",
|
|
476
|
+
...(n.detail ? { detail: n.detail } : {}),
|
|
477
|
+
})),
|
|
478
|
+
];
|
|
479
|
+
// `gcpDelete` reports deletions as `deleted`; they are prunes in the shared
|
|
480
|
+
// vocabulary — the applier removed something the plan no longer wants.
|
|
481
|
+
return applyResult(applied, result.pruned ?? result.deleted ?? [], notAttempted);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Owned-only prune: for each manifested kind with `list` support, delete the
|
|
485
|
+
* chant-owned live resources whose name is not in `desiredByKind`. Foreign
|
|
486
|
+
* resources (no ownership label) are left alone.
|
|
487
|
+
*
|
|
488
|
+
* Returns what it could not consider alongside what it deleted — a kind with no
|
|
489
|
+
* `list`, or whose list call failed, is reported rather than dropped (#1447).
|
|
490
|
+
*/
|
|
491
|
+
export async function pruneOrphans(desired, resolve, http = defaultHttp, signal) {
|
|
492
|
+
const desiredByKind = new Map();
|
|
493
|
+
for (const r of desired) {
|
|
494
|
+
if (!r.kind)
|
|
495
|
+
continue;
|
|
496
|
+
const names = desiredByKind.get(r.kind) ?? new Set();
|
|
497
|
+
if (r.metadata?.name)
|
|
498
|
+
names.add(r.metadata.name);
|
|
499
|
+
desiredByKind.set(r.kind, names);
|
|
500
|
+
}
|
|
501
|
+
const pruned = [];
|
|
502
|
+
const notPrunable = [];
|
|
503
|
+
for (const [kind, keep] of desiredByKind) {
|
|
504
|
+
const mapper = MAPPERS[kind];
|
|
505
|
+
if (!mapper?.list) {
|
|
506
|
+
console.log(`prune: cannot list kind ${kind} — owned orphans of it are not considered`);
|
|
507
|
+
notPrunable.push({ kind, reason: "no-list-capability" });
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
const ctx = resolve(mapper, desired.find((r) => r.kind === kind));
|
|
511
|
+
const res = await http("GET", mapper.list.url(ctx), undefined, signal);
|
|
512
|
+
if (res.status >= 300) {
|
|
513
|
+
console.log(`prune: listing kind ${kind} failed (${res.status}) — not considered`);
|
|
514
|
+
notPrunable.push({ kind, reason: "list-failed", detail: `${res.status}: ${res.text}` });
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
for (const item of mapper.list.items(parseJson(res.text))) {
|
|
518
|
+
if (!isChantOwned(item.labels) || keep.has(item.name))
|
|
519
|
+
continue;
|
|
520
|
+
const result = await deleteResource(mapper, { kind, metadata: { name: item.name } }, ctx, http, signal);
|
|
521
|
+
console.log(`pruned: ${kind}/${item.name} (${ctx.base})`);
|
|
522
|
+
pruned.push(result);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return { pruned, notPrunable };
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* The native GCP applier (#706) — read a built CNRM manifest and apply each
|
|
529
|
+
* resource directly to its GCP REST API, targeting a local floci-gcp emulator or
|
|
530
|
+
* real GCP by endpoint override. Unlike AWS/Azure/k8s, GCP has no native deploy
|
|
531
|
+
* service to shell out to, so chant maps each `kind` to a REST call itself (the
|
|
532
|
+
* `MAPPERS` dispatch table). Uses longInfra profile. `http` is injectable for
|
|
533
|
+
* tests.
|
|
534
|
+
*
|
|
535
|
+
* A kind `MAPPERS` does not cover is **reported, not dropped** — it comes back
|
|
536
|
+
* in `notAttempted` (#1447). Before that, it was a `console.log` and a
|
|
537
|
+
* populated `applied` array, so a caller could not tell a partial apply from a
|
|
538
|
+
* complete one and `ApplyOp` reported success either way.
|
|
539
|
+
*/
|
|
540
|
+
export async function gcpApply(args, signal, http = defaultHttp) {
|
|
541
|
+
const resources = orderByReferences(parseManifest(readFileSync(args.manifestPath, "utf8"), args.manifestPath));
|
|
542
|
+
const endpoint = resolveGcpEndpoint(args);
|
|
543
|
+
const resolve = (mapper, resource) => ({
|
|
544
|
+
base: (endpoint ?? mapper.defaultHost).replace(/\/$/, ""),
|
|
545
|
+
project: args.project ?? (resource ? resolveGcpProject(resource) : ""),
|
|
546
|
+
});
|
|
547
|
+
const applied = [];
|
|
548
|
+
const notAttempted = [];
|
|
549
|
+
for (const r of resources) {
|
|
550
|
+
const mapper = requireKind(r, args.manifestPath) ? MAPPERS[r.kind] : undefined;
|
|
551
|
+
if (!mapper) {
|
|
552
|
+
const kind = r.kind;
|
|
553
|
+
console.log(`skip: no mapper for kind ${kind}`);
|
|
554
|
+
notAttempted.push({ kind, name: r.metadata?.name ?? "?", reason: "unsupported-kind" });
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
const ctx = resolve(mapper, r);
|
|
558
|
+
const result = await applyResource(mapper, r, ctx, http, signal);
|
|
559
|
+
const verb = result.created ? "created" : result.updated ? "updated" : "unchanged";
|
|
560
|
+
console.log(`${verb}: ${result.kind}/${result.name} (${ctx.base})`);
|
|
561
|
+
applied.push(result);
|
|
562
|
+
}
|
|
563
|
+
const prune = args.prune
|
|
564
|
+
? await pruneOrphans(resources, resolve, http, signal)
|
|
565
|
+
: { pruned: [], notPrunable: [] };
|
|
566
|
+
return { applied, pruned: prune.pruned, notAttempted, notPrunable: prune.notPrunable };
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Idempotently delete one resource: `DELETE` its resource URL. A 404 means it is
|
|
570
|
+
* already gone. For async resources, `DELETE` returns a long-running operation
|
|
571
|
+
* that is polled to completion. `http` is injectable for tests.
|
|
572
|
+
*/
|
|
573
|
+
export async function deleteResource(mapper, resource, ctx, http = defaultHttp, signal) {
|
|
574
|
+
const plan = mapper.plan(resource, ctx);
|
|
575
|
+
const name = resource.metadata?.name ?? "?";
|
|
576
|
+
const res = await http("DELETE", plan.getUrl, undefined, signal);
|
|
577
|
+
if (res.status === 404) {
|
|
578
|
+
return { kind: mapper.kind, name, deleted: false };
|
|
579
|
+
}
|
|
580
|
+
if (res.status >= 300) {
|
|
581
|
+
throw new Error(`${mapper.kind} ${name} delete failed (${res.status}): ${res.text}`);
|
|
582
|
+
}
|
|
583
|
+
if (mapper.operation) {
|
|
584
|
+
const pollUrl = mapper.operation.pollUrl(parseJson(res.text), ctx);
|
|
585
|
+
if (pollUrl) {
|
|
586
|
+
await waitForOperation(mapper.operation, pollUrl, http, signal);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return { kind: mapper.kind, name, deleted: true };
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* The inverse of {@link gcpApply} — read a built CNRM manifest and delete the
|
|
593
|
+
* resources it declares (in reverse order, so dependents go before their
|
|
594
|
+
* dependencies). Idempotent: already-absent resources are a no-op. Uses
|
|
595
|
+
* longInfra profile. `http` is injectable for tests.
|
|
596
|
+
*/
|
|
597
|
+
export async function gcpDelete(args, signal, http = defaultHttp) {
|
|
598
|
+
// Delete in reverse dependency order: a referrer goes before the resource it
|
|
599
|
+
// references.
|
|
600
|
+
const resources = orderByReferences(parseManifest(readFileSync(args.manifestPath, "utf8"), args.manifestPath)).reverse();
|
|
601
|
+
const deleted = [];
|
|
602
|
+
const notAttempted = [];
|
|
603
|
+
for (const r of resources) {
|
|
604
|
+
const mapper = requireKind(r, args.manifestPath) ? MAPPERS[r.kind] : undefined;
|
|
605
|
+
if (!mapper) {
|
|
606
|
+
const kind = r.kind;
|
|
607
|
+
console.log(`skip: no mapper for kind ${kind}`);
|
|
608
|
+
notAttempted.push({ kind, name: r.metadata?.name ?? "?", reason: "unsupported-kind" });
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
const base = (resolveGcpEndpoint(args) ?? mapper.defaultHost).replace(/\/$/, "");
|
|
612
|
+
const project = args.project ?? resolveGcpProject(r);
|
|
613
|
+
const result = await deleteResource(mapper, r, { base, project }, http, signal);
|
|
614
|
+
console.log(`${result.deleted ? "deleted" : "absent"}: ${result.kind}/${result.name} (${base})`);
|
|
615
|
+
deleted.push(result);
|
|
616
|
+
}
|
|
617
|
+
return { deleted, notAttempted };
|
|
618
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GCP Op activities — resolved by the core activity registry when a project's
|
|
3
|
+
* `chant.config.ts` lists the `gcp` lexicon. Contributes the native GCP applier
|
|
4
|
+
* (`gcpApply`), which maps CNRM resources to GCP REST calls since GCP has no
|
|
5
|
+
* native deployment service to shell out to.
|
|
6
|
+
*/
|
|
7
|
+
export { gcpApply, gcpDelete, applyResource, deleteResource, waitForOperation, longRunningOperation, bucketInsertBody, pubSubTopicBody, pubSubSubscriptionBody, cloudRunServiceBody, secretBody, serviceAccountBody, storageBucketMapper, pubSubTopicMapper, pubSubSubscriptionMapper, cloudRunServiceMapper, secretManagerSecretMapper, gcpServiceAccountMapper, MAPPERS, referencedNames, orderByReferences, pruneOrphans, toApplyResult, chantOwnershipLabels, isChantOwned, resolveGcpEndpoint, resolveGcpProject, parseManifest, } from "./gcp-apply.js";
|
|
8
|
+
// floci-gcp (GCP emulator) lifecycle — the typed twin of aws's flociUp/Down, so
|
|
9
|
+
// the trio's GCP op boots/tears down the emulator as a modeled step, not a shell.
|
|
10
|
+
export { flociGcpUp, flociGcpDown, flociGcpRunCommand, flociGcpRmCommand, flociGcpExistsCommand, flociGcpHealthUrl, flociGcpEndpoint, } from "./floci-gcp.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed step-builder wrappers for this lexicon's activities (chant #1288
|
|
3
|
+
* Stage 2). See `lexicons/k8s/src/op/builders.ts`'s module doc for why these
|
|
4
|
+
* live beside their `*Args` interfaces rather than in core: core cannot
|
|
5
|
+
* import a lexicon's types, so a wrapper whose `opts` IS the activity's own
|
|
6
|
+
* `*Args` interface can only sit in the lexicon that declares that
|
|
7
|
+
* interface. `opts`'s type in each wrapper below IS the activity's own
|
|
8
|
+
* `*Args` interface (via `Omit`/`WithStepRefs`) — never restated. `core`'s own
|
|
9
|
+
* `gcpApply`/`gcpDelete`/`flociGcpUp`/`flociGcpDown` are unchanged and
|
|
10
|
+
* produce byte-identical `ActivityStep` output; these are purely additive.
|
|
11
|
+
*/
|
|
12
|
+
import { activity, takeProfileAndId, } from "@intentius/chant/op";
|
|
13
|
+
/**
|
|
14
|
+
* Apply built GCP (CNRM) resources directly to their GCP REST APIs — the
|
|
15
|
+
* fully typed twin of core's `gcpApply`. `opts` is {@link GcpApplyArgs}
|
|
16
|
+
* itself, minus the positional `manifestPath`. Defaults to the `longInfra`
|
|
17
|
+
* profile.
|
|
18
|
+
*/
|
|
19
|
+
export const gcpApply = (manifestPath, opts) => {
|
|
20
|
+
const { args, profile, id } = takeProfileAndId(opts);
|
|
21
|
+
return activity("gcpApply", { manifestPath, ...args }, { profile: profile ?? "longInfra", ...(id ? { id } : {}) });
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Delete the GCP (CNRM) resources in a built manifest — the inverse of
|
|
25
|
+
* {@link gcpApply}, fully typed twin of core's `gcpDelete`. `opts` is
|
|
26
|
+
* {@link GcpApplyArgs} itself (the activity reuses it), minus the positional
|
|
27
|
+
* `manifestPath`. Defaults to the `longInfra` profile.
|
|
28
|
+
*/
|
|
29
|
+
export const gcpDelete = (manifestPath, opts) => {
|
|
30
|
+
const { args, profile, id } = takeProfileAndId(opts);
|
|
31
|
+
return activity("gcpDelete", { manifestPath, ...args }, { profile: profile ?? "longInfra", ...(id ? { id } : {}) });
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Boot a local floci-gcp (GCP emulator) — the fully typed twin of core's
|
|
35
|
+
* `flociGcpUp`. `opts` is {@link FlociGcpUpArgs} itself. Defaults to the
|
|
36
|
+
* `longInfra` profile.
|
|
37
|
+
*/
|
|
38
|
+
export const flociGcpUp = (opts) => {
|
|
39
|
+
const { args, profile, id } = takeProfileAndId(opts);
|
|
40
|
+
return activity("flociGcpUp", args, { profile: profile ?? "longInfra", ...(id ? { id } : {}) });
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Stop and remove the local floci-gcp container — the fully typed twin of
|
|
44
|
+
* core's `flociGcpDown`. `opts` is {@link FlociGcpDownArgs} itself. Defaults
|
|
45
|
+
* to the `fastIdempotent` profile.
|
|
46
|
+
*/
|
|
47
|
+
export const flociGcpDown = (opts) => {
|
|
48
|
+
const { args, profile, id } = takeProfileAndId(opts);
|
|
49
|
+
return activity("flociGcpDown", args, { profile: profile ?? "fastIdempotent", ...(id ? { id } : {}) });
|
|
50
|
+
};
|