-
Notifications
You must be signed in to change notification settings - Fork 413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support installing extensions and rework OS update #1941
Changes from all commits
6757381
f322412
653063d
67349b2
dff98ab
16771e3
549f7b1
6cdfc2d
e34463f
662bf1d
5b44766
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,23 +8,20 @@ require ( | |
github.com/Masterminds/goutils v1.1.0 // indirect | ||
github.com/Masterminds/semver v1.4.2 // indirect | ||
github.com/Masterminds/sprig v2.20.0+incompatible | ||
github.com/Microsoft/go-winio v0.4.14 // indirect | ||
github.com/OpenPeeDeeP/depguard v1.0.1 // indirect | ||
github.com/apparentlymart/go-cidr v1.0.0 | ||
github.com/ashcrow/osrelease v0.0.0-20180626175927-9b292693c55c | ||
github.com/clarketm/json v1.14.1 | ||
github.com/containers/image v3.0.2+incompatible | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hum, container-runtime-config (and openshift/runtime-utils) still use the old version. That should probably be updated to decrease duplication… but it’s also rather out of scope of this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, we can clean this up separately. |
||
github.com/containers/storage v1.13.5 | ||
github.com/containers/image/v5 v5.5.1 | ||
github.com/containers/storage v1.20.2 | ||
github.com/coreos/fcct v0.5.0 | ||
github.com/coreos/go-semver v0.3.0 | ||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect | ||
github.com/coreos/ign-converter v0.0.0-20200629171308-e40a44f244c5 | ||
github.com/coreos/ignition v0.35.0 | ||
github.com/coreos/ignition/v2 v2.3.0 | ||
github.com/davecgh/go-spew v1.1.1 | ||
github.com/docker/docker v1.4.2-0.20190927142053-ada3c14355ce // indirect | ||
github.com/docker/docker-credential-helpers v0.6.3 // indirect | ||
github.com/docker/go-connections v0.4.0 // indirect | ||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect | ||
github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1 // indirect | ||
github.com/elazarl/goproxy/ext v0.0.0-20190911111923-ecfe977594f1 // indirect | ||
|
@@ -41,31 +38,23 @@ require ( | |
github.com/gostaticanalysis/analysisutil v0.0.3 // indirect | ||
github.com/hashicorp/golang-lru v0.5.3 // indirect | ||
github.com/huandu/xstrings v1.2.0 // indirect | ||
github.com/imdario/mergo v0.3.7 | ||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect | ||
github.com/imdario/mergo v0.3.9 | ||
github.com/magiconair/properties v1.8.1 // indirect | ||
github.com/mattn/go-isatty v0.0.9 // indirect | ||
github.com/mtrmac/gpgme v0.1.2 // indirect | ||
github.com/opencontainers/go-digest v1.0.0-rc1 | ||
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 // indirect | ||
github.com/opencontainers/runc v1.0.0-rc8.0.20190827142921-dd075602f158 // indirect | ||
github.com/openshift/api v3.9.1-0.20191111211345-a27ff30ebf09+incompatible | ||
github.com/openshift/client-go v0.0.0-20200320150128-a906f3d8e723 | ||
github.com/openshift/library-go v0.0.0-20200320155611-2a351bebf158 | ||
github.com/openshift/runtime-utils v0.0.0-20191011150825-9169de69ebf6 | ||
github.com/pkg/errors v0.8.1 | ||
github.com/pkg/errors v0.9.1 | ||
github.com/prometheus/client_golang v1.1.0 | ||
github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d | ||
github.com/spf13/cobra v0.0.5 | ||
github.com/spf13/jwalterweatherman v1.1.0 // indirect | ||
github.com/spf13/pflag v1.0.5 | ||
github.com/stretchr/testify v1.4.0 | ||
github.com/stretchr/testify v1.6.1 | ||
github.com/ultraware/funlen v0.0.2 // indirect | ||
github.com/vincent-petithory/dataurl v0.0.0-20160330182126-9a301d65acbb | ||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect | ||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect | ||
github.com/xeipuuv/gojsonschema v1.1.0 // indirect | ||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 | ||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 | ||
google.golang.org/appengine v1.6.1 // indirect | ||
k8s.io/api v0.18.3 | ||
k8s.io/apiextensions-apiserver v0.18.0 | ||
|
Large diffs are not rendered by default.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,6 +103,18 @@ func MergeMachineConfigs(configs []*mcfgv1.MachineConfig, osImageURL string) (*m | |
kargs = append(kargs, cfg.Spec.KernelArguments...) | ||
} | ||
|
||
extensions := []string{} | ||
for _, cfg := range configs { | ||
extensions = append(extensions, cfg.Spec.Extensions...) | ||
} | ||
|
||
// Ensure that kernel-devel extension is applied only with default kernel. | ||
if kernelType != KernelTypeDefault { | ||
if InSlice("kernel-devel", extensions) { | ||
return nil, fmt.Errorf("installing kernel-devel extension is not supported with kernelType: %s", kernelType) | ||
} | ||
} | ||
|
||
return &mcfgv1.MachineConfig{ | ||
Spec: mcfgv1.MachineConfigSpec{ | ||
OSImageURL: osImageURL, | ||
|
@@ -112,6 +124,7 @@ func MergeMachineConfigs(configs []*mcfgv1.MachineConfig, osImageURL string) (*m | |
}, | ||
FIPS: fips, | ||
KernelType: kernelType, | ||
Extensions: extensions, | ||
}, | ||
}, nil | ||
} | ||
|
@@ -285,12 +298,41 @@ func ValidateIgnition(ignconfig interface{}) error { | |
} | ||
} | ||
|
||
// InSlice search for an element in slice and return true if found, otherwise return false | ||
func InSlice(elem string, slice []string) bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be unexported There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks for catching this, this was carried from work done in #1850. I missed updating inArray() call in update.go to InSlice(). Fixed https://github.com/openshift/machine-config-operator/pull/1941/files#diff-06961b075f1753956d802ba954d2cfb5R694 |
||
for _, k := range slice { | ||
if k == elem { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func validateExtensions(exts []string) error { | ||
supportedExtensions := []string{"usbguard", "kernel-devel"} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could these be constants exported alongside the MC api types? If we could even add them to the CRD's openapi schema that'd be even better, so that users get immediate feedback on invalid extensions. Or maybe even have a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not very sure. The list of supported extensions is going to change whenever we add more extensions support in upcoming releases. In future, we are also exploring to add metadata for supported extension list in machine-os-content openshift/os#409 which MCO can read from and validate before rendering. |
||
invalidExts := []string{} | ||
for _, ext := range exts { | ||
if !InSlice(ext, supportedExtensions) { | ||
invalidExts = append(invalidExts, ext) | ||
} | ||
} | ||
if len(invalidExts) != 0 { | ||
return fmt.Errorf("invalid extensions found: %v", invalidExts) | ||
} | ||
return nil | ||
|
||
} | ||
|
||
// ValidateMachineConfig validates that given MachineConfig Spec is valid. | ||
func ValidateMachineConfig(cfg mcfgv1.MachineConfigSpec) error { | ||
if !(cfg.KernelType == "" || cfg.KernelType == KernelTypeDefault || cfg.KernelType == KernelTypeRealtime) { | ||
return errors.Errorf("kernelType=%s is invalid", cfg.KernelType) | ||
} | ||
|
||
if err := validateExtensions(cfg.Extensions); err != nil { | ||
return err | ||
} | ||
|
||
if cfg.Config.Raw != nil { | ||
ignCfg, err := IgnParseWrapper(cfg.Config.Raw) | ||
if err != nil { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1031,7 +1031,17 @@ func (dn *Daemon) checkStateOnFirstRun() error { | |
if !osMatch { | ||
glog.Infof("Bootstrap pivot required to: %s", targetOSImageURL) | ||
// This only returns on error | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should move this comment down to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. umm, we will return back here also when updateOS() fails? |
||
return dn.updateOSAndReboot(state.currentConfig) | ||
osImageContentDir, err := ExtractOSImage(targetOSImageURL) | ||
if err != nil { | ||
return err | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
if err := dn.updateOS(state.currentConfig, osImageContentDir); err != nil { | ||
return err | ||
} | ||
if err := os.RemoveAll(osImageContentDir); err != nil { | ||
return err | ||
} | ||
return dn.finalizeAndReboot(state.currentConfig) | ||
} | ||
glog.Info("No bootstrap pivot required; unlinking bootstrap node annotations") | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package daemon | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"math" | ||
"strings" | ||
"time" | ||
|
||
"github.com/containers/image/v5/docker" | ||
"github.com/containers/image/v5/image" | ||
"github.com/containers/image/v5/types" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
func retryIfNecessary(ctx context.Context, operation func() error) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason not to use k8s.io/client-go/util/retry? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I followed the convention of what skopeo has been doing to retry https://github.com/containers/skopeo/blob/153f18dc0ac34e1adfc700806ef30af33187908b/cmd/skopeo/utils.go#L330 |
||
err := operation() | ||
for attempt := 0; err != nil && attempt < numRetriesNetCommands; attempt++ { | ||
delay := time.Duration(int(math.Pow(2, float64(attempt)))) * time.Second | ||
fmt.Printf("Warning: failed, retrying in %s ... (%d/%d)", delay, attempt+1, numRetriesNetCommands) | ||
select { | ||
case <-time.After(delay): | ||
break | ||
case <-ctx.Done(): | ||
return err | ||
} | ||
err = operation() | ||
} | ||
return err | ||
} | ||
|
||
// newDockerImageSource creates an image source for an image reference. | ||
// The caller must call .Close() on the returned ImageSource. | ||
func newDockerImageSource(ctx context.Context, sys *types.SystemContext, name string) (types.ImageSource, error) { | ||
var imageName string | ||
if !strings.HasPrefix(name, "//") { | ||
imageName = "//" + name | ||
} else { | ||
imageName = name | ||
} | ||
ref, err := docker.ParseReference(imageName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return ref.NewImageSource(ctx, sys) | ||
} | ||
|
||
// This function has been inspired from upstream skopeo inspect, see https://github.com/containers/skopeo/blob/master/cmd/skopeo/inspect.go | ||
// We can use skopeo inspect directly once fetching RepoTags becomes optional in skopeo. | ||
func imageInspect(imageName string) (*types.ImageInspectInfo, error) { | ||
var ( | ||
src types.ImageSource | ||
imgInspect *types.ImageInspectInfo | ||
err error | ||
) | ||
|
||
ctx := context.Background() | ||
sys := &types.SystemContext{AuthFilePath: kubeletAuthFile} | ||
|
||
if err := retryIfNecessary(ctx, func() error { | ||
src, err = newDockerImageSource(ctx, sys, imageName) | ||
return err | ||
}); err != nil { | ||
return nil, errors.Wrapf(err, "Error parsing image name %q", imageName) | ||
} | ||
|
||
defer src.Close() | ||
|
||
img, err := image.FromUnparsedImage(ctx, sys, image.UnparsedInstance(src, nil)) | ||
if err != nil { | ||
return nil, fmt.Errorf("Error parsing manifest for image: %v", err) | ||
} | ||
|
||
if err := retryIfNecessary(ctx, func() error { | ||
imgInspect, err = img.Inspect(ctx) | ||
return err | ||
}); err != nil { | ||
return nil, err | ||
} | ||
|
||
return imgInspect, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason not to do:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, missed to refactor at the end in proper way. fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This breaks OKD as it doesn't have
oc
in FCOS image. Fromrelease-image.log
on bootstrap node:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
decided to follow up thanks Vadim 🙏 #1941 (comment)