@@ -2247,49 +2247,36 @@ func getApprovedCSVs(
22472247 return nil
22482248 }
22492249
2250- packageDependencies := getBundleDependencies (installPlan , subscriptionCSV , "" )
2251-
2252- approvedCSVs := sets.Set [string ]{}
2253- approvedCSVs .Insert (subscriptionCSV )
2254-
2255- // Approve all CSVs that are dependencies of the subscription CSV.
2256- for _ , packageDependency := range packageDependencies .UnsortedList () {
2257- for _ , csvName := range installPlan .Spec .ClusterServiceVersionNames {
2258- if strings .HasPrefix (csvName , packageDependency + ".v" ) {
2259- approvedCSVs .Insert (csvName )
2260- }
2261- }
2262- }
2250+ approvedCSVs := getBundleDependencies (installPlan , subscriptionCSV )
22632251
22642252 return approvedCSVs
22652253}
22662254
2267- // getBundleDependencies recursively gets the dependencies from a target CSV or package name. If the package name is
2268- // provided instead of the target CSV, then it assumes the CSVs are in the format of `<package>.v<version>`. The
2269- // returned set is of package names and not the CSV (i.e. no version in it) .
2255+ // getBundleDependencies reads the install plan for required package dependencies.
2256+ // The package names are mapped to their CSV identifiers before recursively evaluating the dependency chain.
2257+ // The returned set contains the target CSV and all of its dependency CSVs .
22702258func getBundleDependencies (
2271- installPlan * operatorv1alpha1.InstallPlan , targetCSV string , packageName string ,
2259+ installPlan * operatorv1alpha1.InstallPlan , targetCSV string ,
22722260) sets.Set [string ] {
2273- packageDependencies := sets.Set [string ]{}
2261+ approvedCSVs := sets.Set [string ]{}
22742262
2275- if targetCSV == "" && packageName == "" {
2276- return packageDependencies
2263+ if targetCSV == "" {
2264+ return approvedCSVs
22772265 }
22782266
2279- for i , bundle := range installPlan .Status .BundleLookups {
2280- if targetCSV != "" && bundle .Identifier != targetCSV {
2281- continue
2282- }
2267+ approvedCSVs .Insert (targetCSV )
22832268
2284- if packageName != "" && ! strings .HasPrefix (bundle .Identifier , packageName + ".v" ) {
2285- continue
2286- }
2269+ // stores the mapping of package names to unapproved CSV identifiers
2270+ packageToCSV := make (map [string ]string )
2271+ // stores the required package names for each unapproved CSV
2272+ packageDependencies := make (map [string ]sets.Set [string ])
22872273
2274+ for i , bundle := range installPlan .Status .BundleLookups {
22882275 if bundle .Properties == "" {
2289- break
2276+ continue
22902277 }
22912278
2292- props := map [string ]interface {} {}
2279+ props := map [string ]any {}
22932280
22942281 err := json .Unmarshal ([]byte (bundle .Properties ), & props )
22952282 if err != nil {
@@ -2304,37 +2291,86 @@ func getBundleDependencies(
23042291 break
23052292 }
23062293
2307- propsList , ok := props ["properties" ].([]interface {} )
2294+ propsList , ok := props ["properties" ].([]any )
23082295 if ! ok {
2309- break
2296+ continue
23102297 }
23112298
23122299 for _ , prop := range propsList {
2313- propMap , ok := prop .(map [string ]interface {})
2300+ propMap , ok := prop .(map [string ]any )
2301+ if ! ok {
2302+ continue
2303+ }
2304+
2305+ propType , ok := propMap ["type" ].(string )
23142306 if ! ok {
23152307 continue
23162308 }
23172309
2318- if propMap [ "type" ] != "olm.package.required" {
2310+ if propType != "olm.package" && propType != "olm.package.required" {
23192311 continue
23202312 }
23212313
2322- propValue , ok := propMap ["value" ].(map [string ]interface {} )
2314+ propValue , ok := propMap ["value" ].(map [string ]any )
23232315 if ! ok {
23242316 continue
23252317 }
23262318
2327- depPackageName , ok := propValue ["packageName" ].(string )
2328- if ! ok || depPackageName == "" {
2319+ pkgName , ok := propValue ["packageName" ].(string )
2320+ if ! ok || pkgName == "" {
23292321 continue
23302322 }
23312323
2332- packageDependencies .Insert (depPackageName )
2333- packageDependencies = packageDependencies .Union (getBundleDependencies (installPlan , "" , depPackageName ))
2324+ switch propType {
2325+ case "olm.package" :
2326+ packageToCSV [pkgName ] = bundle .Identifier
2327+ case "olm.package.required" :
2328+ if packageDependencies [bundle .Identifier ] == nil {
2329+ packageDependencies [bundle .Identifier ] = sets.Set [string ]{}
2330+ }
2331+
2332+ packageDependencies [bundle .Identifier ].Insert (pkgName )
2333+ }
2334+ }
2335+ }
2336+
2337+ approvedCSVs = approvedCSVs .Union (getDependencyCSVs (targetCSV , packageToCSV , packageDependencies ))
2338+
2339+ return approvedCSVs
2340+ }
2341+
2342+ // getDependencyCSVs recursively converts the package dependencies to their CSV identifiers
2343+ func getDependencyCSVs (
2344+ startingCSV string , packageToCSV map [string ]string , packageDependencies map [string ]sets.Set [string ],
2345+ ) sets.Set [string ] {
2346+ dependencyCSVs := sets.Set [string ]{}
2347+
2348+ if startingCSV == "" || packageToCSV == nil || packageDependencies == nil {
2349+ return dependencyCSVs
2350+ }
2351+
2352+ packages , ok := packageDependencies [startingCSV ]
2353+ if ! ok || packages == nil {
2354+ return dependencyCSVs
2355+ }
2356+
2357+ for pkg := range packages {
2358+ if csv , ok := packageToCSV [pkg ]; ok {
2359+ dependencyCSVs .Insert (csv )
23342360 }
23352361 }
23362362
2337- return packageDependencies
2363+ if len (dependencyCSVs ) == 0 {
2364+ // The startingCSV's dependencies are already satisfied
2365+ // by other installed CSVs. No additional CSVs need approval.
2366+ return dependencyCSVs
2367+ }
2368+
2369+ for csv := range dependencyCSVs {
2370+ dependencyCSVs = dependencyCSVs .Union (getDependencyCSVs (csv , packageToCSV , packageDependencies ))
2371+ }
2372+
2373+ return dependencyCSVs
23382374}
23392375
23402376func (r * OperatorPolicyReconciler ) mustnothaveInstallPlan (
0 commit comments