Repository navigation
feat: add Scaleway BYOC provider - #2105
simple-agent-manager[bot] wants to merge 51 commits into
Conversation
Add Scaleway as a new cloud provider with skeleton BYOC client: - Add SCALEWAY = 6 to Provider proto enum - Add ProviderScaleway constant, registration, and all switch cases - Add region config with default fr-par and SCW_DEFAULT_REGION env var - Create skeleton ByocScaleway client with stub implementations - Wire up provider factory in connect.go - Add test cases for provider ID and region Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add low-level Scaleway API wrappers in pkg/clouds/scaleway/ following the pattern established by pkg/clouds/aws/ and pkg/clouds/gcp/: - common.go: Base client with HTTP helpers, auth header, region/zone utils - auth.go: Credential validation via IAM API, env var loading - storage.go: S3-compatible object storage using AWS SDK with custom endpoint - secret.go: Secret Manager API (create, version, list, delete) - jobs.go: Serverless Jobs API for CD task execution - registry.go: Container Registry namespace and image management - dns.go: DNS zone management - errors.go: Structured error handling with IsNotFound/IsConflict helpers Includes unit tests for error detection, URL construction, and S3 endpoint generation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement the Scaleway BYOC provider methods using the SDK wrappers from pkg/clouds/scaleway/: - Authenticate: validates credentials via IAM API, creates S3 client - Deploy/Preview: marshal compose to protobuf, upload payload, run CD job - GetProjectUpdate/GetServices/GetService: download state from S3 bucket - PutConfig/ListConfig/DeleteConfig: Scaleway Secret Manager operations - CreateUploadURL: presigned S3-compatible upload URLs - SetUpCD: create bucket, registry namespace, job definition - TearDownCD: basic cleanup with TODO for full implementation - CdCommand: run arbitrary CD commands via Serverless Jobs - CdList: list Pulumi stacks from S3 state bucket - GetDeploymentStatus: check Serverless Job run status QueryLogs, Subscribe, and PrepareDomainDelegation remain as stubs (ErrNotImplemented) as they require Scaleway-specific logging and DNS infrastructure not yet available. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- PrepareDomainDelegation: creates a DNS zone in Scaleway and returns NS records for parent zone delegation - Subscribe: polls Serverless Job run status to stream deployment events with state change detection - QueryLogs: queries Cockpit Loki API for container/job logs with support for both historical queries and follow/tail mode - Add Cockpit SDK wrapper (cockpit.go) for token management and Loki query_range integration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change CD command from `node lib/index.js` to `/app/cd` (Go CD binary) - Add DEFANG_PULUMI_DIR debug support for local CD testing - Add SCALEWAY_DEPLOY_LOG.md tracking deployment progress and fixes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scaleway S3 presigned URLs use HTTPS path-style format (https://s3.fr-par.scw.cloud/bucket/key) but Kaniko expects s3://bucket/key for S3 build contexts. Add convertScalewayS3URL() to perform this conversion, similar to the existing GCS URL conversion. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pass S3_ENDPOINT to CD task environment for Scaleway S3-compatible storage - Fix secret name format: replace path separators with underscores to match Scaleway Secret Manager naming convention - Add early return in debug mode after DebugPulumiCD completes - Update work log with session 4 findings (blockers 6-10) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the eval$IFS$KANIKO_SCRIPT solution for running shell scripts in Scaleway Serverless Jobs, including failed approaches and verification experiments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Session 5 resolved blockers 11-16: - AWS SDK v2 IMDS fallback (AWS_EC2_METADATA_DISABLED=true) - Kaniko chown in sandbox (patched binary ignoring EPERM) - Local storage limit (local_storage_capacity=10GB) - Staging directory permissions (MkdirAll 0644→0755) - apt-get setgroups in sandbox (apt config + user mgmt stubs) - Health check required fields (default threshold/interval) Deployment succeeded! App endpoint live on Scaleway. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add CDImage validation with actionable error message (like Azure) - Normalize Scaleway's 400 "same secret name" error to 409 so PutConfig correctly falls through to update existing secrets - Store raw API error body for detailed error matching Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CD binary reads its command from os.Args, but the Scaleway job was only setting DEFANG_CD_CMD in env vars (which the CD binary ignores). Now pass the command string via the Scaleway start endpoint's command field, which is whitespace-split into an exec array by the API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…r stubs Documents three new blockers fixed: - Blocker 17: USER appuser not in /etc/passwd (functional stubs instead of exit 0) - Blocker 18: addgroup symlink overwrites adduser (os.Remove before WriteFile) - Blocker 19: Kaniko cache reuses old broken layers (deleted cache tags) Full deployment now working: Next.js app + Postgres on Scaleway Serverless Containers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Config → Up → Verify (HTTP 200 + Postgres data) → Down all working. Added known issue about Loki DNS not resolving in devcontainer. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Scaleway provider case to configureAccessGateway in compose fixup: - Default chat model: llama-3.3-70b-instruct - Default embedding model: bge-multilingual-gemma2 - Uses LiteLLM's native scaleway/ prefix (SCW_SECRET_KEY for auth) Add sample chat app (samples/scaleway-llm-chat/) demonstrating the provider: type: model compose pattern with Scaleway Generative APIs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Simplify compose.yaml to single service talking directly to Scaleway Generative APIs (OpenAI-compatible at api.scaleway.ai) - Remove LiteLLM intermediary (host-mode ports unsupported on Scaleway) - Add PULUMI_HOME env var for Scaleway CD jobs (non-root container) - Shorten project name to avoid 16-char resource name limit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
For Scaleway deployments: - Model services use Scaleway Generative APIs directly (no LiteLLM sidecar needed). Dependent services get OPENAI_API_KEY (user-set), endpoint URL, and model name injected. - REDIS_PASSWORD env var is auto-injected for managed Redis services since Scaleway requires authentication. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Image building section now reflects the Kaniko solution. LiteLLM "remaining work" section replaced with the final direct Generative API approach that was validated end-to-end. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These files don't belong in the CLI repo: SCALEWAY_DEPLOY_LOG.md is an internal work log and samples/scaleway-llm-chat/ belongs in the samples repo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…UpCD When CreateJobDefinition returns a conflict error, the code now calls ListJobDefinitions to find the existing job by name and stores its ID, preventing a nil jobDefID from being used in subsequent RunJob calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Scaleway API does exact name matching, but ListSecrets documents prefix semantics. Now falls back to listing all secrets and filtering client-side by prefix when the exact match returns no results. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ication The function shares significant logic with wireDependentServices but the differences (no network wiring, nil OPENAI_API_KEY, dependency removal) are interleaved, making extraction non-trivial. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only call the Scaleway S3 URL conversion when the URL actually contains a Scaleway domain, avoiding unnecessary processing for other providers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ProviderGCP and RegionDefaultGCP constants were reformatted only for alignment with the new Scaleway additions. Revert to original formatting to minimize diff noise. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Scaleway log validation update (2026-05-11) Pushed fixes through c96d540:
Validation performed against validation/scaleway/log-smoke with /tmp/defang-scaleway-pr:
Cleanup:
|
|
Adding concrete log command/output excerpts from the Scaleway validation run. Deployment-time logs from compose up: Post-deploy CD logs command: Runtime logs command after hitting the endpoint: Follow mode live request: Cleanup log excerpt: |
Scaleway Managed Database requires passwords with uppercase, lowercase, digit, and special character. CreateRandomConfigValue now accepts a ProviderID and generates Scaleway-compatible passwords for that provider. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
|
@defangdevs resolve conflicts or rebase |
lionello
left a comment
There was a problem hiding this comment.
What's the binary size impact?
|
Flagging a concrete dependency from the paired Pulumi provider PR (DefangLabs/pulumi-defang#234): the Context: the Scaleway build step is moving off Kaniko-in-a-Serverless-Job (live-tested and confirmed broken under the Job's gVisor sandbox — see the #234 comment thread) onto an ephemeral Compute Instance running Docker/BuildKit via
So the practical difference for I haven't touched code here — wanted to surface the shape of the change before it lands, since |
…niko-in-a-Job Scaleway Serverless Jobs run under gVisor with privilege escalation disabled and all root capabilities dropped. Live-tested: rootless BuildKit fails at daemon boot (needs newuidmap, denied), and Kaniko (stock and the actively-maintained osscontainertools fork) fails unpacking any ordinary base image's rootfs (chown on /etc/shadow is denied) -- reproduces with a bare `FROM alpine:3.19` + `RUN echo`, nothing specific to this provider's Dockerfiles. Neither tool is viable in that sandbox. Replace the Kaniko-in-a-Job Build resource with one that boots a plain Compute Instance -- Scaleway's own official "Docker" Marketplace image, not a Defang-authored one a BYOC customer would have no reason to trust -- driven entirely by a cloud-init boot script: fetch the S3 build context (curl --aws-sigv4, no AWS SDK needed), `docker buildx build --push`, relay output to a dedicated Cockpit logs data source (the project's auto-provisioned one only accepts writes from Scaleway's own managed services, confirmed live), then self-terminate. Every piece of this (API request shapes, the SigV4 content-sha256 quirk on Scaleway's older curl, the Cockpit data-source/token lifecycle, end-to-end build+push+log) was validated against a real Scaleway account, not just read from docs. Includes an opt-in integration test (SCW_LIVE_TEST=1) that re-runs the same validation. BuildState gains LogsEndpoint/LogSelector so a future CLI change (DefangLabs/defang#2105, which currently stubs out Scaleway build logs entirely) has something to read; not wired further than that yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
Adds Scaleway BYOC support and an explicit operational contract with the paired Pulumi provider PR. Provisioning stays in Pulumi. The CLI reads published physical IDs, endpoints, and log selectors from state to report services, monitor deployments, and query logs.
The shared
pkg/deploymentandpkg/clouds/scaleway/contractpackages live in this MIT repository and use only the standard library. The CLI has no compiled dependency onpulumi-defang. Both programs compile in the integration; no runtime plugins are required.Behavior
defangDeploymentoutputs map Compose names to physical resource IDs, endpoints, health-check paths, and runtime log selectors. The CLI queries native container status using those IDs. Managed-service health remains unknown.project.pbreadback; permission, corrupt-state, and unsupported-version errors are preserved. Build-only log requests direct users to Scaleway Cockpit.REDIS_PASSWORDconfig.Current paired validation
CLI
a58b5665b48d827d168288466aeb6d98fe62cb78and provider/CDc5d9985fe616d0d008f6bbb5d82ef0103d686de6passed fresh-stack live validation after both branches merged current main. Both PRs are mergeable. The exact published CD image wasdefangio/cd-sandbox@sha256:6eb5a16e2dbf149816a3e190a97e9e9f40d78ed9148b0002e28fee21c2e36ee1(scw-contract-c5d9985).The rebuilt CLI completed foreground deployment of
scwclimaininfr-par, deployment4pjcifaq22i1. The old checkpoint was confirmed absent before deployment. The app delayed listening for 15 seconds, then returned HTTP 200 on/health/ready. Native API verified startup/liveness thresholds 9/3, interval 5s, timeout 2s, metadata/native endpoint and ID agreement, and the exact CD image. Bare and composite config references resolved correctly; their keys were absent from the native public environment map. Separate CLI processes reported healthy status and retrieved the early startup record.The first main-merge test at
c015a2acexited 2 on Pulumi's temporary version-zero checkpoint while CD continued. Pulumi CLI 3.268.0 reproduced the exact empty checkpoint against a local backend. Fixa58b5665treats only an explicit version-zero checkpoint with a nonempty stack and no snapshot/export as metadata unavailable. Missing/null versions, malformed snapshots, and unsupported versions remain errors. Regression tests cover the literal envelope, rejected boundary cases, and monitoring through bootstrap to native readiness. Metadata version 1, its fields, and encoding are unchanged.The four latest shared files match prerequisite CLI #2302, commit
a841bfeb. Provider/CD retain the published modulev0.0.0-20261023210045-db3ba0c100d9: its wire definitions and encoder match the latest CLI; the new bootstrap reader behavior is only needed by the consumer. No local workspace replacement is required.Full CLI and prerequisite race/short suites and lint pass. CLI protobuf regeneration and workflow checks pass. Provider/integration and CD race suites, provider lint, SDK/schema regeneration, and all provider CI checks, including the combined Docker image build, pass. Latest CLI and prerequisite Go, Nix, and CodeQL checks all pass (runs 40027978577 and 40027981304).
Cleanup verified at
2026-10-23T21:45:30.416019+00:00: zero containers, namespaces, private networks, jobs, secrets, Cockpit tokens, and registry namespaces; the state bucket returned 404. The first teardown hit delayed network detach. Exact test-owned native deletion and a secondcompose downreconciled state and exited 0. CD then logged a nonfatal export error because the stack had been removed.Earlier validation
The earlier dual-project matrix used CLI
1d69cc8c, provider5a3784e, and image digestsha256:04afad4e0843de6cf69c5026a012b1cde697daff998ac2387a96cafa59dbf088:ee077b1bdeployed a top-level model declaration with custom environment names; HTTP checked URL/model and API-key presence without making an inference call.bb3be35and digestsha256:04b24676839b78450a0afe0ce62af1b07a7f5a09d2f7b590a7642023e8dc7f5epassed native startup-probe, endpoint, status, and log checks.All earlier resources were removed. Network detach also required exact test-owned deletion and state reconciliation in those runs. An earlier Scaleway 1.48.0 reconciliation logged a premature plugin exit despite command exit 0; its cause remains unverified.
Limits and earlier evidence
CLI merge
c015a2acretains main's agent confirmation/setup, Compose model behavior, and workflows alongside Scaleway. The latest bootstrap-reader fix is included in the validated CLI above. This live run covers containers and operational discovery; managed PostgreSQL/Redis metadata and secret propagation have Pulumi mock coverage without provisioning databases.The original PR recorded HTTP/inference and
mastra-extendedlive tests on 2026-05-11 usingrg.fr-par.scw.cloud/defang-cd/cd:sam-20260511d. Those tests predate this contract. The original notes also recorded delegated-DNS permission errors and a private-network cleanup issue; native Scaleway domains are used in this validation.Error-classification test follow-up
Test-only commits CLI
0f8c754039335392a1fba088cbfc7d22f481fefcand shared contract095b395689aa39da8ef5184b619fb8065dd9925ftighten expected failures to rejectErrNotFoundfor ambiguous deployments, future metadata versions, and malformed metadata. A malformed-metadata case and a non-string output skip case were added; existing bootstrap cases cover invalid JSON and unsupported state versions. Controlled mutations returningErrNotFoundfor each of the three error paths fail the strengthened assertions. Both full race/short suites and lint pass. All checks pass on both test-only commits. CodeRabbit reviewed shared-contract095b3956with no actionable findings. Production files, dependencies, schema, and CD image are unchanged; the live-validated CLI artifact remainsa58b5665above.Cost-estimation review fix
Commit
42bed432removes Scaleway from the estimate tool's advertised providers, leaving AWS and GCP. The JSON-schema tag separator also keeps the GCP enum value and description separate. The actual generated tool schema was checked for exactly those providers, a required provider field, and the description. The full race/short suite, lint, and Go/Nix/CodeQL CI pass at this commit. Deployment metadata and Scaleway cloud-operation code are unchanged from the live-validated pair.Binary size impact
Measured PR head
42bed432against merged main1d0e734d, using Go 1.26.10, linux/amd64, CGO disabled,-trimpath, and-ldflags='-s -w -X main.version=size-comparison'. VCS stamping is disabled and version strings are identical.Standalone contract #2302 (
095b3956) produces a byte-identical CLI binary to main: zero added bytes in this comparison. The full #2105 increase includes all Scaleway CLI support. Compression measures gzip of the binary alone, without archive packaging. Other targets were not measured. Exact inputs and hashes.Copy check