Skip to content

Commit a8e41fe

Browse files
committed
OTA-1010: release extract: --include works for a minor level update
1 parent 02503fe commit a8e41fe

File tree

3 files changed

+270
-43
lines changed

3 files changed

+270
-43
lines changed

pkg/cli/admin/release/extract.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,20 @@ import (
2121
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2222
"k8s.io/apimachinery/pkg/runtime/schema"
2323
"k8s.io/cli-runtime/pkg/genericiooptions"
24+
appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
2425
"k8s.io/client-go/rest"
2526
kcmdutil "k8s.io/kubectl/pkg/cmd/util"
2627
"k8s.io/kubectl/pkg/util/templates"
2728

2829
imagev1 "github.com/openshift/api/image/v1"
30+
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
2931
"github.com/openshift/library-go/pkg/image/dockerv1client"
3032
"github.com/openshift/library-go/pkg/manifest"
3133
"github.com/openshift/oc/pkg/cli/image/extract"
3234
"github.com/openshift/oc/pkg/cli/image/imagesource"
3335
imagemanifest "github.com/openshift/oc/pkg/cli/image/manifest"
3436
"github.com/openshift/oc/pkg/cli/image/workqueue"
37+
"github.com/openshift/oc/pkg/version"
3538
"github.com/pkg/errors"
3639
)
3740

