ce7cb702218693d08ea6d83464d2457c9250027c
This commit is contained in:
commit
34c5f8963c
18 changed files with 145336 additions and 0 deletions
137
services/quay-operator/actions/build.fsx
Normal file
137
services/quay-operator/actions/build.fsx
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#load "cachedata.fsx"
|
||||
#load "image.fsx"
|
||||
#load "catalog.fsx"
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open Contract
|
||||
open Projects
|
||||
open Image
|
||||
open Cachedata
|
||||
|
||||
let revision = Environment.GetEnvironmentVariable "SOURCE_REVISION"
|
||||
let targets = Environment.GetEnvironmentVariable "TARGETS" |> decode<Target array>
|
||||
let project = selectProject targets
|
||||
require (validRevision revision) "invalid source revision"
|
||||
let sourceRoot = "/source/repository"
|
||||
validateProject sourceRoot project
|
||||
restoreCache "/cache" "/output/go-cache"
|
||||
let work = "/workspace"
|
||||
|
||||
Directory.EnumerateDirectories("/toolchain/source", "*", SearchOption.AllDirectories)
|
||||
|> Seq.iter (fun path ->
|
||||
directory (Path.Combine(work, Path.GetRelativePath("/toolchain/source", path)))
|
||||
|> ignore)
|
||||
|
||||
Directory.EnumerateFiles("/toolchain/source", "*", SearchOption.AllDirectories)
|
||||
|> Seq.iter (fun path -> File.Copy(path, Path.Combine(work, Path.GetRelativePath("/toolchain/source", path))))
|
||||
|
||||
patches
|
||||
|> List.iter (fun name ->
|
||||
requireSuccess
|
||||
"/toolchain/usr/bin/patch"
|
||||
[ "--batch"
|
||||
"--fuzz=0"
|
||||
"--forward"
|
||||
"--strip=1"
|
||||
"--input=" + Path.Combine(sourceRoot, "packages/quay-operator", name) ]
|
||||
(Some work)
|
||||
[]
|
||||
|> ignore)
|
||||
|
||||
let go = "/toolchain/usr/lib/go/bin/go"
|
||||
|
||||
let environment arch =
|
||||
[ "CGO_ENABLED", "0"
|
||||
"GOOS", "linux"
|
||||
"GOARCH", arch
|
||||
"GOENV", "off"
|
||||
"GOTOOLCHAIN", "local"
|
||||
"GOROOT", "/toolchain/usr/lib/go"
|
||||
"GOCACHE", "/output/go-cache"
|
||||
"GOPATH", "/tmp/gopath"
|
||||
"GOPROXY", "off"
|
||||
"GOWORK", "off" ]
|
||||
|
||||
let version = requireSuccess go [ "version" ] None (environment "amd64")
|
||||
require (version.StartsWith("go version go1.27.3 ", StringComparison.Ordinal)) "Go version changed"
|
||||
printfn "%s" (version.Trim())
|
||||
|
||||
let tests =
|
||||
run go [ "test"; "-mod=vendor"; "./apis/quay/v1"; "./pkg/..." ] (Some work) (environment "amd64")
|
||||
|
||||
printfn "%s" (tests.Output.Trim())
|
||||
require (tests.Code = 0) ("operator tests failed: " + tests.Error)
|
||||
|
||||
let assets =
|
||||
Directory.EnumerateFiles(Path.Combine(work, "kustomize"), "*", SearchOption.AllDirectories)
|
||||
|> Seq.map (fun path -> "workspace/" + Path.GetRelativePath(work, path), path)
|
||||
|> Seq.toList
|
||||
|
||||
let files arch =
|
||||
let binary = Path.Combine(directory ("/output/bin/" + arch), "manager")
|
||||
// runtime.Caller locates Kustomize assets under the compiled /workspace path.
|
||||
requireSuccess
|
||||
go
|
||||
[ "build"; "-mod=vendor"; "-ldflags=-s -w -buildid="; "-o"; binary; "main.go" ]
|
||||
(Some work)
|
||||
(environment arch)
|
||||
|> ignore
|
||||
|
||||
("workspace/manager", binary) :: assets
|
||||
|
||||
let digest =
|
||||
assemble "/toolchain/image-base" "/output" revision [ "/workspace/manager" ] "/workspace" files
|
||||
|
||||
printfn "build=image project=%s digest=%s" project.Name digest
|
||||
|
||||
let catalogBinary arch =
|
||||
let binary = Path.Combine(directory ("/output/catalog-bin/" + arch), "opm")
|
||||
|
||||
requireSuccess
|
||||
go
|
||||
[ "build"
|
||||
"-mod=readonly"
|
||||
"-tags=json1,containers_image_openpgp"
|
||||
"-trimpath"
|
||||
"-ldflags=-s -w -buildid= -X github.com/operator-framework/operator-registry/cmd/opm/version.opmVersion="
|
||||
+ catalogVersion
|
||||
"-o"
|
||||
binary
|
||||
"./cmd/opm" ]
|
||||
(Some "/toolchain/catalog-source")
|
||||
(environment arch @ [ "GOMODCACHE", "/toolchain/modules" ])
|
||||
|> ignore
|
||||
|
||||
File.SetUnixFileMode(binary, executableMode)
|
||||
arch, binary
|
||||
|
||||
let catalogBinaries = [ catalogBinary "amd64"; catalogBinary "arm64" ] |> Map.ofList
|
||||
|
||||
let catalogProbe arch =
|
||||
let binary =
|
||||
Path.Combine(directory ("/output/catalog-bin/" + arch), "grpc_health_probe")
|
||||
|
||||
requireSuccess
|
||||
go
|
||||
[ "build"
|
||||
"-mod=readonly"
|
||||
"-trimpath"
|
||||
"-ldflags=-s -w -buildid= -X main.versionTag=" + probeVersion
|
||||
"-o"
|
||||
binary
|
||||
"." ]
|
||||
(Some("/toolchain/modules/github.com/grpc-ecosystem/grpc-health-probe@" + probeVersion))
|
||||
(environment arch @ [ "GOMODCACHE", "/toolchain/modules" ])
|
||||
|> ignore
|
||||
|
||||
File.SetUnixFileMode(binary, executableMode)
|
||||
arch, binary
|
||||
|
||||
let catalogProbes = [ catalogProbe "amd64"; catalogProbe "arm64" ] |> Map.ofList
|
||||
|
||||
let catalogDigest =
|
||||
Catalog.build "/toolchain/catalog-base" catalogBinaries catalogProbes sourceRoot "/output" revision digest
|
||||
|
||||
File.WriteAllText("/output/catalog-digest", catalogDigest)
|
||||
printfn "build=image project=quay-catalog digest=%s" catalogDigest
|
||||
156
services/quay-operator/actions/cache.fsx
Normal file
156
services/quay-operator/actions/cache.fsx
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
#r "System.Formats.Tar"
|
||||
#r "/opt/fsi/packages/AWSSDK.Core.dll"
|
||||
#r "/opt/fsi/packages/AWSSDK.S3.dll"
|
||||
#r "/opt/fsi/packages/ZstdSharp.dll"
|
||||
#nowarn "0760"
|
||||
#load "cachedata.fsx"
|
||||
#load "cache-gc.fsx"
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Formats.Tar
|
||||
open System.IO
|
||||
open System.Net
|
||||
open System.Net.Http
|
||||
open System.Net.Security
|
||||
open System.Security.Cryptography
|
||||
open System.Security.Cryptography.X509Certificates
|
||||
open System.Text
|
||||
open System.Text.Json
|
||||
open System.Text.Json.Serialization
|
||||
open System.Threading.Tasks
|
||||
open Amazon.Runtime
|
||||
open Amazon.S3
|
||||
open Amazon.S3.Model
|
||||
open Contract
|
||||
open Projects
|
||||
open Cachedata
|
||||
open ZstdSharp
|
||||
|
||||
let bucket = "project-delivery"
|
||||
|
||||
let credential path = File.ReadAllText(path).Trim()
|
||||
let root = X509CertificateLoader.LoadCertificateFromFile "/cache-ca/ca.crt"
|
||||
|
||||
let validateCertificate (certificate: X509Certificate) (providedChain: X509Chain) (errors: SslPolicyErrors) =
|
||||
not (isNull certificate)
|
||||
&& not (isNull providedChain)
|
||||
&& not (errors.HasFlag SslPolicyErrors.RemoteCertificateNameMismatch)
|
||||
&& (use chain = new X509Chain()
|
||||
chain.ChainPolicy.TrustMode <- X509ChainTrustMode.CustomRootTrust
|
||||
chain.ChainPolicy.CustomTrustStore.Add root |> ignore
|
||||
chain.ChainPolicy.RevocationMode <- X509RevocationMode.NoCheck
|
||||
|
||||
providedChain.ChainElements
|
||||
|> Seq.iter (fun item -> chain.ChainPolicy.ExtraStore.Add item.Certificate |> ignore)
|
||||
|
||||
chain.Build(new X509Certificate2(certificate)))
|
||||
|
||||
type CacheClientFactory() =
|
||||
inherit HttpClientFactory()
|
||||
|
||||
override _.CreateHttpClient(_) =
|
||||
let handler = new HttpClientHandler()
|
||||
|
||||
handler.ServerCertificateCustomValidationCallback <-
|
||||
fun _ certificate chain errors -> validateCertificate certificate chain errors
|
||||
|
||||
new HttpClient(handler, true)
|
||||
|
||||
let configuration = AmazonS3Config()
|
||||
configuration.ServiceURL <- "https://s3.quorate.internal"
|
||||
configuration.AuthenticationRegion <- "us-east-1"
|
||||
configuration.ForcePathStyle <- true
|
||||
configuration.HttpClientFactory <- CacheClientFactory()
|
||||
|
||||
let client =
|
||||
AmazonS3Client(
|
||||
BasicAWSCredentials(credential "/cache-auth/accesskey", credential "/cache-auth/secretkey"),
|
||||
configuration
|
||||
)
|
||||
|
||||
let result (operation: Task<'T>) = operation.GetAwaiter().GetResult()
|
||||
|
||||
let project =
|
||||
Environment.GetEnvironmentVariable "TARGETS"
|
||||
|> decode<Target array>
|
||||
|> selectProject
|
||||
|
||||
let prefix = $"projects/{project.Name}/{project.Workflow}/cache/go/"
|
||||
let manifestKey = prefix + "_latest.json"
|
||||
|
||||
let pull () =
|
||||
try
|
||||
use reply =
|
||||
result (client.GetObjectAsync(GetObjectRequest(BucketName = bucket, Key = manifestKey), cancellationToken))
|
||||
|
||||
use reader = new StreamReader(reply.ResponseStream)
|
||||
let body = reader.ReadToEnd()
|
||||
let manifest = decode<CacheManifest> body
|
||||
|
||||
if compatible manifest then
|
||||
let digest = payloadDigest manifest
|
||||
|
||||
use payload =
|
||||
result (
|
||||
client.GetObjectAsync(
|
||||
GetObjectRequest(BucketName = bucket, Key = prefix + manifest.PayloadKey),
|
||||
cancellationToken
|
||||
)
|
||||
)
|
||||
|
||||
use output = File.Create "/cache/payload.tar.zst"
|
||||
payload.ResponseStream.CopyTo output
|
||||
output.Dispose()
|
||||
require (sha256 "/cache/payload.tar.zst" = digest) "cache payload digest mismatch"
|
||||
File.WriteAllText("/cache/manifest.json", body)
|
||||
printfn "cache=downloaded component=go"
|
||||
else
|
||||
printfn "cache=miss component=go reason=incompatible"
|
||||
with :? AmazonS3Exception as error when error.StatusCode = HttpStatusCode.NotFound ->
|
||||
printfn "cache=miss component=go reason=absent"
|
||||
|
||||
let export () =
|
||||
let archive = "/tmp/cache.tar.zst"
|
||||
use output = File.Create archive
|
||||
use zstd = new CompressionStream(output, 1)
|
||||
use writer = new TarWriter(zstd, TarEntryFormat.Pax, true)
|
||||
|
||||
Directory.EnumerateFiles("/build-cache", "*", SearchOption.AllDirectories)
|
||||
|> Seq.sort
|
||||
|> Seq.iter (fun path -> writer.WriteEntry(path, Path.GetRelativePath("/build-cache", path)))
|
||||
|
||||
writer.Dispose()
|
||||
zstd.Dispose()
|
||||
output.Dispose()
|
||||
|
||||
let manifest =
|
||||
{ SchemaVersion = 1
|
||||
CacheVersion = cacheVersion ()
|
||||
InputHashes = inputHashes ()
|
||||
PayloadKey = $"objects/{sha256 archive}.tar.zst" }
|
||||
|
||||
use payload = File.OpenRead archive
|
||||
|
||||
result (
|
||||
client.PutObjectAsync(
|
||||
PutObjectRequest(BucketName = bucket, Key = prefix + manifest.PayloadKey, InputStream = payload),
|
||||
cancellationToken
|
||||
)
|
||||
)
|
||||
|> ignore
|
||||
|
||||
use body = new MemoryStream(JsonSerializer.SerializeToUtf8Bytes(manifest, json))
|
||||
|
||||
let request =
|
||||
PutObjectRequest(BucketName = bucket, Key = manifestKey, InputStream = body)
|
||||
|
||||
request.ContentType <- "application/json"
|
||||
result (client.PutObjectAsync(request, cancellationToken)) |> ignore
|
||||
CacheGc.prune client bucket manifestKey manifest.PayloadKey cancellationToken
|
||||
printfn "cache=exported component=go"
|
||||
|
||||
match Environment.GetEnvironmentVariable "CACHE_ACTION" with
|
||||
| "pull" -> pull ()
|
||||
| "export" -> export ()
|
||||
| _ -> fail "invalid cache action"
|
||||
119
services/quay-operator/actions/cachedata.fsx
Normal file
119
services/quay-operator/actions/cachedata.fsx
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#r "/opt/fsi/packages/ZstdSharp.dll"
|
||||
#load "projects.fsx"
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Formats.Tar
|
||||
open System.IO
|
||||
open System.Security.Cryptography
|
||||
open System.Text
|
||||
open System.Text.Json.Serialization
|
||||
open Contract
|
||||
open ZstdSharp
|
||||
|
||||
[<CLIMutable>]
|
||||
type CacheManifest =
|
||||
{ [<JsonPropertyName("schemaVersion")>]
|
||||
SchemaVersion: int
|
||||
[<JsonPropertyName("cacheVersion")>]
|
||||
CacheVersion: string
|
||||
[<JsonPropertyName("inputHashes")>]
|
||||
InputHashes: Dictionary<string, string>
|
||||
[<JsonPropertyName("payloadKey")>]
|
||||
PayloadKey: string }
|
||||
|
||||
let cacheInputs =
|
||||
[ "cachedata.fsx", "services/quay-operator/actions/cachedata.fsx"
|
||||
"cache.fsx", "services/quay-operator/actions/cache.fsx"
|
||||
"projects.fsx", "services/quay-operator/actions/projects.fsx"
|
||||
"toolchain.fsx", "services/quay-operator/actions/toolchain.fsx"
|
||||
"build.fsx", "services/quay-operator/actions/build.fsx"
|
||||
"image.fsx", "services/project-delivery/actions/go-oci/image.fsx"
|
||||
"catalog.fsx", "services/quay-operator/actions/catalog.fsx"
|
||||
"contract.fsx", "services/project-delivery/actions/go-oci/contract.fsx"
|
||||
"go-oci.apko.yaml", "services/quay-operator/actions/runtime.apko.yaml"
|
||||
"catalog.apko.yaml", "services/quay-operator/actions/catalog.apko.yaml" ]
|
||||
|
||||
let cacheVersion () =
|
||||
cacheInputs
|
||||
|> List.map (fun (name, _) -> name + "=" + sha256 (Path.Combine("/orchestration", name)))
|
||||
|> String.concat "\n"
|
||||
|> Encoding.UTF8.GetBytes
|
||||
|> SHA256.HashData
|
||||
|> Convert.ToHexString
|
||||
|> _.ToLowerInvariant()
|
||||
|
||||
let inputHashes () =
|
||||
let hashes = Dictionary<string, string>()
|
||||
|
||||
for name, path in cacheInputs do
|
||||
hashes[path] <- sha256 (Path.Combine("/orchestration", name))
|
||||
|
||||
hashes
|
||||
|
||||
let payloadDigest (manifest: CacheManifest) =
|
||||
let key = manifest.PayloadKey
|
||||
|
||||
require
|
||||
(not (isNull key)
|
||||
&& key.StartsWith("objects/", StringComparison.Ordinal)
|
||||
&& key.EndsWith(".tar.zst", StringComparison.Ordinal))
|
||||
"invalid cache payload key"
|
||||
|
||||
let digest = key[8 .. key.Length - 9]
|
||||
require (validSha256 digest && key = $"objects/{digest}.tar.zst") "invalid cache payload digest"
|
||||
digest
|
||||
|
||||
let compatible (manifest: CacheManifest) =
|
||||
let expected = inputHashes ()
|
||||
|
||||
manifest.SchemaVersion = 1
|
||||
&& manifest.CacheVersion = cacheVersion ()
|
||||
&& not (isNull manifest.InputHashes)
|
||||
&& expected.Count = manifest.InputHashes.Count
|
||||
&& expected
|
||||
|> Seq.forall (fun pair -> manifest.InputHashes.TryGetValue pair.Key = (true, pair.Value))
|
||||
|
||||
let restoreCache cacheRoot destination =
|
||||
directory destination |> ignore
|
||||
let manifestPath = Path.Combine(cacheRoot, "manifest.json")
|
||||
|
||||
if File.Exists manifestPath then
|
||||
let manifest = File.ReadAllText manifestPath |> decode<CacheManifest>
|
||||
|
||||
if compatible manifest then
|
||||
let archive = Path.Combine(cacheRoot, "payload.tar.zst")
|
||||
require (sha256 archive = payloadDigest manifest) "cache payload digest mismatch"
|
||||
use input = File.OpenRead archive
|
||||
use zstd = new DecompressionStream(input)
|
||||
use reader = new TarReader(zstd)
|
||||
let mutable entry = reader.GetNextEntry()
|
||||
|
||||
while not (isNull entry) do
|
||||
let parts = entry.Name.TrimEnd('/').Split('/')
|
||||
|
||||
require
|
||||
(parts
|
||||
|> Array.forall (fun part -> part <> "" && part <> "." && part <> ".." && not (part.Contains '\\')))
|
||||
"invalid cache path"
|
||||
|
||||
let target = Path.Combine(destination, entry.Name)
|
||||
|
||||
match entry.EntryType with
|
||||
| TarEntryType.Directory -> directory target |> ignore
|
||||
| TarEntryType.RegularFile
|
||||
| TarEntryType.V7RegularFile ->
|
||||
directory (Path.GetDirectoryName target) |> ignore
|
||||
use output = new FileStream(target, FileMode.CreateNew)
|
||||
|
||||
if entry.Length > 0L then
|
||||
entry.DataStream.CopyTo output
|
||||
| _ -> fail "invalid cache entry type"
|
||||
|
||||
entry <- reader.GetNextEntry()
|
||||
|
||||
printfn "cache=restored component=go"
|
||||
else
|
||||
printfn "cache=miss component=go reason=incompatible"
|
||||
else
|
||||
printfn "cache=miss component=go reason=absent"
|
||||
20
services/quay-operator/actions/catalog.apko.yaml
Normal file
20
services/quay-operator/actions/catalog.apko.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
contents:
|
||||
keyring:
|
||||
- https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
|
||||
repositories:
|
||||
- https://packages.wolfi.dev/os
|
||||
packages:
|
||||
- ca-certificates-bundle=20261020-r0
|
||||
- wolfi-baselayout=20230201-r31
|
||||
accounts:
|
||||
groups:
|
||||
- groupname: application
|
||||
gid: 65532
|
||||
users:
|
||||
- username: application
|
||||
uid: 65532
|
||||
gid: 65532
|
||||
run-as: 65532
|
||||
environment:
|
||||
PATH: /usr/bin:/bin
|
||||
SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
|
||||
80
services/quay-operator/actions/catalog.fsx
Normal file
80
services/quay-operator/actions/catalog.fsx
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
open System
|
||||
open System.IO
|
||||
open System.Runtime.InteropServices
|
||||
open System.Text
|
||||
open System.Text.Json.Nodes
|
||||
open Contract
|
||||
open Image
|
||||
|
||||
let build
|
||||
basePath
|
||||
(binaries: Map<string, string>)
|
||||
(probes: Map<string, string>)
|
||||
sourceRoot
|
||||
output
|
||||
revision
|
||||
operatorDigest
|
||||
=
|
||||
let host =
|
||||
match RuntimeInformation.ProcessArchitecture with
|
||||
| Architecture.X64 -> "amd64"
|
||||
| Architecture.Arm64 -> "arm64"
|
||||
| value -> fail $"unsupported catalog builder architecture {value}"
|
||||
|
||||
let opm = binaries[host]
|
||||
let source = Path.Combine(sourceRoot, "packages/project-quay-catalog")
|
||||
|
||||
let content =
|
||||
requireSuccess opm [ "render"; Path.Combine(source, "bundles/3.18.2"); "--output"; "json" ] None []
|
||||
|
||||
let bundle = JsonNode.Parse content
|
||||
let operatorImage = $"zot.quorate.internal/olm/quay-operator@{operatorDigest}"
|
||||
|
||||
for property in (bundle["properties"]).AsArray() do
|
||||
if (property["type"]).GetValue<string>() = "olm.bundle.object" then
|
||||
let bytes =
|
||||
Convert.FromBase64String((property.["value"].["data"]).GetValue<string>())
|
||||
|
||||
let resource = JsonNode.Parse(Encoding.UTF8.GetString bytes)
|
||||
|
||||
if (resource["kind"]).GetValue<string>() = "ClusterServiceVersion" then
|
||||
resource.["metadata"].["annotations"].["containerImage"] <- operatorImage
|
||||
let deployment = resource.["spec"].["install"].["spec"].["deployments"].[0]
|
||||
deployment.["spec"].["template"].["spec"].["containers"].[0].["image"] <- operatorImage
|
||||
|
||||
for image in (resource.["spec"].["relatedImages"]).AsArray() do
|
||||
image["image"] <- operatorImage
|
||||
|
||||
property.["value"].["data"] <-
|
||||
resource.ToJsonString() |> Encoding.UTF8.GetBytes |> Convert.ToBase64String
|
||||
|
||||
for image in (bundle["relatedImages"]).AsArray() do
|
||||
image["image"] <- operatorImage
|
||||
|
||||
let package =
|
||||
requireSuccess
|
||||
opm
|
||||
[ "alpha"
|
||||
"render-template"
|
||||
"basic"
|
||||
Path.Combine(source, "catalog-template.yaml")
|
||||
"--output"
|
||||
"json" ]
|
||||
None
|
||||
[]
|
||||
|
||||
let config = directory (Path.Combine(output, "catalog-config"))
|
||||
let catalog = Path.Combine(config, "catalog.json")
|
||||
File.WriteAllText(catalog, bundle.ToJsonString() + "\n" + package)
|
||||
requireSuccess opm [ "validate"; config ] None [] |> ignore
|
||||
|
||||
assemble
|
||||
basePath
|
||||
(Path.Combine(output, "catalog"))
|
||||
revision
|
||||
[ "/usr/bin/opm"; "serve"; "/configs" ]
|
||||
"/"
|
||||
(fun architecture ->
|
||||
[ "usr/bin/opm", binaries[architecture]
|
||||
"usr/bin/grpc_health_probe", probes[architecture]
|
||||
"configs/catalog.json", catalog ])
|
||||
4
services/quay-operator/actions/initialize.fsx
Normal file
4
services/quay-operator/actions/initialize.fsx
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#load "go-init.fsx"
|
||||
|
||||
System.IO.Directory.CreateDirectory "/workspace/output/workspace" |> ignore
|
||||
System.IO.Directory.CreateDirectory "/workspace/cache" |> ignore
|
||||
45
services/quay-operator/actions/projects.fsx
Normal file
45
services/quay-operator/actions/projects.fsx
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#load "contract.fsx"
|
||||
|
||||
open System.IO
|
||||
open Contract
|
||||
|
||||
type Project =
|
||||
{ Name: string
|
||||
Workflow: string
|
||||
Repository: string }
|
||||
|
||||
let upstream = "117e757e6abd2729d6ab4cfa93a2af674d47e1e4"
|
||||
let sourceHash = "0d3cd9fbca03f5d4fd797a848eae3fda7c9725a895a897b656b2aee1de4c0fe8"
|
||||
let patches = [ "status.patch" ]
|
||||
|
||||
let project =
|
||||
{ Name = "quay-op"
|
||||
Workflow = "quay-op-build"
|
||||
Repository = "olm/quay-operator" }
|
||||
|
||||
let catalogRepo = "olm/project-quay-catalog"
|
||||
let catalogVersion = "v1.74.0"
|
||||
let catalogRef = "a936068280ee098fb8bcd089a1a9f14de12d0ece"
|
||||
let catalogHash = "834966a48aecd6e6a6489b879c08c849d13418f86c813551140e6c7c866965e1"
|
||||
let probeVersion = "v0.4.61"
|
||||
let probeRef = "5d0402b1a167a1a610e51b458287c4bf12331bc6"
|
||||
|
||||
let sourcePaths =
|
||||
(patches |> List.map (fun name -> "packages/quay-operator/" + name))
|
||||
@ [ "packages/project-quay-catalog/catalog-template.yaml"
|
||||
"packages/project-quay-catalog/bundles/3.18.2/manifests/quay-operator.clusterserviceversion.yaml"
|
||||
"packages/project-quay-catalog/bundles/3.18.2/manifests/quayregistries.crd.yaml"
|
||||
"packages/project-quay-catalog/bundles/3.18.2/metadata/annotations.yaml" ]
|
||||
|
||||
let selectProject (targets: Target array) =
|
||||
require
|
||||
(targets.Length = 2
|
||||
&& (targets |> Array.forall (fun target -> target.Kind = "ZotOCI"))
|
||||
&& (targets |> Array.map _.Repository |> Set.ofArray) = Set.ofList [ project.Repository; catalogRepo ])
|
||||
"invalid operator delivery target"
|
||||
|
||||
project
|
||||
|
||||
let validateProject sourceRoot _ =
|
||||
sourcePaths
|
||||
|> List.iter (fun path -> require (File.Exists(Path.Combine(sourceRoot, path))) $"missing source input: {path}")
|
||||
55
services/quay-operator/actions/publish.fsx
Normal file
55
services/quay-operator/actions/publish.fsx
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#nowarn "0760"
|
||||
|
||||
#r "/opt/fsi/packages/Oci.dll"
|
||||
#load "projects.fsx"
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open System.Text.Json
|
||||
open Contract
|
||||
open Quorate.Oci
|
||||
open Projects
|
||||
|
||||
let revision = Environment.GetEnvironmentVariable "SOURCE_REVISION"
|
||||
let targets = Environment.GetEnvironmentVariable "TARGETS" |> decode<Target array>
|
||||
let project = selectProject targets
|
||||
let layout = "/handoff/layout"
|
||||
let digest = File.ReadAllText("/handoff/image-digest").Trim()
|
||||
let catalogDigest = File.ReadAllText("/handoff/catalog-digest").Trim()
|
||||
|
||||
require (validRevision revision) "invalid source revision"
|
||||
require (validDigest digest) "invalid image digest"
|
||||
require (validDigest catalogDigest) "invalid catalog digest"
|
||||
|
||||
let publish () =
|
||||
let auth = RegistryAuth.Load("/auth/.dockerconfigjson", "zot.quorate.internal")
|
||||
use root = Registry.LoadRoot "/registry-ca/ca.crt"
|
||||
use registry = Registry(Uri("https://zot.quorate.internal"), auth, root)
|
||||
|
||||
[ project.Repository, layout, digest
|
||||
catalogRepo, "/handoff/catalog/layout", catalogDigest ]
|
||||
|> List.map (fun (repository, imageLayout, expectedDigest) ->
|
||||
let published =
|
||||
registry
|
||||
.PushAsync(repository, imageLayout, "delivery", $"delivery-{revision}", cancellationToken)
|
||||
.GetAwaiter()
|
||||
.GetResult()
|
||||
|
||||
require (published = expectedDigest) "published digest mismatch"
|
||||
printfn "publish=%s digest=%s" repository expectedDigest
|
||||
|
||||
{ Kind = "ZotOCI"
|
||||
Repository = repository
|
||||
Reference = $"zot.quorate.internal/{repository}@{expectedDigest}" })
|
||||
|
||||
let published = publish () |> List.toArray
|
||||
directory "/result" |> ignore
|
||||
|
||||
File.WriteAllText(
|
||||
"/result/delivery-result",
|
||||
JsonSerializer.Serialize(
|
||||
{ SourceRevision = revision
|
||||
Targets = published },
|
||||
json
|
||||
)
|
||||
)
|
||||
19
services/quay-operator/actions/runtime.apko.yaml
Normal file
19
services/quay-operator/actions/runtime.apko.yaml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
contents:
|
||||
keyring:
|
||||
- https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
|
||||
repositories:
|
||||
- https://packages.wolfi.dev/os
|
||||
packages:
|
||||
- ca-certificates-bundle=20261020-r0
|
||||
accounts:
|
||||
groups:
|
||||
- groupname: application
|
||||
gid: 65532
|
||||
users:
|
||||
- username: application
|
||||
uid: 65532
|
||||
gid: 65532
|
||||
run-as: 65532
|
||||
environment:
|
||||
PATH: /usr/bin:/bin
|
||||
SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
|
||||
43
services/quay-operator/actions/source.fsx
Normal file
43
services/quay-operator/actions/source.fsx
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#load "sourcefilter.fsx"
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open System.IO.Compression
|
||||
open System.Net.Http
|
||||
open System.Net.Http.Headers
|
||||
open Contract
|
||||
open Sourcefilter
|
||||
|
||||
let repository = Environment.GetEnvironmentVariable "SOURCE_REPOSITORY"
|
||||
let revision = Environment.GetEnvironmentVariable "SOURCE_REVISION"
|
||||
let archive = "/source/tmp/source.tar.gz"
|
||||
let destination = "/source/repository"
|
||||
|
||||
require (repository = "https://forge.quorate.internal/quorate/cluster") "invalid source repository"
|
||||
require (validRevision revision) "invalid source revision"
|
||||
|
||||
let token = File.ReadAllText("/source-auth/token").Trim()
|
||||
|
||||
let download () =
|
||||
use request =
|
||||
new HttpRequestMessage(
|
||||
HttpMethod.Get,
|
||||
$"http://forgejo-http.forgejo.svc.cluster.local.:3000/api/v1/repos/quorate/cluster/archive/{revision}.tar.gz"
|
||||
)
|
||||
|
||||
request.Headers.Authorization <- AuthenticationHeaderValue("token", token)
|
||||
use client = new HttpClient(Timeout = TimeSpan.FromMinutes 10.0)
|
||||
|
||||
use reply =
|
||||
client.Send(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
|
||||
|
||||
require reply.IsSuccessStatusCode $"source download failed: {int reply.StatusCode}"
|
||||
use input = reply.Content.ReadAsStream(cancellationToken)
|
||||
use output = File.Create archive
|
||||
input.CopyTo output
|
||||
|
||||
download ()
|
||||
extractSource archive destination
|
||||
File.Delete archive
|
||||
File.WriteAllText("/source/.ready", revision + "\n")
|
||||
printfn "source=primary revision=%s" revision
|
||||
33
services/quay-operator/actions/sourcefilter.fsx
Normal file
33
services/quay-operator/actions/sourcefilter.fsx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#load "projects.fsx"
|
||||
|
||||
open System.Collections.Generic
|
||||
open System.Formats.Tar
|
||||
open System.IO
|
||||
open System.IO.Compression
|
||||
open Contract
|
||||
open Projects
|
||||
|
||||
let extractSource archive destination =
|
||||
use input = File.OpenRead archive
|
||||
use gzip = new GZipStream(input, CompressionMode.Decompress)
|
||||
use reader = new TarReader(gzip)
|
||||
let found = HashSet<string>()
|
||||
let mutable root = None
|
||||
let mutable entry = reader.GetNextEntry()
|
||||
while not (isNull entry) do
|
||||
if entry.EntryType <> TarEntryType.GlobalExtendedAttributes then
|
||||
let parts = entry.Name.TrimEnd('/').Split('/')
|
||||
require (parts |> Array.forall (fun part -> part <> "" && part <> "." && part <> ".." && not (part.Contains '\\'))) "invalid source path"
|
||||
match root with
|
||||
| None -> root <- Some parts[0]
|
||||
| Some name -> require (name = parts[0]) "multiple source roots"
|
||||
let path = parts |> Array.skip 1 |> String.concat "/"
|
||||
if List.contains path sourcePaths then
|
||||
require (entry.EntryType = TarEntryType.RegularFile || entry.EntryType = TarEntryType.V7RegularFile) "source input is not a regular file"
|
||||
require (found.Add path) "duplicate source input"
|
||||
let target = Path.Combine(destination, path)
|
||||
directory (Path.GetDirectoryName target) |> ignore
|
||||
use output = File.Create target
|
||||
if entry.Length > 0L then entry.DataStream.CopyTo output
|
||||
entry <- reader.GetNextEntry()
|
||||
require (found.Count = sourcePaths.Length) "source inputs are missing"
|
||||
119
services/quay-operator/actions/toolchain.fsx
Normal file
119
services/quay-operator/actions/toolchain.fsx
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#load "projects.fsx"
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open System.Net.Http
|
||||
open Contract
|
||||
open Projects
|
||||
|
||||
do
|
||||
let root = "/toolchain"
|
||||
|
||||
requireSuccess
|
||||
"/sbin/apk"
|
||||
[ "add"
|
||||
"--root"
|
||||
root
|
||||
"--initdb"
|
||||
"--no-scripts"
|
||||
"--keys-dir"
|
||||
"/etc/apk/keys"
|
||||
"--repository"
|
||||
"https://packages.wolfi.dev/os"
|
||||
"go-1.27=1.27.3-r0"
|
||||
"patch=2.8.1-r1"
|
||||
"ca-certificates-bundle=20261020-r0" ]
|
||||
None
|
||||
[]
|
||||
|> ignore
|
||||
|
||||
let archive = "/tmp/operator.tar.gz"
|
||||
use client = new HttpClient(Timeout = TimeSpan.FromMinutes 2.0)
|
||||
|
||||
use response =
|
||||
client.GetAsync($"https://github.com/quay/quay-operator/archive/{upstream}.tar.gz").GetAwaiter().GetResult()
|
||||
|
||||
require response.IsSuccessStatusCode $"operator source HTTP {int response.StatusCode}"
|
||||
use source = response.Content.ReadAsStream()
|
||||
use target = File.Create archive
|
||||
source.CopyTo target
|
||||
target.Dispose()
|
||||
require (sha256 archive = sourceHash) "operator source checksum mismatch"
|
||||
let incoming = directory (Path.Combine(root, "incoming"))
|
||||
extractGzip archive incoming
|
||||
let fetched = Directory.EnumerateDirectories incoming |> Seq.exactlyOne
|
||||
Directory.Move(fetched, Path.Combine(root, "source"))
|
||||
|
||||
let catalogArchive = "/tmp/catalog.tar.gz"
|
||||
|
||||
use catalogReply =
|
||||
client
|
||||
.GetAsync($"https://github.com/operator-framework/operator-registry/archive/{catalogRef}.tar.gz")
|
||||
.GetAwaiter()
|
||||
.GetResult()
|
||||
|
||||
require catalogReply.IsSuccessStatusCode $"catalog source HTTP {int catalogReply.StatusCode}"
|
||||
use catalogInput = catalogReply.Content.ReadAsStream()
|
||||
use catalogOutput = File.Create catalogArchive
|
||||
catalogInput.CopyTo catalogOutput
|
||||
catalogOutput.Dispose()
|
||||
require (sha256 catalogArchive = catalogHash) "catalog source checksum mismatch"
|
||||
let catalogIncoming = directory (Path.Combine(root, "catalog-incoming"))
|
||||
extractGzip catalogArchive catalogIncoming
|
||||
let catalogSource = Path.Combine(root, "catalog-source")
|
||||
Directory.Move(Directory.EnumerateDirectories(catalogIncoming) |> Seq.exactlyOne, catalogSource)
|
||||
|
||||
let environment =
|
||||
[ "GOENV", "off"
|
||||
"GOTOOLCHAIN", "local"
|
||||
"GOWORK", "off"
|
||||
"GOROOT", Path.Combine(root, "usr/lib/go")
|
||||
"GOPATH", "/tmp/gopath"
|
||||
"GOMODCACHE", Path.Combine(root, "modules")
|
||||
"GOPROXY", "https://proxy.golang.org"
|
||||
"GOSUMDB", "sum.golang.org"
|
||||
"GOCACHE", "/tmp/go-cache" ]
|
||||
|
||||
requireSuccess (Path.Combine(root, "usr/lib/go/bin/go")) [ "mod"; "download" ] (Some catalogSource) environment
|
||||
|> ignore
|
||||
|
||||
requireSuccess
|
||||
(Path.Combine(root, "usr/lib/go/bin/go"))
|
||||
[ "mod"; "download"; "github.com/grpc-ecosystem/grpc-health-probe@" + probeRef ]
|
||||
(Some root)
|
||||
environment
|
||||
|> ignore
|
||||
|
||||
let probeSource =
|
||||
Path.Combine(root, "modules/github.com/grpc-ecosystem/grpc-health-probe@" + probeVersion)
|
||||
|
||||
requireSuccess (Path.Combine(root, "usr/lib/go/bin/go")) [ "mod"; "download" ] (Some probeSource) environment
|
||||
|> ignore
|
||||
|
||||
requireSuccess
|
||||
"/usr/bin/apko"
|
||||
[ "build"
|
||||
"--arch"
|
||||
"x86_64,arm64"
|
||||
"--sbom=false"
|
||||
"/orchestration/go-oci.apko.yaml"
|
||||
"quay-op:base"
|
||||
directory (Path.Combine(root, "image-base")) ]
|
||||
None
|
||||
[]
|
||||
|> ignore
|
||||
|
||||
requireSuccess
|
||||
"/usr/bin/apko"
|
||||
[ "build"
|
||||
"--arch"
|
||||
"x86_64,arm64"
|
||||
"--sbom=false"
|
||||
"/orchestration/catalog.apko.yaml"
|
||||
"quay-catalog:base"
|
||||
directory (Path.Combine(root, "catalog-base")) ]
|
||||
None
|
||||
[]
|
||||
|> ignore
|
||||
|
||||
printfn "toolchain=primary upstream=%s" upstream
|
||||
3
services/quay-operator/k8s/kustomizeconfig.yaml
Normal file
3
services/quay-operator/k8s/kustomizeconfig.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
images:
|
||||
- path: spec/templates/container/image
|
||||
kind: WorkflowTemplate
|
||||
90
services/quay-operator/k8s/network-policy.yaml
Normal file
90
services/quay-operator/k8s/network-policy.yaml
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: tools
|
||||
namespace: project-delivery
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
delivery.quorate.dev/stage: quay-op-toolchain
|
||||
egress:
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
k8s:io.kubernetes.pod.namespace: kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- {port: "53", protocol: UDP}
|
||||
- {port: "53", protocol: TCP}
|
||||
rules:
|
||||
dns:
|
||||
- {matchName: packages.wolfi.dev}
|
||||
- {matchName: github.com}
|
||||
- {matchName: codeload.github.com}
|
||||
- {matchName: proxy.golang.org}
|
||||
- {matchName: sum.golang.org}
|
||||
- {matchName: storage.googleapis.com}
|
||||
- toFQDNs:
|
||||
- {matchName: packages.wolfi.dev}
|
||||
- {matchName: github.com}
|
||||
- {matchName: codeload.github.com}
|
||||
- {matchName: proxy.golang.org}
|
||||
- {matchName: sum.golang.org}
|
||||
- {matchName: storage.googleapis.com}
|
||||
toPorts:
|
||||
- ports:
|
||||
- {port: "443", protocol: TCP}
|
||||
---
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: publish
|
||||
namespace: project-delivery
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
delivery.quorate.dev/stage: quay-op-publish
|
||||
egress:
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
k8s:io.kubernetes.pod.namespace: kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- {port: "53", protocol: UDP}
|
||||
- {port: "53", protocol: TCP}
|
||||
rules:
|
||||
dns:
|
||||
- {matchName: zot.quorate.internal}
|
||||
- toCIDR: [172.28.129.182/32]
|
||||
toPorts:
|
||||
- ports:
|
||||
- {port: "443", protocol: TCP}
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
k8s:io.kubernetes.pod.namespace: zot
|
||||
app.kubernetes.io/name: zot
|
||||
app.kubernetes.io/instance: zot
|
||||
toPorts:
|
||||
- ports:
|
||||
- {port: "5000", protocol: TCP}
|
||||
---
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: zot-in
|
||||
namespace: zot
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: zot
|
||||
app.kubernetes.io/instance: zot
|
||||
ingress:
|
||||
- fromEndpoints:
|
||||
- matchLabels:
|
||||
k8s:io.kubernetes.pod.namespace: project-delivery
|
||||
io.cilium.k8s.policy.serviceaccount: project-delivery-executor
|
||||
delivery.quorate.dev/stage: quay-op-publish
|
||||
toPorts:
|
||||
- ports:
|
||||
- {port: "5000", protocol: TCP}
|
||||
21
services/quay-operator/k8s/project.yaml
Normal file
21
services/quay-operator/k8s/project.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: delivery.quorate.dev/v1alpha1
|
||||
kind: ProjectDelivery
|
||||
metadata:
|
||||
name: image
|
||||
namespace: project-delivery
|
||||
spec:
|
||||
source:
|
||||
repository: https://forge.quorate.internal/quorate/cluster
|
||||
continuous:
|
||||
ref: refs/heads/master
|
||||
paths:
|
||||
- packages/quay-operator
|
||||
- packages/project-quay-catalog
|
||||
- services/quay-operator
|
||||
targets:
|
||||
- kind: ZotOCI
|
||||
repository: olm/quay-operator
|
||||
- kind: ZotOCI
|
||||
repository: olm/project-quay-catalog
|
||||
workflowTemplateRef:
|
||||
name: build
|
||||
45
services/quay-operator/k8s/vso.yaml
Normal file
45
services/quay-operator/k8s/vso.yaml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: zot-vso
|
||||
namespace: project-delivery
|
||||
automountServiceAccountToken: false
|
||||
---
|
||||
apiVersion: secrets.hashicorp.com/v1beta1
|
||||
kind: VaultAuth
|
||||
metadata:
|
||||
name: zot
|
||||
namespace: project-delivery
|
||||
spec:
|
||||
method: kubernetes
|
||||
mount: kubernetes
|
||||
kubernetes:
|
||||
role: quay-op-writer
|
||||
serviceAccount: quay-op-zot-vso
|
||||
vaultConnectionRef: vault/vault
|
||||
---
|
||||
apiVersion: secrets.hashicorp.com/v1beta1
|
||||
kind: VaultStaticSecret
|
||||
metadata:
|
||||
name: writer
|
||||
namespace: project-delivery
|
||||
spec:
|
||||
type: kv-v2
|
||||
mount: secret
|
||||
path: zot/quay-op
|
||||
refreshAfter: 1h
|
||||
destination:
|
||||
name: quay-op-writer
|
||||
create: true
|
||||
overwrite: true
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
transformation:
|
||||
excludeRaw: true
|
||||
excludes: [.*]
|
||||
templates:
|
||||
.dockerconfigjson:
|
||||
text: |
|
||||
{{- $user := get .Secrets "username" -}}
|
||||
{{- $password := get .Secrets "password" -}}
|
||||
{"auths":{"zot.quorate.internal":{"username":"{{ $user }}","password":"{{ $password }}","auth":"{{ printf "%s:%s" $user $password | b64enc }}"}}}
|
||||
vaultAuthRef: quay-op-zot
|
||||
80
services/quay-operator/k8s/workflow-patch.yaml
Normal file
80
services/quay-operator/k8s/workflow-patch.yaml
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
- op: replace
|
||||
path: /metadata/labels/app.kubernetes.io~1instance
|
||||
value: quay-op
|
||||
- op: replace
|
||||
path: /spec/podMetadata/labels/delivery.quorate.dev~1project
|
||||
value: quay-op
|
||||
- op: replace
|
||||
path: /spec/templates/5/metadata/labels/delivery.quorate.dev~1stage
|
||||
value: quay-op-toolchain
|
||||
- op: replace
|
||||
path: /spec/templates/7/metadata/labels/delivery.quorate.dev~1stage
|
||||
value: quay-op-publish
|
||||
- op: replace
|
||||
path: /spec/templates/1/volumes/0
|
||||
value: &orchestration
|
||||
name: orchestration
|
||||
projected:
|
||||
defaultMode: 0444
|
||||
sources:
|
||||
- configMap:
|
||||
name: go-oci-orch
|
||||
items:
|
||||
- {key: contract.fsx, path: contract.fsx}
|
||||
- {key: initialize.fsx, path: go-init.fsx}
|
||||
- {key: image.fsx, path: image.fsx}
|
||||
- configMap:
|
||||
name: quay-op-project
|
||||
- op: replace
|
||||
path: /spec/templates/3/volumes/0
|
||||
value: *orchestration
|
||||
- op: replace
|
||||
path: /spec/templates/4/volumes/0
|
||||
value: *orchestration
|
||||
- op: replace
|
||||
path: /spec/templates/5/volumes/0
|
||||
value: *orchestration
|
||||
- op: replace
|
||||
path: /spec/templates/6/volumes/0
|
||||
value: *orchestration
|
||||
- op: replace
|
||||
path: /spec/templates/7/volumes/0
|
||||
value: *orchestration
|
||||
- op: replace
|
||||
path: /spec/templates/7/volumes/1/secret/secretName
|
||||
value: quay-op-writer
|
||||
- op: replace
|
||||
path: /spec/templates/8/volumes/0
|
||||
value: *orchestration
|
||||
- op: add
|
||||
path: /spec/templates/6/container/volumeMounts/-
|
||||
value:
|
||||
name: workflow-workspace
|
||||
mountPath: /workspace
|
||||
subPath: output/workspace
|
||||
- op: replace
|
||||
path: /spec/templates/4/container/volumeMounts
|
||||
value:
|
||||
- {name: orchestration, mountPath: /orchestration, readOnly: true}
|
||||
- {name: cache-auth, mountPath: /cache-auth, readOnly: true}
|
||||
- {name: cache-ca, mountPath: /cache-ca, readOnly: true}
|
||||
- {name: workflow-workspace, mountPath: /cache, subPath: cache}
|
||||
- {name: workflow-workspace, mountPath: /tmp, subPath: state/cache-tmp}
|
||||
- op: replace
|
||||
path: /spec/templates/5/container/volumeMounts
|
||||
value:
|
||||
- {name: orchestration, mountPath: /orchestration, readOnly: true}
|
||||
- {name: workflow-workspace, mountPath: /toolchain, subPath: toolchain}
|
||||
- {name: workflow-workspace, mountPath: /tmp, subPath: state/toolchain-tmp}
|
||||
- op: add
|
||||
path: /spec/templates/6/container/volumeMounts/5/readOnly
|
||||
value: true
|
||||
- op: replace
|
||||
path: /spec/templates/8/container/volumeMounts
|
||||
value:
|
||||
- {name: orchestration, mountPath: /orchestration, readOnly: true}
|
||||
- {name: cache-auth, mountPath: /cache-auth, readOnly: true}
|
||||
- {name: cache-ca, mountPath: /cache-ca, readOnly: true}
|
||||
- {name: workflow-workspace, mountPath: /source, subPath: source, readOnly: true}
|
||||
- {name: workflow-workspace, mountPath: /build-cache, subPath: output/go-cache, readOnly: true}
|
||||
- {name: workflow-workspace, mountPath: /tmp, subPath: output/cache-tmp}
|
||||
57
services/quay-operator/kustomization.yaml
Normal file
57
services/quay-operator/kustomization.yaml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namePrefix: quay-op-
|
||||
configurations:
|
||||
- k8s/kustomizeconfig.yaml
|
||||
images:
|
||||
- name: registry.quorate.internal/quorate/fsharp-runner
|
||||
digest: sha256:d7b904f4f0cae9fdba7c7345cdf08c91162245834a8a13658d93396272aeec83
|
||||
resources:
|
||||
- ../project-delivery/k8s/workflows/go-oci/parallel
|
||||
- k8s/network-policy.yaml
|
||||
- k8s/project.yaml
|
||||
- k8s/vso.yaml
|
||||
configMapGenerator:
|
||||
- name: project
|
||||
namespace: project-delivery
|
||||
files:
|
||||
- build.fsx=actions/build.fsx
|
||||
- catalog.fsx=actions/catalog.fsx
|
||||
- catalog.apko.yaml=actions/catalog.apko.yaml
|
||||
- cache.fsx=actions/cache.fsx
|
||||
- cache-gc.fsx=../project-delivery/actions/cache-gc.fsx
|
||||
- cachedata.fsx=actions/cachedata.fsx
|
||||
- source.fsx=actions/source.fsx
|
||||
- sourcefilter.fsx=actions/sourcefilter.fsx
|
||||
- initialize.fsx=actions/initialize.fsx
|
||||
- projects.fsx=actions/projects.fsx
|
||||
- publish.fsx=actions/publish.fsx
|
||||
- toolchain.fsx=actions/toolchain.fsx
|
||||
- go-oci.apko.yaml=actions/runtime.apko.yaml
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: true
|
||||
labels:
|
||||
app.kubernetes.io/name: project-delivery
|
||||
app.kubernetes.io/instance: quay-op
|
||||
patches:
|
||||
- path: k8s/workflow-patch.yaml
|
||||
target:
|
||||
group: argoproj.io
|
||||
version: v1alpha1
|
||||
kind: WorkflowTemplate
|
||||
name: build
|
||||
replacements:
|
||||
- source:
|
||||
group: argoproj.io
|
||||
version: v1alpha1
|
||||
kind: WorkflowTemplate
|
||||
name: quay-op-build
|
||||
fieldPath: metadata.name
|
||||
targets:
|
||||
- select:
|
||||
group: delivery.quorate.dev
|
||||
version: v1alpha1
|
||||
kind: ProjectDelivery
|
||||
name: quay-op-image
|
||||
fieldPaths:
|
||||
- spec.workflowTemplateRef.name
|
||||
Loading…
Reference in a new issue