@@ -114,65 +114,92 @@ func (p *Plugin) Generate() ([]byte, error) {
114114 }
115115 }
116116
117- // Keep track of which placement maps to which policy. This will be used to determine
117+ // Keep track of which placement maps to which policy and policySet . This will be used to determine
118118 // how many placement bindings are required since one binding per placement is required.
119- plcNameToPolicyIdxs := map [string ][]int {}
119+ // plcNameToPolicyAndSetIdxs[plcName]["policy"] stores the index of policy
120+ // plcNameToPolicyAndSetIdxs[plcName]["policyset"] stores the index of policyset
121+ plcNameToPolicyAndSetIdxs := map [string ]map [string ][]int {}
120122 for i := range p .Policies {
121123 // only generate placement when GeneratePlacementWhenInSet equals to true or policy is not
122124 // part of any policy sets
123125 if p .Policies [i ].GeneratePlacementWhenInSet || len (p .Policies [i ].PolicySets ) == 0 {
124- plcName , err := p .createPlacement (& p .Policies [i ])
126+ plcName , err := p .createPlacement (& p .Policies [i ]. Placement , p . Policies [ i ]. Name )
125127 if err != nil {
126128 return nil , err
127129 }
128- plcNameToPolicyIdxs [plcName ] = append (plcNameToPolicyIdxs [plcName ], i )
130+ if plcNameToPolicyAndSetIdxs [plcName ] == nil {
131+ plcNameToPolicyAndSetIdxs [plcName ] = map [string ][]int {}
132+ }
133+ plcNameToPolicyAndSetIdxs [plcName ]["policy" ] = append (plcNameToPolicyAndSetIdxs [plcName ]["policy" ], i )
129134 }
130135 }
131136
132- // Sort the keys of plcNameToPolicyIdxs so that the policy bindings are generated in a
137+ for i := range p .PolicySets {
138+ plcName , err := p .createPlacement (& p .PolicySets [i ].Placement , p .PolicySets [i ].Name )
139+ if err != nil {
140+ return nil , err
141+ }
142+ if plcNameToPolicyAndSetIdxs [plcName ] == nil {
143+ plcNameToPolicyAndSetIdxs [plcName ] = map [string ][]int {}
144+ }
145+ plcNameToPolicyAndSetIdxs [plcName ]["policyset" ] =
146+ append (plcNameToPolicyAndSetIdxs [plcName ]["policyset" ], i )
147+ }
148+
149+ // Sort the keys of plcNameToPolicyseetsIdxs so that the policy bindings are generated in a
133150 // consistent order.
134- plcNames := make ([]string , len (plcNameToPolicyIdxs ))
151+ plcNames := make ([]string , len (plcNameToPolicyAndSetIdxs ))
135152 i := 0
136- for k := range plcNameToPolicyIdxs {
153+ for k := range plcNameToPolicyAndSetIdxs {
137154 plcNames [i ] = k
138155 i ++
139156 }
140157 sort .Strings (plcNames )
141158
142159 plcBindingCount := 0
143160 for _ , plcName := range plcNames {
144- // Determine which policies to be included in the placement binding.
161+ // Determine which policies and policy sets to be included in the placement binding.
145162 policyConfs := []* types.PolicyConfig {}
146- for _ , i := range plcNameToPolicyIdxs [plcName ] {
163+ for _ , i := range plcNameToPolicyAndSetIdxs [plcName ][ "policy" ] {
147164 policyConfs = append (policyConfs , & p .Policies [i ])
148165 }
166+ policySetConfs := []* types.PolicySetConfig {}
167+ for _ , i := range plcNameToPolicyAndSetIdxs [plcName ]["policyset" ] {
168+ policySetConfs = append (policySetConfs , & p .PolicySets [i ])
169+ }
149170
150171 // If there is more than one policy associated with a placement but no default binding name
151172 // specified, throw an error
152- if len (policyConfs ) > 1 && p .PlacementBindingDefaults .Name == "" {
173+ if ( len (policyConfs ) > 1 || len ( policySetConfs ) > 1 ) && p .PlacementBindingDefaults .Name == "" {
153174 return nil , fmt .Errorf (
154- "placementBindingDefaults.name must be set but is empty (multiple policies were found for the PlacementBinding to placement %s)" ,
175+ "placementBindingDefaults.name must be set but is empty (multiple policies or policy sets were found for the PlacementBinding to placement %s)" ,
155176 plcName ,
156177 )
157178 }
158179
159180 var bindingName string
160- // If there is only one policy, use the policy name if there is no default
181+ existMultiple := false
182+ // If there is only one policy or one policy set, use the policy or policy set name if there is no default
161183 // binding name specified
162- if len (policyConfs ) == 1 && p . PlacementBindingDefaults . Name == "" {
184+ if len (policyConfs ) == 1 && len ( policySetConfs ) == 0 {
163185 bindingName = "binding-" + policyConfs [0 ].Name
186+ } else if len (policyConfs ) == 0 && len (policySetConfs ) == 0 {
187+ bindingName = "binding-" + policySetConfs [0 ].Name
164188 } else {
189+ existMultiple = true
190+ }
191+ // If there are multiple policies or policy sets, use the default placement binding name
192+ // but append a number to it so it's a unique name.
193+ if p .PlacementBindingDefaults .Name != "" && existMultiple {
165194 plcBindingCount ++
166- // If there are multiple policies, use the default placement binding name
167- // but append a number to it so it's a unique name.
168195 if plcBindingCount == 1 {
169196 bindingName = p .PlacementBindingDefaults .Name
170197 } else {
171198 bindingName = fmt .Sprintf ("%s%d" , p .PlacementBindingDefaults .Name , plcBindingCount )
172199 }
173200 }
174201
175- err := p .createPlacementBinding (bindingName , plcName , policyConfs )
202+ err := p .createPlacementBinding (bindingName , plcName , policyConfs , policySetConfs )
176203 if err != nil {
177204 return nil , fmt .Errorf ("failed to create a placement binding: %w" , err )
178205 }
@@ -271,6 +298,7 @@ func (p *Plugin) applyDefaults(unmarshaledConfig map[string]interface{}) {
271298 if p .PolicyDefaults .Standards == nil {
272299 p .PolicyDefaults .Standards = defaults .Standards
273300 }
301+
274302 // Generate temporary sets to later merge the policy sets declared in p.Policies[*] and p.PolicySets
275303 plcsetToPlc := make (map [string ]map [string ]bool )
276304 plcToPlcset := make (map [string ]map [string ]bool )
@@ -717,21 +745,21 @@ func (p *Plugin) getPlcFromPath(plcPath string) (string, map[string]interface{},
717745
718746// getCsKey generates the key for the policy's cluster/label selectors to be used in
719747// Policies.csToPlc.
720- func getCsKey (policyConf * types.PolicyConfig ) string {
721- return fmt .Sprintf ("%#v" , policyConf . Placement .ClusterSelectors )
748+ func getCsKey (placementConfig * types.PlacementConfig ) string {
749+ return fmt .Sprintf ("%#v" , placementConfig .ClusterSelectors )
722750}
723751
724752// getPlcName will generate a placement name for the policy. If the placement has
725753// previously been generated, skip will be true.
726- func (p * Plugin ) getPlcName (policyConf * types.PolicyConfig ) (name string , skip bool ) {
727- if policyConf . Placement .Name != "" {
754+ func (p * Plugin ) getPlcName (placementConfig * types.PlacementConfig , nameDefault string ) (string , bool ) {
755+ if placementConfig .Name != "" {
728756 // If the policy explicitly specifies a placement name, use it
729- return policyConf . Placement .Name , false
757+ return placementConfig .Name , false
730758 } else if p .PolicyDefaults .Placement .Name != "" {
731759 // If the policy doesn't explicitly specify a placement name, and there is a
732760 // default placement name set, check if one has already been generated for these
733761 // cluster/label selectors
734- csKey := getCsKey (policyConf )
762+ csKey := getCsKey (placementConfig )
735763 if _ , ok := p .csToPlc [csKey ]; ok {
736764 // Just reuse the previously created placement with the same cluster/label selectors
737765 return p .csToPlc [csKey ], true
@@ -746,18 +774,18 @@ func (p *Plugin) getPlcName(policyConf *types.PolicyConfig) (name string, skip b
746774 return fmt .Sprintf ("%s%d" , p .PolicyDefaults .Placement .Name , len (p .csToPlc )+ 1 ), false
747775 }
748776 // Default to a placement per policy
749- return "placement-" + policyConf . Name , false
777+ return "placement-" + nameDefault , false
750778}
751779
752- // createPlacement creates a placement for the input policy configuration by writing it to
780+ // createPlacement creates a placement for the input placement config and default name by writing it to
753781// the policy generator's output buffer. The name of the placement or an error is returned.
754782// If the placement has already been generated, it will be reused and not added to the
755783// policy generator's output buffer. An error is returned if the placement cannot be created.
756- func (p * Plugin ) createPlacement (policyConf * types.PolicyConfig ) (
784+ func (p * Plugin ) createPlacement (placementConfig * types.PlacementConfig , nameDefault string ) (
757785 name string , err error ,
758786) {
759- plrPath := policyConf . Placement .PlacementRulePath
760- plcPath := policyConf . Placement .PlacementPath
787+ plrPath := placementConfig .PlacementRulePath
788+ plcPath := placementConfig .PlacementPath
761789 var placement map [string ]interface {}
762790 // If a path to a placement is provided, find the placement and reuse it.
763791 if plrPath != "" || plcPath != "" {
@@ -782,17 +810,17 @@ func (p *Plugin) createPlacement(policyConf *types.PolicyConfig) (
782810 p .processedPlcs [name ] = true
783811 } else {
784812 var skip bool
785- name , skip = p .getPlcName (policyConf )
813+ name , skip = p .getPlcName (placementConfig , nameDefault )
786814 if skip {
787815 return
788816 }
789817
790818 // Determine which selectors to use
791819 var resolvedSelectors map [string ]string
792- if len (policyConf . Placement .ClusterSelectors ) > 0 {
793- resolvedSelectors = policyConf . Placement .ClusterSelectors
794- } else if len (policyConf . Placement .LabelSelector ) > 0 {
795- resolvedSelectors = policyConf . Placement .LabelSelector
820+ if len (placementConfig .ClusterSelectors ) > 0 {
821+ resolvedSelectors = placementConfig .ClusterSelectors
822+ } else if len (placementConfig .LabelSelector ) > 0 {
823+ resolvedSelectors = placementConfig .LabelSelector
796824 }
797825
798826 // Sort the keys so that the match expressions can be ordered based on the label name
@@ -855,7 +883,7 @@ func (p *Plugin) createPlacement(policyConf *types.PolicyConfig) (
855883 }
856884 }
857885
858- csKey := getCsKey (policyConf )
886+ csKey := getCsKey (placementConfig )
859887 p .csToPlc [csKey ] = name
860888 }
861889
@@ -880,13 +908,13 @@ func (p *Plugin) createPlacement(policyConf *types.PolicyConfig) (
880908 return
881909}
882910
883- // createPlacementBinding creates a placement binding for the input placement and policies by
911+ // createPlacementBinding creates a placement binding for the input placement, policies and policy sets by
884912// writing it to the policy generator's output buffer. An error is returned if the placement binding
885913// cannot be created.
886914func (p * Plugin ) createPlacementBinding (
887- bindingName , plcName string , policyConfs []* types.PolicyConfig ,
915+ bindingName , plcName string , policyConfs []* types.PolicyConfig , policySetConfs [] * types. PolicySetConfig ,
888916) error {
889- subjects := make ([]map [string ]string , 0 , len (policyConfs ))
917+ subjects := make ([]map [string ]string , 0 , len (policyConfs )+ len ( policySetConfs ) )
890918 for _ , policyConf := range policyConfs {
891919 subject := map [string ]string {
892920 // Remove the version at the end
@@ -897,6 +925,16 @@ func (p *Plugin) createPlacementBinding(
897925 subjects = append (subjects , subject )
898926 }
899927
928+ for _ , policySetConf := range policySetConfs {
929+ subject := map [string ]string {
930+ // Remove the version at the end
931+ "apiGroup" : strings .Split (policyAPIVersion , "/" )[0 ],
932+ "kind" : policySetKind ,
933+ "name" : policySetConf .Name ,
934+ }
935+ subjects = append (subjects , subject )
936+ }
937+
900938 var resolvedPlcKind string
901939 var resolvedPlcAPIVersion string
902940 if p .usingPlR {
0 commit comments