@@ -94,7 +97,8 @@ func NewExtract(f kcmdutil.Factory, streams genericiooptions.IOStreams) *cobra.C
9497
If --install-config is set, it will be used to determine the expected cluster configuration,
9598
otherwise the command will interrogate your current cluster to determine its configuration.
9699
This command is most accurate when the version of the extracting client matches the version
97-
of the cluster under consideration.
100+
of the cluster under consideration. Otherwise, for example, newly introduced capabilities in
101+
the version of the extracting client might be considered enabled.
98102
99103
Instead of extracting the manifests, you can specify --git=DIR to perform a Git
100104
checkout of the source code that comprises the release. A warning will be printed
@@ -359,10 +363,27 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
359363
if o.Included {
360364
context := "connected cluster"
361365
inclusionConfig := manifestInclusionConfiguration{}
366+
367+
clientVersion, reportedVersion, versionErr := version.ExtractVersion()
368+
if versionErr != nil {
369+
return versionErr
370+
}
371+
if reportedVersion == "" {
372+
reportedVersion = clientVersion.String()
373+
}
374+
362375
if o.InstallConfig == "" {
363-
inclusionConfig, err = findClusterIncludeConfig(ctx, o.RESTConfig)
376+
configv1client, configv1clientErr := configv1client.NewForConfig(o.RESTConfig)
377+
if configv1clientErr != nil {
378+
return configv1clientErr
379+
}
380+
appsv1client, appsv1clientErr := appsv1client.NewForConfig(o.RESTConfig)
381+
if appsv1clientErr != nil {
382+
return appsv1clientErr
383+
}
384+
inclusionConfig, err = findClusterIncludeConfig(ctx, configv1client, appsv1client, reportedVersion)
364385
} else {
365-
inclusionConfig, err = findClusterIncludeConfigFromInstallConfig(ctx, o.InstallConfig)
386+
inclusionConfig, err = findClusterIncludeConfigFromInstallConfig(ctx, o.InstallConfig, reportedVersion)
366387
context = o.InstallConfig
367388
}
368389
if err != nil {

pkg/cli/admin/release/extract_tools.go

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"io"
1515
"os"
1616
"path/filepath"
17-
"regexp"
1817
"runtime"
1918
"sort"
2019
"strings"
@@ -32,7 +31,6 @@ import (
3231
"k8s.io/apimachinery/pkg/util/sets"
3332
"k8s.io/cli-runtime/pkg/genericiooptions"
3433
appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
35-
"k8s.io/client-go/rest"
3634
"sigs.k8s.io/yaml"
3735

3836
"github.com/MakeNowJust/heredoc"
@@ -43,7 +41,6 @@ import (
4341
"github.com/openshift/oc/pkg/cli/admin/internal/codesign"
4442
"github.com/openshift/oc/pkg/cli/image/extract"
4543
"github.com/openshift/oc/pkg/cli/image/imagesource"
46-
"github.com/openshift/oc/pkg/version"
4744
)
4845

4946
// extractTarget describes how a file in the release image can be extracted to disk.
@@ -1167,17 +1164,9 @@ func copyAndReplace(errorOutput io.Writer, w io.Writer, r io.Reader, bufferSize
11671164

11681165
}
11691166

1170-
func findClusterIncludeConfigFromInstallConfig(ctx context.Context, installConfigPath string) (manifestInclusionConfiguration, error) {
1167+
func findClusterIncludeConfigFromInstallConfig(ctx context.Context, installConfigPath, ocVersion string) (manifestInclusionConfiguration, error) {
11711168
config := manifestInclusionConfiguration{}
11721169

1173-
clientVersion, reportedVersion, err := version.ExtractVersion()
1174-
if err != nil {
1175-
return config, err
1176-
}
1177-
if reportedVersion == "" {
1178-
reportedVersion = clientVersion.String()
1179-
}
1180-
11811170
installConfigBytes, err := os.ReadFile(installConfigPath)
11821171
if err != nil {
11831172
return config, err
@@ -1205,67 +1194,69 @@ func findClusterIncludeConfigFromInstallConfig(ctx context.Context, installConfi
12051194
return config, fmt.Errorf("unrecognized baselineCapabilitySet %q", data.Capabilities.BaselineCapabilitySet)
12061195
} else {
12071196
if data.Capabilities.BaselineCapabilitySet == configv1.ClusterVersionCapabilitySetCurrent {
1208-
klog.Infof("If the eventual cluster will not be the same minor version as this %s 'oc', the actual %s capability set may differ.", reportedVersion, data.Capabilities.BaselineCapabilitySet)
1197+
klog.Infof("If the eventual cluster will not be the same minor version as this %s 'oc', the actual %s capability set may differ.", ocVersion, data.Capabilities.BaselineCapabilitySet)
12091198
}
12101199
config.Capabilities.EnabledCapabilities = append(config.Capabilities.EnabledCapabilities, enabled...)
12111200
}
12121201
config.Capabilities.EnabledCapabilities = append(config.Capabilities.EnabledCapabilities, data.Capabilities.AdditionalEnabledCapabilities...)
12131202

1214-
klog.Infof("If the eventual cluster will not be the same minor version as this %s 'oc', the known capability sets may differ.", reportedVersion)
1203+
klog.Infof("If the eventual cluster will not be the same minor version as this %s 'oc', the known capability sets may differ.", ocVersion)
12151204
config.Capabilities.KnownCapabilities = configv1.KnownClusterVersionCapabilities
12161205
}
12171206

12181207
return config, nil
12191208
}
12201209

1221-
func findClusterIncludeConfig(ctx context.Context, restConfig *rest.Config) (manifestInclusionConfiguration, error) {
1210+
func findClusterIncludeConfig(ctx context.Context, configv1client configv1client.ConfigV1Interface, appsv1client appsv1client.AppsV1Interface, ocVersion string) (manifestInclusionConfiguration, error) {
12221211
config := manifestInclusionConfiguration{}
12231212

1224-
client, err := configv1client.NewForConfig(restConfig)
1225-
if err != nil {
1226-
return config, err
1227-
}
1228-
1229-
if featureGate, err := client.FeatureGates().Get(ctx, "cluster", metav1.GetOptions{}); err != nil {
1213+
if featureGate, err := configv1client.FeatureGates().Get(ctx, "cluster", metav1.GetOptions{}); err != nil {
12301214
return config, err
12311215
} else {
12321216
config.RequiredFeatureSet = ptr.To[string](string(featureGate.Spec.FeatureSet))
12331217
}
12341218

1235-
if clusterVersion, err := client.ClusterVersions().Get(ctx, "version", metav1.GetOptions{}); err != nil {
1219+
if clusterVersion, err := configv1client.ClusterVersions().Get(ctx, "version", metav1.GetOptions{}); err != nil {
12361220
return config, err
12371221
} else {
12381222
config.Overrides = clusterVersion.Spec.Overrides
12391223
config.Capabilities = &clusterVersion.Status.Capabilities
12401224

1241-
// FIXME: eventually pull in GetImplicitlyEnabledCapabilities from https://github.com/openshift/cluster-version-operator/blob/86e24d66119a73f50282b66a8d6f2e3518aa0e15/pkg/payload/payload.go#L237-L240 for cases where a minor update would implicitly enable some additional capabilities. For now, 4.13 to 4.14 will always enable MachineAPI, ImageRegistry, etc..
1242-
currentVersion := clusterVersion.Status.Desired.Version
1243-
matches := regexp.MustCompile(`^(\d+[.]\d+)[.].*`).FindStringSubmatch(currentVersion)
1244-
if len(matches) < 2 {
1245-
return config, fmt.Errorf("failed to parse major.minor version from ClusterVersion status.desired.version %q", currentVersion)
1246-
} else if matches[1] == "4.13" {
1247-
build := configv1.ClusterVersionCapability("Build")
1248-
deploymentConfig := configv1.ClusterVersionCapability("DeploymentConfig")
1249-
imageRegistry := configv1.ClusterVersionCapability("ImageRegistry")
1250-
config.Capabilities.EnabledCapabilities = append(config.Capabilities.EnabledCapabilities, configv1.ClusterVersionCapabilityMachineAPI, build, deploymentConfig, imageRegistry)
1251-
config.Capabilities.KnownCapabilities = append(config.Capabilities.KnownCapabilities, configv1.ClusterVersionCapabilityMachineAPI, build, deploymentConfig, imageRegistry)
1225+
known := sets.New[configv1.ClusterVersionCapability](configv1.KnownClusterVersionCapabilities...)
1226+
previouslyKnown := sets.New[configv1.ClusterVersionCapability](config.Capabilities.KnownCapabilities...)
1227+
config.Capabilities.KnownCapabilities = previouslyKnown.Union(known).UnsortedList()
1228+
1229+
// refresh BaselineCapabilitySet as more capabilities might be included across versions
1230+
key := configv1.ClusterVersionCapabilitySetCurrent
1231+
if clusterVersion.Spec.Capabilities != nil && clusterVersion.Spec.Capabilities.BaselineCapabilitySet != "" {
1232+
key = clusterVersion.Spec.Capabilities.BaselineCapabilitySet
12521233
}
1234+
enabled := sets.New[configv1.ClusterVersionCapability](configv1.ClusterVersionCapabilitySets[key]...)
1235+
// The set of the capabilities may grow over time. Without downloading the payload that is running on the cluster,
1236+
// it is hard to project all the enabled capabilities after upgrading to the incoming release.
1237+
// As an approximation, all newly introduced capabilities are considered enabled to check if a manifest from the
1238+
// release should be included while some of them might not be actually enabled on the cluster.
1239+
// As a result, unexpected manifests could be included. The number of such manifests is likely small, provided that
1240+
// only a small amount of capabilities are added over time and that happens only for minor level updates:
1241+
// #Cap(4.11)=4 -> #Cap(4.17)=15, averagely less than two per minor update.
1242+
// https://docs.openshift.com/container-platform/4.17/installing/overview/cluster-capabilities.html
1243+
deltaKnown := known.Difference(previouslyKnown)
1244+
if deltaKnown.Len() > 0 {
1245+
klog.Infof("The new capabilities that are introduced in this oc version %s are considered enabled on checking if a manifest is included: %s. They may be disabled on the eventual cluster", ocVersion, deltaKnown.UnsortedList())
1246+
}
1247+
enabled = enabled.Union(deltaKnown)
1248+
config.Capabilities.EnabledCapabilities = sets.New[configv1.ClusterVersionCapability](config.Capabilities.EnabledCapabilities...).Union(enabled).UnsortedList()
12531249
}
12541250

1255-
if infrastructure, err := client.Infrastructures().Get(ctx, "cluster", metav1.GetOptions{}); err != nil {
1251+
if infrastructure, err := configv1client.Infrastructures().Get(ctx, "cluster", metav1.GetOptions{}); err != nil {
12561252
return config, err
12571253
} else if infrastructure.Status.PlatformStatus == nil {
12581254
return config, fmt.Errorf("cluster infrastructure does not declare status.platformStatus: %v", infrastructure.Status)
12591255
} else {
12601256
config.Platform = ptr.To[string](strings.ToLower(string(infrastructure.Status.PlatformStatus.Type)))
12611257
}
12621258

1263-
appsClient, err := appsv1client.NewForConfig(restConfig)
1264-
if err != nil {
1265-
return config, err
1266-
}
1267-
1268-
if deployment, err := appsClient.Deployments("openshift-cluster-version").Get(ctx, "cluster-version-operator", metav1.GetOptions{}); err != nil {
1259+
if deployment, err := appsv1client.Deployments("openshift-cluster-version").Get(ctx, "cluster-version-operator", metav1.GetOptions{}); err != nil {
12691260
return config, err
12701261
} else {
12711262
for _, container := range deployment.Spec.Template.Spec.Containers {

0 commit comments

Comments
 (0)