1616# under the License.
1717#
1818import shutil
19+ import time
1920from openserverless .common .kube_api_client import KubeApiClient
2021import os
2122import uuid
2223import logging
2324from datetime import datetime , timezone , timedelta
2425from types import SimpleNamespace
26+ import random
27+ import string
2528
2629JOB_NAME = "build"
2730CM_NAME = "cm"
@@ -59,11 +62,8 @@ def __init__(self, user_env=None):
5962
6063 # define registry auth
6164 self .registry_auth = self .get_registry_auth ()
65+ self .custom_registry_auth = False
6266 logging .info (f"Using registry auth: { self .registry_auth } " )
63-
64- # define demo mode
65- self .demo_mode = int (os .environ .get ("DEMO_MODE" , 0 )) == 1
66- logging .info (f"Using demo mode: { self .demo_mode } " )
6767
6868 def init (self , build_config : dict ):
6969 """
@@ -85,18 +85,28 @@ def init(self, build_config: dict):
8585 if status is None :
8686 logging .error ("Failed to create nuvolaris-buildkitd-conf ConfigMap" )
8787
88-
88+ def create_registry_secret (self , username : str , password : str , registry : str ):
89+ randompart = '' .join (random .choices (string .ascii_lowercase + string .digits , k = 5 ))
90+ random_name = f"reg-{ self .user } -{ randompart } "
91+ conf = KubeApiClient .build_dockerconfigjson (username = username , password = password ,registry = registry )
92+
93+ data = {".dockerconfigjson" : conf }
94+ secret = self .kube_client .post_secret (secret_name = random_name , secret_data = data , type = "kubernetes.io/dockerconfigjson" )
95+ return secret
96+
8997 def get_registry_host (self ) -> str :
9098 """
9199 Retrieve the registry host
92100 - firstly, check if the user environment has a registry host set
93101 - otherwise retrieve the OpenServerless config map
94102 - if not present use a default value
95- """
96- registry_host = 'nuvolaris-registry-svc:5000'
103+ """
104+ # if customized by the user
97105 if (self .user_env .get ('REGISTRY_HOST' ) is not None ):
98- return self .build_config .get ('REGISTRY_HOST' )
99-
106+ return self .user_env .get ('REGISTRY_HOST' )
107+
108+ # the default
109+ registry_host = 'nuvolaris-registry-svc:5000'
100110 ops_config_map = self .kube_client .get_config_map ('config' )
101111 if ops_config_map is not None :
102112 if 'annotations' in ops_config_map .get ('metadata' , {}):
@@ -108,29 +118,44 @@ def get_registry_host(self) -> str:
108118
109119 def get_registry_auth (self ) -> str :
110120 """
111- Get the name of the registry auth secret. If the user environment has a registry auth set, use it.
112- Otherwise, use the default 'registry-pull-secret'.
121+ Get the name of the registry auth secret. If the user environment has a registry auth set, use it.
113122 """
114123 if (self .user_env .get ('REGISTRY_SECRET' ) is not None ):
115- return self .build_config .get ('REGISTRY_SECRET' )
124+ custom_credentials = self .user_env .get ('REGISTRY_SECRET' )
125+ # if not ':' it means that the user is referencing an already created custom secret
126+ if ":" not in custom_credentials :
127+ return custom_credentials
116128
129+ username , password = custom_credentials .split (":" )
130+ registry_secret = self .create_registry_secret (
131+ username = username , password = password ,
132+ registry = self .registry_host
133+ )
134+ if registry_secret is not None :
135+ self .registry_auth = registry_secret ['metadata' ]['name' ]
136+ # is custom only when is not equal to the default
137+ if self .registry_auth != "registry-pull-secret" :
138+ self .custom_registry_auth = True
117139
118- return 'registry-pull-secret'
140+ return self .user_env .get ('REGISTRY_SECRET' )
141+
142+ return 'registry-pull-secret-int'
119143
120- def create_docker_file (self ) -> str :
144+ def create_docker_file (self , requirements = None ) -> str :
121145 """
122146 Create a Dockerfile in the current directory.
123147 """
124148 source = self .build_config .get ("source" )
125149
126- dockerfile_content = f"FROM { source } \n "
127- if 'file' in self .build_config :
128- requirement_file = self .get_requirements_file_from_kind ()
129- dockerfile_content += f"COPY ./{ requirement_file } /tmp/{ requirement_file } \n "
130- if self .demo_mode :
131- dockerfile_content += "RUN echo \" /bin/extend\" \n "
132- else :
133- dockerfile_content += "RUN \" /bin/extend\" \n "
150+ dockerfile_content = f"FROM { source } \n \n "
151+
152+ if 'file' in self .build_config :
153+ if requirements is not None :
154+ dockerfile_content += f"COPY { requirements } /tmp/{ requirements } \n "
155+ dockerfile_content += "USER root\n "
156+ dockerfile_content += "RUN /bin/extend\n "
157+ dockerfile_content += "USER nobody\n "
158+
134159
135160 return dockerfile_content
136161
@@ -163,30 +188,42 @@ def build(self, image_name: str) -> str:
163188 """
164189 import tempfile
165190 import base64
166-
191+
192+ # define registry host
193+ self .registry_host = self .get_registry_host ()
194+ if self .registry_host is None :
195+ return None
196+ logging .info (f"Using registry host: { self .registry_host } " )
197+
198+ # define registry auth
199+ self .registry_auth = self .get_registry_auth ()
200+
201+ logging .info (f"Using registry auth: { self .registry_auth } " )
202+
167203 # firstly remove old build jobs
168204 self .delete_old_build_jobs ()
169205
170206 tmpdirname = tempfile .mkdtemp ()
171207 logging .info (f"Starting the build to: { tmpdirname } " )
208+ requirements_file = None
172209 if 'file' in self .build_config :
173210 logging .info ("Decoding the requirements file from base64" )
174211 # decode base64 self.build_config.get('file')
175212 try :
176213 requirements = base64 .b64decode (self .build_config .get ('file' )).decode ('utf-8' )
177-
178- requirement_file = self . get_requirements_file_from_kind ()
179- with open (os .path .join (tmpdirname , requirement_file ), 'w' ) as f :
214+ requirements_file = self . get_requirements_file_from_kind ()
215+
216+ with open (os .path .join (tmpdirname ,requirements_file ), 'w' ) as f :
180217 f .write (requirements )
181-
218+
182219 except Exception as e :
183220 logging .error (f"Failed to decode the requirements file: { e } " )
184221 return None
185222
186223 dockerfile_path = os .path .join (tmpdirname , "Dockerfile" )
187224 logging .info (f"Creating Dockerfile at: { dockerfile_path } " )
188225 with open (dockerfile_path , "w" ) as dockerfile :
189- dockerfile .write (self .create_docker_file ())
226+ dockerfile .write (self .create_docker_file (requirements = requirements_file ))
190227
191228 # check if the directory contains a Dockerfile and is not empty.
192229 if not self .check_build_dir (tmpdirname ):
@@ -212,9 +249,15 @@ def build(self, image_name: str) -> str:
212249 logging .error (f"Failed to create job { self .job_name } " )
213250 return None
214251
252+ time .sleep (3 )
215253 if not self .kube_client .delete_config_map (cm_name = self .cm ):
216254 logging .error (f"Failed to delete ConfigMap { self .cm } " )
217255
256+
257+ if self .custom_registry_auth :
258+ if not self .kube_client .delete_secret (secret_name = self .registry_auth ):
259+ logging .error (f"Failed to delete Secret { self .custom_registry_auth } " )
260+
218261 return job
219262
220263 def delete_old_build_jobs (self , max_age_hours : int = 24 ) -> int :
@@ -282,7 +325,10 @@ def check_build_dir(self, unzip_dir: str) -> bool:
282325
283326 def create_build_job (self , image_name : str ) -> dict :
284327 """Create a Kubernetes job manifest for building the Docker image."""
285- registry_image_name = f"{ self .registry_host } /{ image_name } "
328+ if not self .custom_registry_auth :
329+ registry_image_name = f"{ self .registry_host } /{ image_name } "
330+ else :
331+ registry_image_name = f"{ image_name } "
286332
287333 # --- MANIFEST DEL JOB ---
288334 job_manifest = {
@@ -341,7 +387,7 @@ def create_build_job(self, image_name: str) -> dict:
341387 "command" : ["sh" , "-c" ],
342388 "args" : [
343389 "rootlesskit buildkitd --config /config/buildkitd.toml & sleep 3 && "
344- f"buildctl build --frontend=dockerfile.v0 --local context=/workspace --local dockerfile=/workspace --output=type=image,name={ registry_image_name } ,push=true"
390+ f"buildctl build --progress=plain -- frontend=dockerfile.v0 --local context=/workspace --local dockerfile=/workspace --output=type=image,name={ registry_image_name } ,push=true"
345391 ],
346392 "securityContext" : {
347393 "runAsUser" : 1000 ,
0 commit comments