package v2 import ( "errors" "fmt" "edge-infra.dev/pkg/sds/lib/set" ) var ( errV1AndV2SpecSpecified = errors.New("V1 spec cannot be specified alongside V2 spec") errStandByLongerThanSuspendTime = errors.New("stand-by time cannot be longer than suspend time") errSuspendLongerThanOffTime = errors.New("suspend time cannot be longer than off time") ) // Validates the DisplayConfig, checking: // - V1 spec is valid and not configured alongside V2 spec. // - All display-ports are unique. // - MPID and supported resolutions are not configured in spec. // - Only one display is configured as the primary. // - DPMS configuration is valid (standby-time < suspend-time < off-time). func (displayConfig *DisplayConfig) Validate() error { if displayConfig == nil { return nil } if displayConfig.V1 != nil { return validateV1(displayConfig) } if err := validateNonSettableFields(displayConfig); err != nil { return err } if err := validateDisplayPorts(displayConfig); err != nil { return err } if err := validatePrimary(displayConfig); err != nil { return err } return validateDPMS(displayConfig) } // V1 and V2 spec cannot both be configured. // // V1 spec must be valid. func validateV1(displayConfig *DisplayConfig) error { if displayConfig.Displays != nil || displayConfig.Layout != nil || displayConfig.DPMS != nil { return errV1AndV2SpecSpecified } return displayConfig.V1.Validate() } // Display-ports must be unique for displays and layout. func validateDisplayPorts(displayConfig *DisplayConfig) error { displayDPs := set.Set[DisplayPort]{} for _, dp := range displayConfig.Displays.DisplayPorts() { if _, ok := displayDPs[dp]; ok { return fmt.Errorf("display display-ports must be unique, multiple displays use '%s'", dp) } displayDPs.Add(dp) } layoutDPs := set.Set[DisplayPort]{} for _, dp := range displayConfig.Layout { if _, ok := layoutDPs[dp]; ok { return fmt.Errorf("layout display-ports must be unique, multiple entries for '%s'", dp) } layoutDPs.Add(dp) } return nil } // Displays cannot configure MPID or supported resolution. func validateNonSettableFields(displayConfig *DisplayConfig) error { for _, display := range displayConfig.Displays { if display.MPID != nil { return fmt.Errorf("display %s specified 'MPID': this must not be configured in the NodeDisplayConfig spec", display.DisplayPort) } if display.SupportedResolutions != nil { return fmt.Errorf("display %s specified 'supportedResolutions': resolution must be configured via the 'resolution' field", display.DisplayPort) } } return nil } // Only one display can be the primary. func validatePrimary(displayConfig *DisplayConfig) error { primaries := []DisplayPort{} for _, display := range displayConfig.Displays { if display.IsPrimary() { primaries = append(primaries, display.DisplayPort) } } if len(primaries) > 1 { return fmt.Errorf("there can only be one primary, found %d: %v", len(primaries), primaries) } return nil } // Validates DPMS configuration. // // Where these fields are set, they must be configured so // standby-time < suspend-time < off-time. // // If a field is not set, it is assumed to be 0. func validateDPMS(displayConfig *DisplayConfig) error { if displayConfig.DPMS == nil { return nil } var standybyTime, suspendTimeTime, offTimeTime int if displayConfig.DPMS.StandbyTime != nil { standybyTime = *displayConfig.DPMS.StandbyTime } if displayConfig.DPMS.SuspendTime != nil { suspendTimeTime = *displayConfig.DPMS.SuspendTime } if displayConfig.DPMS.OffTime != nil { offTimeTime = *displayConfig.DPMS.OffTime } if standybyTime > suspendTimeTime { return errStandByLongerThanSuspendTime } else if suspendTimeTime > offTimeTime { return errSuspendLongerThanOffTime } return nil }