@@ -6,7 +6,10 @@ def replicate_to_clouds(pipecfg, basearch, buildID, stream) {
66 cosa meta --build=${ buildID} --arch=${ basearch} --dump
77 """ ))
88 def replicators = [:]
9+ def builders = [:]
910 def credentials
11+ pipeutils = load(" utils.groovy" )
12+ def stream_info = pipecfg. streams[stream]
1013
1114 credentials = [file(variable : " ALIYUN_IMAGE_UPLOAD_CONFIG" ,
1215 credentialsId : " aliyun-image-upload-config" )]
@@ -46,10 +49,77 @@ def replicate_to_clouds(pipecfg, basearch, buildID, stream) {
4649 """ )
4750 }
4851 }
52+ // A closure to build the aws-winli AMI. This will be called before replicating to
53+ // all regions, if the option is set for the current stream. `cosa aws-replicate`
54+ // will handle both traditional AMIs and aws-winli AMIs if present in the metadata.
55+ // aws-winli is only supported on x86_64.
56+ def awsWinLIBuildClosure = { config , credentialId ->
57+ def creds = [file(variable : " AWS_CONFIG_FILE" , credentialsId : credentialId)]
58+ withCredentials(creds) {
59+ utils. syncCredentialsIfInRemoteSession([" AWS_CONFIG_FILE" ])
60+ def c = config
61+
62+ // Discover the latest Windows Server AMI to use as the winli-builder instance.
63+ // The AMI rotates frequently with Windows updates and is not persistant in AWS
64+ // for very long, so we need to find the most recent AMI ID.
65+ // Windows Server 2022 was selected here because the Windows Server 2025 AMI does
66+ // not allow legacy bios. WS2022 has an EOL date of 2026-10-13.
67+ // https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2022
68+ // If WS2022 becomes inaccessible in the future and we still need BIOS for our
69+ // winli images then we can just use one of our own previously created winli
70+ // images and pass that to `--windows-ami` below.
71+ def windows_server_ami_name = " "
72+ windows_server_ami_name = " Windows_Server-2022-English-Full-Base-*"
73+ def windows_server_ami = shwrapCapture("""
74+ aws ec2 describe-images \
75+ --region=${ c.primary_region} \
76+ --owners="amazon" \
77+ --filters="Name=name,Values=${ windows_server_ami_name} " \
78+ --query="sort_by(Images, &CreationDate)[-1].ImageId" \
79+ --output text
80+ """ )
81+
82+ // validate that we did actually get an AMI ID returned.
83+ if (! (windows_server_ami_name != / ^ami-[0-9][a-f]{17}$/ )) {
84+ error(" Invalid Windows Server AMI ID: ${ windows_server_ami} " )
85+ }
86+
87+ def extraArgs = []
88+ if (c. grant_users) {
89+ extraArgs + = c. grant_users. collect{" --grant-user=${ it} " }
90+ extraArgs + = c. grant_users. collect{" --grant-user-snapshot=${ it} " }
91+ }
92+ if (c. tags) {
93+ extraArgs + = c. tags. collect { " --tags=${ it} " }
94+ }
95+ if (c. public ) {
96+ extraArgs + = " --public"
97+ }
98+ shwrap("""
99+ cosa ${ image_upload_cmd} -aws \
100+ --upload \
101+ --winli \
102+ --windows-ami=${ windows_server_ami} \
103+ --arch=${ basearch} \
104+ --build=${ buildID} \
105+ --region=${ c.primary_region} \
106+ --credentials-file=\$ {AWS_CONFIG_FILE} \
107+ ${ extraArgs.join(' ')}
108+ """ )
109+ }
110+ }
49111 if (meta. amis) {
50112 credentials = [file(variable : " UNUSED" , credentialsId : " aws-build-upload-config" )]
51113 if (pipecfg. clouds?. aws &&
52114 utils. credentialsExist(credentials)) {
115+
116+ // aws-winli is only supported on x86_64
117+ if ((basearch == " x86_64" ) && (stream_info. create_and_replicate_winli_ami)) {
118+ builders[" ☁️ 🔨:aws-winli" ] = {
119+ awsWinLIBuildClosure. call(pipecfg. clouds. aws,
120+ " aws-build-upload-config" )
121+ }
122+ }
53123 replicators[" ☁️ 🔄:aws" ] = {
54124 awsReplicateClosure. call(pipecfg. clouds. aws,
55125 " aws-build-upload-config" )
@@ -92,6 +162,7 @@ def replicate_to_clouds(pipecfg, basearch, buildID, stream) {
92162 }
93163 }
94164
165+ parallel builders
95166 parallel replicators
96167}
97168// Upload artifacts to clouds
0 commit comments