diff --git a/.gitignore b/.gitignore index 3b505dd..1b206d6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ clientconfig.yml # Configuration for the CSB server. secrets.env zscaler.crt +# Sqlite database for local development. +.csb.db diff --git a/Dockerfile b/Dockerfile index a48eb3c..3535f0a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,9 +18,9 @@ RUN set -e; if [ "$BUILD_ENV" = "production" ] ; then echo "production env"; els cp /app/zscaler.crt $CERT_DIR ; update-ca-certificates ; \ fi -RUN /app/csb pak build brokerpaks/cg-smtp +RUN /app/csb pak build brokerpaks/aws-ses FROM ${base_image} # Copy brokerpaks to final image -COPY --from=build /app/cg-smtp-0.1.0.brokerpak /app/ +COPY --from=build /app/aws-ses-0.1.0.brokerpak /app/ diff --git a/Makefile b/Makefile index 2bc42fc..7eea4d2 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,16 @@ build: - PAK_BUILD_CACHE_PATH=/tmp/pak-build-cache cloud-service-broker pak build brokerpaks/cg-smtp + PAK_BUILD_CACHE_PATH=/tmp/pak-build-cache cloud-service-broker pak build brokerpaks/aws-ses run: build # Load environment variables from secrets.env, scoped to this command only. @bash -c 'env $$(cat secrets.env | xargs) cloud-service-broker serve' watch: - find . | grep -E '\.env|\.tf' | entr -r make run + find . | grep -E '\.env|\.tf|\.yml' | entr -r make run + +clean: + rm -r /tmp/pak-build-cache + rm *.brokerpak + +run-docproxy: + find docproxy | entr -r go run ./docproxy/. diff --git a/README.md b/README.md index 25d9e25..31cab4c 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,7 @@ This repo contains configuration, including brokerpaks, for the cloud.gov deploy - https://github.com/GSA-TTS/datagov-brokerpak-smtp - https://github.com/GSA/ttsnotify-brokerpak-sms + +## Credits + +- AWS Architecture icons are sourced from https://aws.amazon.com/architecture/icons/. diff --git a/brokerpaks/cg-smtp/cg-smtp.yml b/brokerpaks/aws-ses/aws-ses.yml similarity index 79% rename from brokerpaks/cg-smtp/cg-smtp.yml rename to brokerpaks/aws-ses/aws-ses.yml index e1bfb85..0115cd8 100644 --- a/brokerpaks/cg-smtp/cg-smtp.yml +++ b/brokerpaks/aws-ses/aws-ses.yml @@ -1,43 +1,42 @@ version: 1 -name: cg-smtp +name: aws-ses id: 260f2ead-b9e9-48b5-9a01-6e3097208ad7 -description: SMTP service provided by Amazon Simple Email Service (SES) -display_name: SMTP (using AWS SES) -image_url: https://example.com/icon.jpg +description: Send email from verified domains using Amazon Simple Email Service (SES). Supports SMTP and the SES HTTP API. +display_name: AWS Simple Email Service +image_url: https://services.cloud.gov/images/amazon-ses.svg documentation_url: https://aws.amazon.com/ses/ # todo -provider_display_name: "" +provider_display_name: "Cloud.gov" support_url: https://cloud.gov/contact/ -tags: [aws, ses, smtp] +tags: [aws, csb] plans: - name: base id: 35ffb84b-a898-442e-b5f9-0a6a5229827d - description: Provision SMTP credentials for sending email from any user at a domain, like 'agency.gov'. + description: Provision SMTP credentials for sending email from any user at a domain, like `agency.gov`. display_name: Send-only service provision: plan_inputs: user_inputs: - field_name: domain type: string - default: "" - details: Domain from mail will be sent. For example, agency.gov. If left empty, a temporary cloud.gov subdomain will be generated. + required: false + prohibit_update: true + details: Domain from which mail will be sent. For example, `agency.gov`. If left empty, a temporary cloud.gov subdomain will be generated. - field_name: dmarc_report_uri_aggregate type: string required: true - default: "" - details: The mailto URI to which DMARC aggregate reports should be sent. For example, 'mailto:dmarc@example.gov'. Reports are automatically sent to reports@dmarc.cyber.dhs.gov. + details: The mailto URI to which DMARC aggregate reports should be sent. For example, `mailto:dmarc@example.gov`. Reports are automatically sent to `reports@dmarc.cyber.dhs.gov`. If you specify a domain and later update this parameter, remember to update your DNS with the new records in the `required_records` output. - field_name: dmarc_report_uri_failure type: string required: true - default: "" - details: The mailto URI to which DMARC individual message failure reports should be sent. For example, 'mailto:dmarc@example.gov'. + details: The mailto URI to which DMARC individual message failure reports should be sent. For example, `mailto:dmarc@example.gov`. If you specify a domain and later update this parameter, remember to update your DNS with the new records in the `required_records` output. - field_name: enable_feedback_notifications type: boolean details: Flag to toggle creation of SNS topics for feedback notifications. default: false - field_name: mail_from_subdomain type: string - default: "" - details: Subdomain to use as the sending email server. + required: false + details: The custom MAIL FROM domain that you want the verified identity to use. See the [SES v2 API reference](https://docs.aws.amazon.com/ses/latest/APIReference-V2/API_PutEmailIdentityMailFromAttributes.html) for requirements. computed_inputs: - name: aws_access_key_id_govcloud type: string @@ -60,7 +59,7 @@ provision: - name: default_domain overwrite: true type: string - default: ${config("aws.zone")} + default: ${config("cg_smtp.aws.zone")} - name: labels default: ${json.marshal(request.default_labels)} overwrite: true @@ -73,7 +72,7 @@ provision: default: ${request.context} - name: service_offering_name type: string - default: cg-smtp + default: aws-ses - name: service_plan_name type: string default: base @@ -89,10 +88,10 @@ provision: details: If a domain was supplied, you must create these records in that zone in your DNS system. - field_name: dmarc_report_uri_aggregate type: string - details: The mailto URI to which DMARC aggregate reports should be sent. For example, 'mailto:dmarc@example.gov'. Reports are automatically sent to reports@dmarc.cyber.dhs.gov. + details: The mailto URI to which DMARC aggregate reports should be sent. For example, `mailto:dmarc@example.gov`. Reports are automatically sent to `reports@dmarc.cyber.dhs.gov`. - field_name: dmarc_report_uri_failure type: string - details: The mailto URI to which DMARC individual message failure reports should be sent. For example, 'mailto:dmarc@example.gov'. + details: The mailto URI to which DMARC individual message failure reports should be sent. For example, `mailto:dmarc@example.gov`. - field_name: instructions type: string details: Any further steps that you must take before using the service. @@ -101,7 +100,7 @@ provision: details: ARN of the SES Configuration Set associated with the identity. Used to create bindings. - field_name: domain_arn type: string - details: Instance SES domain identity (used when creating bindings) + details: Instance SES domain identity. Used to create bindings. - field_name: bounce_topic_arn type: string details: ARN of the SNS topic receiving bounce feedback notifications. @@ -125,11 +124,10 @@ bind: - field_name: source_ips type: array default: [] - details: IP Ranges that requests to SES must come from. + details: A list of IP ranges in CIDR format. If specified, requests made with this binding must originate from the specified ranges. By default, all requests are allowed. prohibit_update: false - field_name: notification_webhook type: string - default: "" details: HTTPS endpoint to subscribe to feedback notifications. computed_inputs: - name: aws_access_key_id_govcloud @@ -177,7 +175,7 @@ bind: default: ${request.context} - name: service_offering_name type: string - default: cg-smtp + default: aws-ses - name: service_plan_name type: string default: base diff --git a/brokerpaks/cg-smtp/client/.cfignore b/brokerpaks/aws-ses/client/.cfignore similarity index 100% rename from brokerpaks/cg-smtp/client/.cfignore rename to brokerpaks/aws-ses/client/.cfignore diff --git a/brokerpaks/cg-smtp/client/.gitignore b/brokerpaks/aws-ses/client/.gitignore similarity index 100% rename from brokerpaks/cg-smtp/client/.gitignore rename to brokerpaks/aws-ses/client/.gitignore diff --git a/brokerpaks/cg-smtp/client/bin/down.sh b/brokerpaks/aws-ses/client/bin/down.sh similarity index 100% rename from brokerpaks/cg-smtp/client/bin/down.sh rename to brokerpaks/aws-ses/client/bin/down.sh diff --git a/brokerpaks/cg-smtp/client/bin/up.sh b/brokerpaks/aws-ses/client/bin/up.sh similarity index 100% rename from brokerpaks/cg-smtp/client/bin/up.sh rename to brokerpaks/aws-ses/client/bin/up.sh diff --git a/brokerpaks/cg-smtp/client/go.mod b/brokerpaks/aws-ses/client/go.mod similarity index 100% rename from brokerpaks/cg-smtp/client/go.mod rename to brokerpaks/aws-ses/client/go.mod diff --git a/brokerpaks/cg-smtp/client/main.go b/brokerpaks/aws-ses/client/main.go similarity index 99% rename from brokerpaks/cg-smtp/client/main.go rename to brokerpaks/aws-ses/client/main.go index a018144..65eb48b 100644 --- a/brokerpaks/cg-smtp/client/main.go +++ b/brokerpaks/aws-ses/client/main.go @@ -15,7 +15,7 @@ import ( type VCAPServices struct { SMTPService []struct { Credentials Credentials `json:"credentials"` - } `json:"cg-smtp"` + } `json:"aws-ses"` } type Credentials struct { diff --git a/brokerpaks/cg-smtp/client/manifest.yml b/brokerpaks/aws-ses/client/manifest.yml similarity index 100% rename from brokerpaks/cg-smtp/client/manifest.yml rename to brokerpaks/aws-ses/client/manifest.yml diff --git a/brokerpaks/cg-smtp/manifest.yml b/brokerpaks/aws-ses/manifest.yml similarity index 94% rename from brokerpaks/cg-smtp/manifest.yml rename to brokerpaks/aws-ses/manifest.yml index 32093b6..fec0bf9 100644 --- a/brokerpaks/cg-smtp/manifest.yml +++ b/brokerpaks/aws-ses/manifest.yml @@ -1,5 +1,5 @@ packversion: 1 -name: cg-smtp +name: aws-ses version: 0.1.0 metadata: author: cloud.gov team @@ -22,23 +22,23 @@ terraform_binaries: version: 5.53.0 source: https://github.com/terraform-providers/terraform-provider-aws/archive/v5.53.0.zip service_definitions: - - cg-smtp.yml + - aws-ses.yml parameters: [] required_env_variables: - - AWS_ZONE + - AWS_ACCESS_KEY_ID_COMMERCIAL - AWS_ACCESS_KEY_ID_GOVCLOUD - - AWS_SECRET_ACCESS_KEY_GOVCLOUD + - AWS_REGION_COMMERCIAL - AWS_REGION_GOVCLOUD - - AWS_ACCESS_KEY_ID_COMMERCIAL - AWS_SECRET_ACCESS_KEY_COMMERCIAL - - AWS_REGION_COMMERCIAL + - AWS_SECRET_ACCESS_KEY_GOVCLOUD + - CG_SMTP_AWS_ZONE - CLOUD_GOV_ENVIRONMENT env_config_mapping: + AWS_ACCESS_KEY_ID_COMMERCIAL: aws.commercial.access_key_id AWS_ACCESS_KEY_ID_GOVCLOUD: aws.govcloud.access_key_id - AWS_SECRET_ACCESS_KEY_GOVCLOUD: aws.govcloud.secret_access_key + AWS_REGION_COMMERCIAL: aws.commercial.region AWS_REGION_GOVCLOUD: aws.govcloud.region - AWS_ACCESS_KEY_ID_COMMERCIAL: aws.commercial.access_key_id AWS_SECRET_ACCESS_KEY_COMMERCIAL: aws.commercial.secret_access_key - AWS_REGION_COMMERCIAL: aws.commercial.region - AWS_ZONE: aws.zone + AWS_SECRET_ACCESS_KEY_GOVCLOUD: aws.govcloud.secret_access_key + CG_SMTP_AWS_ZONE: cg_smtp.aws.zone CLOUD_GOV_ENVIRONMENT: cloud_gov.environment diff --git a/brokerpaks/cg-smtp/terraform/bind/README.md b/brokerpaks/aws-ses/terraform/bind/README.md similarity index 100% rename from brokerpaks/cg-smtp/terraform/bind/README.md rename to brokerpaks/aws-ses/terraform/bind/README.md diff --git a/brokerpaks/cg-smtp/terraform/bind/main.tf b/brokerpaks/aws-ses/terraform/bind/main.tf similarity index 87% rename from brokerpaks/cg-smtp/terraform/bind/main.tf rename to brokerpaks/aws-ses/terraform/bind/main.tf index 402fe0f..bc2bdd0 100644 --- a/brokerpaks/cg-smtp/terraform/bind/main.tf +++ b/brokerpaks/aws-ses/terraform/bind/main.tf @@ -7,6 +7,10 @@ locals { subscribed_webhook = ((local.subscribe_bounce_notification || local.subscribe_complaint_notification || local.subscribe_delivery_notification) ? var.notification_webhook : null) } +# Trivy: It is best practice to manage access via groups intead of by directly attaching +# policies to users. However, each binding may specify separate source IP constraints +# on sending, so we cannot use a group with a single policy for all users. +#trivy:ignore:AVD-AWS-0143 resource "aws_iam_user" "user" { name = local.user_name path = "/cf/" diff --git a/brokerpaks/cg-smtp/terraform/bind/outputs.tf b/brokerpaks/aws-ses/terraform/bind/outputs.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/bind/outputs.tf rename to brokerpaks/aws-ses/terraform/bind/outputs.tf diff --git a/brokerpaks/cg-smtp/terraform/bind/provider.tf b/brokerpaks/aws-ses/terraform/bind/provider.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/bind/provider.tf rename to brokerpaks/aws-ses/terraform/bind/provider.tf diff --git a/brokerpaks/cg-smtp/terraform/bind/terraform.tfvars-template b/brokerpaks/aws-ses/terraform/bind/terraform.tfvars-template similarity index 100% rename from brokerpaks/cg-smtp/terraform/bind/terraform.tfvars-template rename to brokerpaks/aws-ses/terraform/bind/terraform.tfvars-template diff --git a/brokerpaks/cg-smtp/terraform/bind/variables.tf b/brokerpaks/aws-ses/terraform/bind/variables.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/bind/variables.tf rename to brokerpaks/aws-ses/terraform/bind/variables.tf diff --git a/brokerpaks/cg-smtp/terraform/bind/versions.tf b/brokerpaks/aws-ses/terraform/bind/versions.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/bind/versions.tf rename to brokerpaks/aws-ses/terraform/bind/versions.tf diff --git a/brokerpaks/cg-smtp/terraform/provision/README.md b/brokerpaks/aws-ses/terraform/provision/README.md similarity index 100% rename from brokerpaks/cg-smtp/terraform/provision/README.md rename to brokerpaks/aws-ses/terraform/provision/README.md diff --git a/brokerpaks/cg-smtp/terraform/provision/main.tf b/brokerpaks/aws-ses/terraform/provision/main.tf similarity index 97% rename from brokerpaks/cg-smtp/terraform/provision/main.tf rename to brokerpaks/aws-ses/terraform/provision/main.tf index 0cf94d7..d2db5c8 100644 --- a/brokerpaks/cg-smtp/terraform/provision/main.tf +++ b/brokerpaks/aws-ses/terraform/provision/main.tf @@ -92,7 +92,6 @@ locals { resource "aws_sesv2_email_identity" "identity" { configuration_set_name = aws_sesv2_configuration_set.config.configuration_set_name email_identity = local.domain - # Should match https://github.com/cloud-gov/go-broker-tags/blob/main/tags.go#L10 lifecycle { prevent_destroy = true diff --git a/brokerpaks/cg-smtp/terraform/provision/notification.tf b/brokerpaks/aws-ses/terraform/provision/notification.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/provision/notification.tf rename to brokerpaks/aws-ses/terraform/provision/notification.tf diff --git a/brokerpaks/cg-smtp/terraform/provision/outputs.tf b/brokerpaks/aws-ses/terraform/provision/outputs.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/provision/outputs.tf rename to brokerpaks/aws-ses/terraform/provision/outputs.tf diff --git a/brokerpaks/cg-smtp/terraform/provision/providers.tf b/brokerpaks/aws-ses/terraform/provision/providers.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/provision/providers.tf rename to brokerpaks/aws-ses/terraform/provision/providers.tf diff --git a/brokerpaks/cg-smtp/terraform/provision/terraform.tfvars-template b/brokerpaks/aws-ses/terraform/provision/terraform.tfvars-template similarity index 100% rename from brokerpaks/cg-smtp/terraform/provision/terraform.tfvars-template rename to brokerpaks/aws-ses/terraform/provision/terraform.tfvars-template diff --git a/brokerpaks/cg-smtp/terraform/provision/variables.tf b/brokerpaks/aws-ses/terraform/provision/variables.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/provision/variables.tf rename to brokerpaks/aws-ses/terraform/provision/variables.tf diff --git a/brokerpaks/cg-smtp/terraform/provision/verification.tf b/brokerpaks/aws-ses/terraform/provision/verification.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/provision/verification.tf rename to brokerpaks/aws-ses/terraform/provision/verification.tf diff --git a/brokerpaks/cg-smtp/terraform/provision/versions.tf b/brokerpaks/aws-ses/terraform/provision/versions.tf similarity index 100% rename from brokerpaks/cg-smtp/terraform/provision/versions.tf rename to brokerpaks/aws-ses/terraform/provision/versions.tf diff --git a/docproxy/go.mod b/docproxy/go.mod index 0e53dcc..137f816 100644 --- a/docproxy/go.mod +++ b/docproxy/go.mod @@ -1,4 +1,4 @@ -module github.com/cloud-gov/csb-docproxy +module github.com/cloud-gov/csb/docproxy go 1.23.1 diff --git a/docproxy/images/amazon-ses.svg b/docproxy/images/amazon-ses.svg new file mode 100644 index 0000000..aeb14de --- /dev/null +++ b/docproxy/images/amazon-ses.svg @@ -0,0 +1,10 @@ + + + Icon-Architecture/64/Arch_Amazon-Simple-Email-Service_64 + + + + + + + \ No newline at end of file diff --git a/docproxy/images/cloud-gov-logo.svg b/docproxy/images/cloud-gov-logo.svg new file mode 100644 index 0000000..b2f40f2 --- /dev/null +++ b/docproxy/images/cloud-gov-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docproxy/main.go b/docproxy/main.go index 1b06838..8bd89b0 100644 --- a/docproxy/main.go +++ b/docproxy/main.go @@ -2,9 +2,13 @@ package main import ( "embed" + "fmt" "log/slog" "net/http" + "net/url" "os" + "slices" + "strconv" "strings" "golang.org/x/net/html" @@ -85,6 +89,19 @@ func modifyDocument(n *html.Node) { return false }, + func(n *html.Node) bool { + if n.Type == html.TextNode && n.Parent.Parent.Type == html.ElementNode && n.Parent.Data == "a" { + cls := html.Attribute{ + Key: "class", + Val: "navbar-brand", + } + if i := slices.Index(n.Parent.Attr, cls); i >= 0 { + // Change page title. + n.Data = "Services Reference" + } + } + return false + }, } walk(n, func(n *html.Node) bool { for _, m := range modifications { @@ -106,10 +123,13 @@ var fonts embed.FS //go:embed images/favicon.ico var favicon []byte -// run registers routes and starts the server. It is separate from main so it -// can return errors conventionally and main can handle them all in one place. -func run() error { - slog.SetLogLoggerLevel(slog.LevelInfo) +//go:embed images/cloud-gov-logo.svg +var logo []byte + +//go:embed images/amazon-ses.svg +var amazonSES []byte + +func routes(c config) { http.HandleFunc("/styles.css", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "text/css; charset=utf-8") w.Write(stylesheet) @@ -127,8 +147,16 @@ func run() error { w.Header().Add("Content-Type", "image/vnd.microsoft.icon") w.Write(favicon) }) + http.HandleFunc("/images/cloud-gov-logo.svg", func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "image/svg+xml") + w.Write(logo) + }) + http.HandleFunc("/images/amazon-ses.svg", func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "image/svg+xml") + w.Write(amazonSES) + }) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - resp, err := http.Get("https://csb.dev.us-gov-west-1.aws-us-gov.cloud.gov") + resp, err := http.Get(c.BrokerURL.String()) if err != nil { slog.Error("Getting CSB site", "error", err) w.WriteHeader(http.StatusBadGateway) @@ -148,8 +176,46 @@ func run() error { w.WriteHeader(http.StatusInternalServerError) } }) +} + +type config struct { + Port uint16 + BrokerURL *url.URL +} + +func loadConfig() (config, error) { + c := config{} + + port := os.Getenv("PORT") + p, err := strconv.ParseUint(port, 10, 16) + if err != nil { + return config{}, fmt.Errorf("Invalid PORT: %w", err) + } + c.Port = uint16(p) + + brokerURL := os.Getenv("BROKER_URL") + u, err := url.Parse(brokerURL) + if err != nil { + return config{}, fmt.Errorf("Invalid BROKER_URL: %w", err) + } + c.BrokerURL = u + + return c, nil +} + +// run registers routes and starts the server. It is separate from main so it +// can return errors conventionally and main can handle them all in one place. +func run() error { + slog.SetLogLoggerLevel(slog.LevelInfo) + config, err := loadConfig() + if err != nil { + return err + } + + routes(config) + addr := fmt.Sprintf("localhost:%v", config.Port) slog.Info("Starting server...") - return http.ListenAndServe("localhost:8080", nil) + return http.ListenAndServe(addr, nil) } func main() { diff --git a/docproxy/styles.css b/docproxy/styles.css index be0f7c1..7d3cb82 100644 --- a/docproxy/styles.css +++ b/docproxy/styles.css @@ -17,7 +17,7 @@ body { nav { background-color: #f8f9fa !important; border-bottom: 4px solid #007bff !important; - background-image: url(https://cloud.gov/assets/images/content/cloud-gov-logo.svg); + background-image: url(images/cloud-gov-logo.svg); background-position: right; background-repeat: no-repeat; background-origin: content-box; @@ -43,8 +43,17 @@ pre code { border: revert; } -h1::first-letter { - font-size: 0; +h1 { + /* Align text to center of image */ + padding-top: 8px; +} + +h1 img { + height: 48px; + width: 48px; + margin-right: 0.5em; + /* Compensate for h1 padding */ + margin-top: -8px; } @font-face { diff --git a/docs/diagrams.md b/docs/diagrams.md new file mode 100644 index 0000000..0aac6b0 --- /dev/null +++ b/docs/diagrams.md @@ -0,0 +1,139 @@ +# Diagrams + +## Service Brokers, Before + +The current state of service brokers on Cloud.gov. Open Service Broker API requests are sent to the Cloud Foundry API (CAPI). Service brokers are registered with CAPI to handle requests for particular service offerings. CAPI forwards the request to the registered broker, which communicates with AWS to fulfill the request. (For brevity, not all service brokers and AWS APIs currently in use are depicted.) + +```mermaid +--- +title: "Figure 1: Service Brokers Before Change" +--- + +flowchart LR + u["Cloud.gov Customer"] + + subgraph "AWS" + + subgraph "Cloud.gov" + direction LR + capi["Cloud Foundry API"] + + subgraph "Service Brokers" + awsbroker["AWS Broker"] + s3broker["S3 Broker"] + extbroker["External Domain Broker"] + end + end + + rdsapi["AWS RDS API"] + s3api["AWS S3 API"] + route53api["AWS Route 53 API"] + end + + letsencrypt["Let's Encrypt API"] + + u -->|OSBAPI requests| capi + + capi --> awsbroker + capi --> s3broker + capi --> extbroker + + awsbroker --> rdsapi + s3broker --> s3api + extbroker --> route53api + extbroker --> letsencrypt +``` + +## Service Brokers, After + +This change adds a new broker, the Cloud Service Broker (CSB). The CSB uses OpenTofu, an open-source fork of Terraform, to deploy services. The first new service deployed using the CSB will be AWS Simple Email Service (SES). + +```mermaid +--- +title: "Figure 2: Service Brokers After Change" +--- + +flowchart LR + classDef new fill:#ecffec,stroke:#73d893 + u["Cloud.gov Customer"] + + subgraph "AWS" + + subgraph "Cloud.gov" + direction LR + capi["Cloud Foundry API"] + + subgraph "Service Brokers" + awsbroker["AWS Broker"] + s3broker["S3 Broker"] + csb["Cloud Service Broker"]:::new + extbroker["External Domain Broker"] + end + end + + rdsapi["AWS RDS API"] + s3api["AWS S3 API"] + sesapi["AWS SES API"]:::new + snsapi["AWS SNS API"]:::new + route53api["AWS Route 53 API"] + end + + letsencrypt["Let's Encrypt API"] + + u -->|OSBAPI requests| capi + + capi --> awsbroker + capi --> s3broker + capi --> csb + capi --> extbroker + + awsbroker --> rdsapi + s3broker --> s3api + csb --> sesapi + csb --> snsapi + csb --> route53api + extbroker --> route53api + extbroker --> letsencrypt +``` + +## New HTTP Services + +New HTTP services introduced by the Cloud Service Broker SCR are in green. (For brevity, not all existing Cloud.gov web services are depicted.) + +- The **CSB** fulfills provisioning and binding requests for certain service offerings. +- The **Documentation Proxy** is a server that displays documentation for service offerings maintained by the CSB. The CSB exposes a documentation endpoint, `docs/`. When a user makes a request to this service, the service GETs the `docs/` page and returns it to the user with some visual changes. +- The **Service Updater** regularly updates customer service instances so the instances stay up to date with the latest plans offered by the CSB. It may accept administrative HTTPS requests, but only on an internal domain. + +```mermaid +--- +title: "Figure 3: New HTTP Services" +--- + +flowchart LR + classDef new fill:#ecffec,stroke:#73d893 + u["Cloud.gov Customer"] + + subgraph "AWS" + + subgraph "Cloud.gov" + direction LR + logs["logs.fr.cloud.gov - Cloud.gov Logs"] + etc["(...other services...)"] + capi["api.fr.cloud.gov - Cloud Foundry API"] + docproxy["services.cloud.gov - Cloud Service Broker Documentation Proxy"]:::new + updater["Service updater (internal only)"]:::new + + subgraph "Service Brokers" + csb["csb.app.cloud.gov - Cloud Service Broker"]:::new + end + end + end + + + u -->|Logs Dashboard| logs + u -->|Other requests| etc + u -->|OSBAPI requests| capi + u -->|Documentation page| docproxy + capi --> csb + docproxy --> csb +``` diff --git a/go.work b/go.work new file mode 100644 index 0000000..c9b8652 --- /dev/null +++ b/go.work @@ -0,0 +1,6 @@ +go 1.23.2 + +use ( + ./docproxy + ./service-updater +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..58afebd --- /dev/null +++ b/go.work.sum @@ -0,0 +1,119 @@ +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/nats-io/nats.go v1.34.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/sagikazarmark/crypt v0.19.0/go.mod h1:c6vimRziqqERhtSe0MhIvzE1w54FrCHtrXb5NH/ja78= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= +go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= +go.etcd.io/etcd/client/v2 v2.305.12/go.mod h1:aQ/yhsxMu+Oht1FOupSr60oBvcS9cKXHrzBpDsPTf9E= +go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/service-updater/go.mod b/service-updater/go.mod new file mode 100644 index 0000000..ea7d97f --- /dev/null +++ b/service-updater/go.mod @@ -0,0 +1,17 @@ +module github.com/cloud-gov/csb/service-updater + +go 1.23.2 + +require github.com/cloudfoundry/go-cfclient/v3 v3.0.0-alpha.9 + +require ( + github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab // indirect + github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 // indirect + github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.9.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/service-updater/go.sum b/service-updater/go.sum new file mode 100644 index 0000000..f292371 --- /dev/null +++ b/service-updater/go.sum @@ -0,0 +1,29 @@ +github.com/cloudfoundry/go-cfclient/v3 v3.0.0-alpha.9 h1:HK3+nJEPgwlhc5H74aw/V4mVowqWaTKGjHONdVQQ2Vw= +github.com/cloudfoundry/go-cfclient/v3 v3.0.0-alpha.9/go.mod h1:eUjFfpsU3lRv388wKlXMmkQfsJ9pveUHZEia7AoBCPY= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 h1:YFh+sjyJTMQSYjKwM4dFKhJPJC/wfo98tPUc17HdoYw= +github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/service-updater/main.go b/service-updater/main.go new file mode 100644 index 0000000..ad44ae7 --- /dev/null +++ b/service-updater/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "context" + "fmt" + + "github.com/cloudfoundry/go-cfclient/v3/client" + "github.com/cloudfoundry/go-cfclient/v3/config" +) + +func run() error { + // Use CF client to get information about a service instance + // Get services created by the CSB - filter by + // Use client to upgrade a service + // Create timer to upgrade periodically + + // Simple version upgrades all instances every day, just to be safe. + // Less simple version checks to see if they need an upgrade based on plan + // hash or similar. + cfg, err := config.NewFromCFHome() + if err != nil { + return err + } + cf, err := client.New(cfg) + if err != nil { + return err + } + // todo: Filter by tag = csb + instances, _, err := cf.ServiceInstances.List(context.Background(), nil) + if err != nil { + return err + } + // how to update each without doing it all at once? and how to keep track of updates and log if they go wrong? + fmt.Println(instances[0].Name) + return nil +} + +func main() { + err := run() + if err != nil { + panic(err) + } +}