@@ -30,6 +30,9 @@ pub const SSH_MOUNT_PATH_PREFIX: &str = "/stackable/gitssh";
3030pub const GIT_SYNC_SAFE_DIR_OPTION : & str = "safe.directory" ;
3131pub const GIT_SYNC_ROOT_DIR : & str = "/tmp/git" ;
3232pub const GIT_SYNC_LINK : & str = "current" ;
33+ pub const CA_CERT_VOLUME_NAME_PREFIX : & str = "ca-cert" ;
34+ pub const CA_CERT_MOUNT_PATH_PREFIX : & str = "/stackable/gitca" ;
35+ pub const GIT_SSL_CA_INFO_CONFIG_KEY : & str = "http.sslCAInfo" ;
3336
3437#[ derive( Snafu , Debug , EnumDiscriminants ) ]
3538#[ strum_discriminants( derive( IntoStaticStr ) ) ]
@@ -65,6 +68,9 @@ pub struct GitSyncResources {
6568
6669 /// GitSync volumes containing the synchronized repository
6770 pub git_ssh_volumes : Vec < Volume > ,
71+
72+ // GitSync volumes containing Ca certificates
73+ pub git_ca_cert_volumes : Vec < Volume > ,
6874}
6975
7076impl GitSyncResources {
@@ -155,6 +161,21 @@ impl GitSyncResources {
155161 git_sync_container_volume_mounts. push ( ssh_volume_mount) ;
156162 }
157163
164+ if git_sync. ca_cert_secret_name . is_some ( ) {
165+ let ca_cert_secret_mount_path = format ! ( "{CA_CERT_MOUNT_PATH_PREFIX}-{i}" ) ;
166+ let ca_cert_secret_volume_name = format ! ( "{CA_CERT_VOLUME_NAME_PREFIX}-{i}" ) ;
167+
168+ let ca_cert_volume_mount =
169+ VolumeMountBuilder :: new ( ca_cert_secret_volume_name, ca_cert_secret_mount_path)
170+ . build ( ) ;
171+ git_sync_container_volume_mounts. push ( ca_cert_volume_mount) ;
172+ }
173+
174+ let ca_cert_path: Option < String > = git_sync
175+ . ca_cert_secret_name
176+ . as_ref ( )
177+ . map ( |_| format ! ( "{CA_CERT_MOUNT_PATH_PREFIX}-{i}/ca.crt" ) ) ;
178+
158179 let container = Self :: create_git_sync_container (
159180 & format ! ( "{CONTAINER_NAME_PREFIX}-{i}" ) ,
160181 resolved_product_image,
@@ -163,6 +184,7 @@ impl GitSyncResources {
163184 & env_vars,
164185 & git_sync_container_volume_mounts,
165186 container_log_config,
187+ ca_cert_path. as_deref ( ) ,
166188 ) ?;
167189
168190 let init_container = Self :: create_git_sync_container (
@@ -173,6 +195,7 @@ impl GitSyncResources {
173195 & env_vars,
174196 & git_sync_container_volume_mounts,
175197 container_log_config,
198+ ca_cert_path. as_deref ( ) ,
176199 ) ?;
177200
178201 let volume = VolumeBuilder :: new ( volume_name. clone ( ) )
@@ -211,11 +234,20 @@ impl GitSyncResources {
211234 . build ( ) ;
212235 resources. git_ssh_volumes . push ( ssh_secret_volume) ;
213236 }
237+
238+ if let Some ( ca_cert_secret_name) = & git_sync. ca_cert_secret_name {
239+ let ca_cert_secret_volume_name = format ! ( "{CA_CERT_VOLUME_NAME_PREFIX}-{i}" ) ;
240+ let ca_cert_secret_volume = VolumeBuilder :: new ( & ca_cert_secret_volume_name)
241+ . with_secret ( ca_cert_secret_name, false )
242+ . build ( ) ;
243+ resources. git_ca_cert_volumes . push ( ca_cert_secret_volume) ;
244+ }
214245 }
215246
216247 Ok ( resources)
217248 }
218249
250+ #[ allow( clippy:: too_many_arguments) ]
219251 fn create_git_sync_container (
220252 container_name : & str ,
221253 resolved_product_image : & ResolvedProductImage ,
@@ -224,6 +256,7 @@ impl GitSyncResources {
224256 env_vars : & [ EnvVar ] ,
225257 volume_mounts : & [ VolumeMount ] ,
226258 container_log_config : & ContainerLogConfig ,
259+ ca_cert_path : Option < & str > ,
227260 ) -> Result < k8s_openapi:: api:: core:: v1:: Container , Error > {
228261 let container = ContainerBuilder :: new ( container_name)
229262 . context ( InvalidContainerNameSnafu ) ?
@@ -240,6 +273,7 @@ impl GitSyncResources {
240273 git_sync,
241274 one_time,
242275 container_log_config,
276+ ca_cert_path,
243277 ) ] )
244278 . add_env_vars ( env_vars. into ( ) )
245279 . add_volume_mounts ( volume_mounts. to_vec ( ) )
@@ -261,6 +295,7 @@ impl GitSyncResources {
261295 git_sync : & GitSync ,
262296 one_time : bool ,
263297 container_log_config : & ContainerLogConfig ,
298+ ca_cert_path : Option < & str > ,
264299 ) -> String {
265300 let internal_args = BTreeMap :: from ( [
266301 ( "--repo" . to_string ( ) , git_sync. repo . as_str ( ) . to_owned ( ) ) ,
@@ -275,11 +310,15 @@ impl GitSyncResources {
275310 ( "--one-time" . to_string ( ) , one_time. to_string ( ) ) ,
276311 ] ) ;
277312
278- let internal_git_config = BTreeMap :: from ( [ (
313+ let mut internal_git_config = BTreeMap :: from ( [ (
279314 GIT_SYNC_SAFE_DIR_OPTION . to_owned ( ) ,
280315 GIT_SYNC_ROOT_DIR . to_owned ( ) ,
281316 ) ] ) ;
282317
318+ if let Some ( path) = ca_cert_path {
319+ internal_git_config. insert ( GIT_SSL_CA_INFO_CONFIG_KEY . to_owned ( ) , path. to_owned ( ) ) ;
320+ }
321+
283322 let mut git_sync_config = git_sync. git_sync_conf . clone ( ) ;
284323
285324 // The key and value in Git configs are separated by a colon, but both can contain either
@@ -1108,4 +1147,200 @@ secret:
11081147 serde_yaml:: to_string( & git_sync_resources. git_ssh_volumes. first( ) ) . unwrap( )
11091148 ) ;
11101149 }
1150+
1151+ #[ test]
1152+ fn test_git_sync_ca_cert ( ) {
1153+ let git_sync_spec = r#"
1154+ # GitSync using SSH
1155+ - repo: ssh://git@github.com/stackabletech/repo.git
1156+ branch: trunk
1157+ gitFolder: ""
1158+ depth: 3
1159+ wait: 1m
1160+ caCertSecretName: git-ca-cert
1161+ gitSyncConf:
1162+ --rev: HEAD
1163+ "# ;
1164+
1165+ let git_syncs: Vec < GitSync > = yaml_from_str_singleton_map ( git_sync_spec) . unwrap ( ) ;
1166+
1167+ let resolved_product_image = ResolvedProductImage {
1168+ image : "oci.stackable.tech/sdp/product:latest" . to_string ( ) ,
1169+ app_version_label_value : "1.0.0-latest"
1170+ . parse ( )
1171+ . expect ( "static app version label is always valid" ) ,
1172+ product_version : "1.0.0" . to_string ( ) ,
1173+ image_pull_policy : "Always" . to_string ( ) ,
1174+ pull_secrets : None ,
1175+ } ;
1176+
1177+ let extra_env_vars = env_vars_from ( [ ( "VAR1" , "value1" ) ] ) ;
1178+
1179+ let extra_volume_mounts = [ VolumeMount {
1180+ name : "extra-volume" . to_string ( ) ,
1181+ mount_path : "/mnt/extra-volume" . to_string ( ) ,
1182+ ..VolumeMount :: default ( )
1183+ } ] ;
1184+
1185+ let git_sync_resources = GitSyncResources :: new (
1186+ & git_syncs,
1187+ & resolved_product_image,
1188+ & extra_env_vars,
1189+ & extra_volume_mounts,
1190+ "log-volume" ,
1191+ & validate ( default_container_log_config ( ) ) . unwrap ( ) ,
1192+ )
1193+ . unwrap ( ) ;
1194+
1195+ assert ! ( git_sync_resources. is_git_sync_enabled( ) ) ;
1196+
1197+ assert_eq ! ( 1 , git_sync_resources. git_sync_containers. len( ) ) ;
1198+
1199+ assert_eq ! (
1200+ r#"args:
1201+ - |-
1202+ mkdir --parents /stackable/log/git-sync-0 && exec > >(tee /stackable/log/git-sync-0/container.stdout.log) 2> >(tee /stackable/log/git-sync-0/container.stderr.log >&2)
1203+
1204+ prepare_signal_handlers()
1205+ {
1206+ unset term_child_pid
1207+ unset term_kill_needed
1208+ trap 'handle_term_signal' TERM
1209+ }
1210+
1211+ handle_term_signal()
1212+ {
1213+ if [ "${term_child_pid}" ]; then
1214+ kill -TERM "${term_child_pid}" 2>/dev/null
1215+ else
1216+ term_kill_needed="yes"
1217+ fi
1218+ }
1219+
1220+ wait_for_termination()
1221+ {
1222+ set +e
1223+ term_child_pid=$1
1224+ if [[ -v term_kill_needed ]]; then
1225+ kill -TERM "${term_child_pid}" 2>/dev/null
1226+ fi
1227+ wait ${term_child_pid} 2>/dev/null
1228+ trap - TERM
1229+ wait ${term_child_pid} 2>/dev/null
1230+ set -e
1231+ }
1232+
1233+ prepare_signal_handlers
1234+ /stackable/git-sync --depth=3 --git-config='http.sslCAInfo:/stackable/gitca-0/ca.crt,safe.directory:/tmp/git' --link=current --one-time=false --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git &
1235+ wait_for_termination $!
1236+ command:
1237+ - /bin/bash
1238+ - -x
1239+ - -euo
1240+ - pipefail
1241+ - -c
1242+ env:
1243+ - name: VAR1
1244+ value: value1
1245+ image: oci.stackable.tech/sdp/product:latest
1246+ imagePullPolicy: Always
1247+ name: git-sync-0
1248+ resources:
1249+ limits:
1250+ cpu: 200m
1251+ memory: 64Mi
1252+ requests:
1253+ cpu: 100m
1254+ memory: 64Mi
1255+ volumeMounts:
1256+ - mountPath: /tmp/git
1257+ name: content-from-git-0
1258+ - mountPath: /stackable/log
1259+ name: log-volume
1260+ - mountPath: /mnt/extra-volume
1261+ name: extra-volume
1262+ - mountPath: /stackable/gitca-0
1263+ name: ca-cert-0
1264+ "# ,
1265+ serde_yaml:: to_string( & git_sync_resources. git_sync_containers. first( ) ) . unwrap( )
1266+ ) ;
1267+
1268+ assert_eq ! ( 1 , git_sync_resources. git_sync_init_containers. len( ) ) ;
1269+
1270+ assert_eq ! (
1271+ r#"args:
1272+ - |-
1273+ mkdir --parents /stackable/log/git-sync-0-init && exec > >(tee /stackable/log/git-sync-0-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-0-init/container.stderr.log >&2)
1274+ /stackable/git-sync --depth=3 --git-config='http.sslCAInfo:/stackable/gitca-0/ca.crt,safe.directory:/tmp/git' --link=current --one-time=true --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git
1275+ command:
1276+ - /bin/bash
1277+ - -x
1278+ - -euo
1279+ - pipefail
1280+ - -c
1281+ env:
1282+ - name: VAR1
1283+ value: value1
1284+ image: oci.stackable.tech/sdp/product:latest
1285+ imagePullPolicy: Always
1286+ name: git-sync-0-init
1287+ resources:
1288+ limits:
1289+ cpu: 200m
1290+ memory: 64Mi
1291+ requests:
1292+ cpu: 100m
1293+ memory: 64Mi
1294+ volumeMounts:
1295+ - mountPath: /tmp/git
1296+ name: content-from-git-0
1297+ - mountPath: /stackable/log
1298+ name: log-volume
1299+ - mountPath: /mnt/extra-volume
1300+ name: extra-volume
1301+ - mountPath: /stackable/gitca-0
1302+ name: ca-cert-0
1303+ "# ,
1304+ serde_yaml:: to_string( & git_sync_resources. git_sync_init_containers. first( ) ) . unwrap( )
1305+ ) ;
1306+
1307+ assert_eq ! ( 1 , git_sync_resources. git_content_volumes. len( ) ) ;
1308+
1309+ assert_eq ! (
1310+ "emptyDir: {}
1311+ name: content-from-git-0
1312+ " ,
1313+ serde_yaml:: to_string( & git_sync_resources. git_content_volumes. first( ) ) . unwrap( )
1314+ ) ;
1315+
1316+ assert_eq ! ( 1 , git_sync_resources. git_content_volume_mounts. len( ) ) ;
1317+
1318+ assert_eq ! (
1319+ "mountPath: /stackable/app/git-0
1320+ name: content-from-git-0
1321+ " ,
1322+ serde_yaml:: to_string( & git_sync_resources. git_content_volume_mounts. first( ) ) . unwrap( )
1323+ ) ;
1324+
1325+ assert_eq ! ( 1 , git_sync_resources. git_content_folders. len( ) ) ;
1326+
1327+ assert_eq ! (
1328+ "/stackable/app/git-0/current/" ,
1329+ git_sync_resources
1330+ . git_content_folders_as_string( )
1331+ . first( )
1332+ . unwrap( )
1333+ ) ;
1334+
1335+ assert_eq ! ( 1 , git_sync_resources. git_ca_cert_volumes. len( ) ) ;
1336+
1337+ assert_eq ! (
1338+ "name: ca-cert-0
1339+ secret:
1340+ optional: false
1341+ secretName: git-ca-cert
1342+ " ,
1343+ serde_yaml:: to_string( & git_sync_resources. git_ca_cert_volumes. first( ) ) . unwrap( )
1344+ ) ;
1345+ }
11111346}
0 commit comments