@@ -43,6 +43,7 @@ const (
4343 Master PtpRole = 1
4444 Slave PtpRole = 0
4545)
46+ const PTP_SEC_FOLDER = "/etc/ptp-secret-mount/"
4647
4748// log is for logging in this package.
4849var ptpconfiglog = logf .Log .WithName ("ptpconfig-resource" )
@@ -70,11 +71,6 @@ type Ptp4lConf struct {
7071 sections map [string ]Ptp4lConfSection
7172}
7273
73- // PopulatePtp4lConf parses the ptp4l configuration
74- func (p * Ptp4lConf ) PopulatePtp4lConf (config * string , ptp4lopts * string ) error {
75- return p .populatePtp4lConf (config , ptp4lopts )
76- }
77-
7874// GetOption retrieves an option value from a specific section
7975func (p * Ptp4lConf ) GetOption (section , key string ) string {
8076 if sec , ok := p .sections [section ]; ok {
@@ -85,7 +81,7 @@ func (p *Ptp4lConf) GetOption(section, key string) string {
8581 return ""
8682}
8783
88- func (output * Ptp4lConf ) populatePtp4lConf (config * string , ptp4lopts * string ) error {
84+ func (output * Ptp4lConf ) PopulatePtp4lConf (config * string , ptp4lopts * string ) error {
8985 var string_config string
9086 if config != nil {
9187 string_config = * config
@@ -130,7 +126,7 @@ func (r *PtpConfig) validate() error {
130126
131127 for _ , profile := range profiles {
132128 conf := & Ptp4lConf {}
133- conf .populatePtp4lConf (profile .Ptp4lConf , profile .Ptp4lOpts )
129+ conf .PopulatePtp4lConf (profile .Ptp4lConf , profile .Ptp4lOpts )
134130
135131 // Validate that interface field only set in ordinary clock
136132 if profile .Interface != nil && * profile .Interface != "" {
@@ -216,109 +212,59 @@ func (r *PtpConfig) validate() error {
216212 }
217213 }
218214
219- // Validate secret-related settings for this profile
220- if profile .PtpSecretName != nil && * profile .PtpSecretName != "" {
221- sppValue , err := getSppFromPtp4lConf (conf )
222- if err != nil {
223- return fmt .Errorf ("failed to get spp value from ptp4lConf: %w" , err )
224- }
225- if err := validateSecretExists (sppValue , * profile .PtpSecretName ); err != nil {
226- return fmt .Errorf ("failed to validate secret from profile: %w" , err )
227- }
228- saFilePath , err := getSaFileFromPtp4lConf (conf )
229- if err != nil {
230- return fmt .Errorf ("failed to get sa file path from ptp4lConf: %w" , err )
231- }
232- if err := validateSaFileSecretConflicts (saFilePath , * profile .PtpSecretName , r .Name , r .Namespace ); err != nil {
233- return fmt .Errorf ("failed to validate secret conflicts from profile: %w" , err )
234- }
215+ // validate secret-related settings for this profile
216+ saFilePath , err := getSaFileFromPtp4lConf (conf )
217+ if err != nil {
218+ return fmt .Errorf ("failed to get sa file path from ptp4lConf: %w" , err )
235219 }
236- }
237- return nil
238- }
239-
240- // validateSecretConflicts checks if a single profile's sa_file + secret combination
241- // conflicts with any existing PtpConfigs in the openshift-ptp namespace
242- func validateSaFileSecretConflicts (saFilePath string , secretName string , name string , namespace string ) error {
243- if webhookClient == nil {
244- ptpconfiglog .Info ("webhook client not initialized, skipping cross-PtpConfig validation" )
245- return nil
246- }
247-
248- // List all existing PtpConfigs in openshift-ptp namespace
249- ptpConfigList := & PtpConfigList {}
250- if err := webhookClient .List (context .Background (), ptpConfigList , & client.ListOptions {
251- Namespace : "openshift-ptp" ,
252- }); err != nil {
253- ptpconfiglog .Error (err , "failed to list PtpConfigs for validation" )
254- // Don't block creation if we can't list - fail open
255- return nil
256- }
257-
258- // Check each existing PtpConfig for conflicts
259- for _ , existingConfig := range ptpConfigList .Items {
260- // Skip checking against ourselves (for updates)
261- if existingConfig .Name == name && existingConfig .Namespace == namespace {
262- continue
220+ if err := validateSaFile (saFilePath ); err != nil {
221+ return fmt .Errorf ("failed to validate sa file: %w" , err )
263222 }
264-
265- // Check each profile in the existing config
266- for _ , existingProfile := range existingConfig .Spec .Profile {
267- if existingProfile .PtpSecretName == nil || * existingProfile .PtpSecretName == "" {
268- continue
269- }
270- if existingProfile .Ptp4lConf == nil {
271- continue
272- }
273-
274- existingConf := & Ptp4lConf {}
275- if err := existingConf .populatePtp4lConf (existingProfile .Ptp4lConf , existingProfile .Ptp4lOpts ); err != nil {
276- continue
277- }
278- globalSection , exists := existingConf .sections ["[global]" ]
279- if ! exists {
280- continue
281- }
282- existingSaFile , exists := globalSection .options ["sa_file" ]
283- if ! exists {
284- continue
285- }
286- // Check if same sa_file as our profile and different secret
287- if existingSaFile == saFilePath && * existingProfile .PtpSecretName != secretName {
288- return fmt .Errorf ("sa_file '%s' conflict: PtpConfig '%s' already uses secret '%s' with this sa_file path, but this profile tries to use secret '%s'. All PtpConfigs using the same sa_file must reference the same secret" ,
289- saFilePath , existingConfig .Name , * existingProfile .PtpSecretName , secretName )
290- }
223+ secretName := GetSecretNameFromSaFilePath (saFilePath )
224+ sppValue , err := getSppFromPtp4lConf (conf )
225+ if err != nil {
226+ return fmt .Errorf ("failed to get spp value from ptp4lConf: %w" , err )
227+ }
228+ secretKey := GetSecretKeyFromSaFilePath (saFilePath )
229+ if err := validateSppInSecretKey (sppValue , secretName , secretKey ); err != nil {
230+ return fmt .Errorf ("failed to validate spp in secret key: %w" , err )
291231 }
292- }
293232
233+ }
294234 return nil
295235}
296236
297- // validateSecretExists checks that a single profile's ptpSecretName references an existing secret
298- func validateSecretExists ( sppValue string , secretName string ) error {
237+ // checking if the secret exists in the openshift-ptp namespace
238+ func getSecret ( secretName string ) * corev1. Secret {
299239 if webhookClient == nil {
300240 ptpconfiglog .Info ("webhook client not initialized, skipping secret existence validation" )
301241 return nil
302242 }
303-
304- // Try to get the secret from openshift-ptp namespace
305243 secret := & corev1.Secret {}
306244 err := webhookClient .Get (context .Background (), types.NamespacedName {
307245 Namespace : "openshift-ptp" ,
308246 Name : secretName ,
309247 }, secret )
310-
311248 if err != nil {
312- return fmt . Errorf ( "failed to get secret %q: %w" , secretName , err )
249+ return nil
313250 }
251+ return secret
252+ }
314253
315- // Validate SPP (Security Parameter Profile) if specified
316- if err := validateSppInSecret (sppValue , secret ); err != nil {
317- return fmt .Errorf ("failed to validate spp in secret %q: %w" , secretName , err )
318- }
254+ // GetSecretNameFromSaFilePath extracts the secret name from the sa_file path
255+ func GetSecretNameFromSaFilePath (sa_file string ) string {
256+ path := strings .TrimPrefix (sa_file , PTP_SEC_FOLDER )
257+ index := strings .Index (path , "/" )
258+ return path [:index ]
259+ }
319260
320- return nil
261+ // GetSecretKeyFromSaFilePath extracts the secret key from the sa_file path
262+ func GetSecretKeyFromSaFilePath (sa_file string ) string {
263+ path := strings .TrimPrefix (sa_file , PTP_SEC_FOLDER )
264+ index := strings .Index (path , "/" )
265+ return path [index + 1 :]
321266}
267+
322268func getSppFromPtp4lConf (conf * Ptp4lConf ) (string , error ) {
323269 globalSection , exists := conf .sections ["[global]" ]
324270 if ! exists {
@@ -334,6 +280,7 @@ func getSppFromPtp4lConf(conf *Ptp4lConf) (string, error) {
334280 }
335281 return sppValue , nil
336282}
283+
337284func getSaFileFromPtp4lConf (conf * Ptp4lConf ) (string , error ) {
338285 globalSection , exists := conf .sections ["[global]" ]
339286 if ! exists {
@@ -349,38 +296,74 @@ func getSaFileFromPtp4lConf(conf *Ptp4lConf) (string, error) {
349296 return saFileValue , nil
350297}
351298
352- // validateSppInSecret checks that the spp value in ptp4lConf exists in the referenced secret
353- func validateSppInSecret (sppValue string , secret * corev1.Secret ) error {
354- for key , value := range secret .Data {
355- content := string (value )
356- lines := strings .Split (content , "\n " )
299+ // validateSaFile checks that the sa_file path is valid with prefix PTP_SEC_FOLDER
300+ // next directory must be a valid secret name, e.g. PTP_SEC_FOLDER/secret_name/secret_key
301+ // check that secret_key exists in the secret_name secret
302+ func validateSaFile (saFilePath string ) error {
303+ if ! strings .HasPrefix (saFilePath , PTP_SEC_FOLDER ) {
304+ return fmt .Errorf ("sa_file path '%s' is invalid; must start with '%s'" , saFilePath , PTP_SEC_FOLDER )
305+ }
306+ path := strings .TrimPrefix (saFilePath , PTP_SEC_FOLDER )
307+ index := strings .Index (path , "/" )
308+ if index == - 1 || index == len (path )- 1 {
309+ return fmt .Errorf ("sa_file path '%s' is incomplete; must contain a secret key" , saFilePath )
310+ }
311+ secretName := path [:index ]
312+ if secretName == "" {
313+ return fmt .Errorf ("sa_file path '%s' is invalid; must contain a secret name" , saFilePath )
314+ }
315+ secret := getSecret (secretName )
316+ if secret == nil {
317+ return fmt .Errorf ("sa_file path '%s' has invalid secret name '%s'" , saFilePath , secretName )
318+ }
319+ keyCandidate := path [index + 1 :]
320+ return validateKeyInSecret (secret , keyCandidate )
321+ }
322+
323+ // this function will recieve a secret and a key candidate and check if the key is part of the secret
324+ func validateKeyInSecret (secret * corev1.Secret , keyCandidate string ) error {
325+ if _ , exists := secret .Data [keyCandidate ]; ! exists {
326+ return fmt .Errorf ("key '%s' is not part of the secret" , keyCandidate )
327+ }
328+ return nil
329+ }
330+
331+ // validateSppInSecret checks that the spp value exists in a specific key of the secret
332+ func validateSppInSecretKey (sppValue string , secretName string , secretKey string ) error {
333+ secret := getSecret (secretName )
334+ value , exists := secret .Data [secretKey ]
335+ if ! exists {
336+ return fmt .Errorf ("key '%s' not found in secret '%s'" , secretKey , secret .Name )
337+ }
338+
339+ content := string (value )
340+ lines := strings .Split (content , "\n " )
357341
358- // Look for lines starting with "spp <number>"
359- for _ , line := range lines {
360- line = strings .TrimSpace (line )
342+ // Look for lines starting with "spp <number>"
343+ for _ , line := range lines {
344+ line = strings .TrimSpace (line )
361345
362- // Skip empty lines and comments
363- if line == "" || strings .HasPrefix (line , "#" ) {
364- continue
365- }
346+ // Skip empty lines and comments
347+ if line == "" || strings .HasPrefix (line , "#" ) {
348+ continue
349+ }
366350
367- // Check if line starts with "spp "
368- if strings .HasPrefix (strings .ToLower (line ), "spp " ) {
369- parts := strings .Fields (line )
370- if len (parts ) >= 2 {
371- secretSppValue := parts [1 ]
351+ // Check if line starts with "spp "
352+ if strings .HasPrefix (strings .ToLower (line ), "spp " ) {
353+ parts := strings .Fields (line )
354+ if len (parts ) >= 2 {
355+ secretSppValue := parts [1 ]
372356
373- // Check if this matches the PtpConfig's spp
374- if secretSppValue == sppValue {
375- ptpconfiglog .Info ("validated spp match" , "spp" , sppValue , "secret" , secret .Name , "key" , key )
376- return nil // Early return - validation passed ✅
377- }
357+ // Check if this matches the PtpConfig's spp
358+ if secretSppValue == sppValue {
359+ ptpconfiglog .Info ("validated spp match" , "spp" , sppValue , "secret" , secret .Name , "key" , secretKey )
360+ return nil // Validation passed ✅
378361 }
379362 }
380363 }
381364 }
382365
383- return fmt .Errorf ("spp '%s' is not found in secret '%s' " , sppValue , secret .Name )
366+ return fmt .Errorf ("spp '%s' not found in key '%s' of secret '%s' " , sppValue , secretKey , secret .Name )
384367}
385368
386369var _ webhook.Validator = & PtpConfig {}
@@ -435,7 +418,7 @@ func GetInterfaces(config PtpConfig, mode PtpRole) (interfaces []string) {
435418 }
436419 conf := & Ptp4lConf {}
437420 var dummy * string
438- err := conf .populatePtp4lConf (config .Spec .Profile [0 ].Ptp4lConf , dummy )
421+ err := conf .PopulatePtp4lConf (config .Spec .Profile [0 ].Ptp4lConf , dummy )
439422 if err != nil {
440423 logrus .Warnf ("ptp4l conf parsing failed, err=%s" , err )
441424 }
0 commit comments