-
Notifications
You must be signed in to change notification settings - Fork 463
Allow overriding OSImageURL with a layered image #3272
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
Merged
openshift-merge-robot
merged 7 commits into
openshift:master
from
jkyros:new-image-format-minimal
Aug 15, 2022
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
655bcf5
Extend RpmOstreeClient to support layered images
jkyros a8d445c
Update rpm-ostree tests with new signatures
jkyros f3f88f1
Allow machineconfigs to override osimageurl again
jkyros 55e65fa
Adjust unit tests to allow for OSImageURL override
jkyros 7fd97b8
Refactor applyOSChanges to accommodate layering
jkyros 2f0328b
Allow bootstrap path to use new format image
jkyros 6796633
Give rpm-ostree access to the kubelet pull secrets
jkyros File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ package daemon | |
|
|
||
| import ( | ||
| "encoding/json" | ||
| "errors" | ||
| "fmt" | ||
| "os" | ||
| "os/exec" | ||
|
|
@@ -31,15 +32,18 @@ type rpmOstreeState struct { | |
|
|
||
| // RpmOstreeDeployment represents a single deployment on a node | ||
| type RpmOstreeDeployment struct { | ||
| ID string `json:"id"` | ||
| OSName string `json:"osname"` | ||
| Serial int32 `json:"serial"` | ||
| Checksum string `json:"checksum"` | ||
| Version string `json:"version"` | ||
| Timestamp uint64 `json:"timestamp"` | ||
| Booted bool `json:"booted"` | ||
| Origin string `json:"origin"` | ||
| CustomOrigin []string `json:"custom-origin"` | ||
| ID string `json:"id"` | ||
| OSName string `json:"osname"` | ||
| Serial int32 `json:"serial"` | ||
| Checksum string `json:"checksum"` | ||
| Version string `json:"version"` | ||
| Timestamp uint64 `json:"timestamp"` | ||
| Booted bool `json:"booted"` | ||
| Staged bool `json:"staged"` | ||
| LiveReplaced string `json:"live-replaced,omitempty"` | ||
| Origin string `json:"origin"` | ||
| CustomOrigin []string `json:"custom-origin"` | ||
| ContainerImageReference string `json:"container-image-reference"` | ||
| } | ||
|
|
||
| // imageInspection is a public implementation of | ||
|
|
@@ -64,7 +68,9 @@ type NodeUpdaterClient interface { | |
| GetStatus() (string, error) | ||
| GetBootedOSImageURL() (string, string, error) | ||
| Rebase(string, string) (bool, error) | ||
| GetBootedDeployment() (*RpmOstreeDeployment, error) | ||
| RebaseLayered(string) error | ||
| IsBootableImage(string) (bool, error) | ||
| GetBootedAndStagedDeployment() (*RpmOstreeDeployment, *RpmOstreeDeployment, error) | ||
| } | ||
|
|
||
| // RpmOstreeClient provides all RpmOstree related methods in one structure. | ||
|
|
@@ -105,20 +111,16 @@ func (r *RpmOstreeClient) Initialize() error { | |
| } | ||
|
|
||
| // GetBootedDeployment returns the current deployment found | ||
| func (r *RpmOstreeClient) GetBootedDeployment() (*RpmOstreeDeployment, error) { | ||
| func (r *RpmOstreeClient) GetBootedAndStagedDeployment() (booted, staged *RpmOstreeDeployment, err error) { | ||
| status, err := r.loadStatus() | ||
| if err != nil { | ||
| return nil, err | ||
| return nil, nil, err | ||
| } | ||
|
|
||
| for _, deployment := range status.Deployments { | ||
| if deployment.Booted { | ||
| deployment := deployment | ||
| return &deployment, nil | ||
| } | ||
| } | ||
| booted, err = status.getBootedDeployment() | ||
| staged = status.getStagedDeployment() | ||
|
|
||
| return nil, fmt.Errorf("not currently booted in a deployment") | ||
| return | ||
| } | ||
|
|
||
| // GetStatus returns multi-line human-readable text describing system status | ||
|
|
@@ -135,7 +137,7 @@ func (r *RpmOstreeClient) GetStatus() (string, error) { | |
| // Returns the empty string if the host doesn't have a custom origin that matches pivot:// | ||
| // (This could be the case for e.g. FCOS, or a future RHCOS which comes not-pivoted by default) | ||
| func (r *RpmOstreeClient) GetBootedOSImageURL() (string, string, error) { | ||
| bootedDeployment, err := r.GetBootedDeployment() | ||
| bootedDeployment, _, err := r.GetBootedAndStagedDeployment() | ||
| if err != nil { | ||
| return "", "", err | ||
| } | ||
|
|
@@ -148,6 +150,14 @@ func (r *RpmOstreeClient) GetBootedOSImageURL() (string, string, error) { | |
| } | ||
| } | ||
|
|
||
| // we have container images now, make sure we can parse those too | ||
| if bootedDeployment.ContainerImageReference != "" { | ||
| // right now they start with "ostree-unverified-registry:", so scrape that off | ||
| tokens := strings.SplitN(bootedDeployment.ContainerImageReference, ":", 2) | ||
| if len(tokens) > 1 { | ||
| osImageURL = tokens[1] | ||
| } | ||
| } | ||
| return osImageURL, bootedDeployment.Version, nil | ||
| } | ||
|
|
||
|
|
@@ -189,7 +199,7 @@ func (r *RpmOstreeClient) Rebase(imgURL, osImageContentDir string) (changed bool | |
| ostreeCsum string | ||
| ostreeVersion string | ||
| ) | ||
| defaultDeployment, err := r.GetBootedDeployment() | ||
| defaultDeployment, _, err := r.GetBootedAndStagedDeployment() | ||
| if err != nil { | ||
| return | ||
| } | ||
|
|
@@ -275,6 +285,66 @@ func (r *RpmOstreeClient) Rebase(imgURL, osImageContentDir string) (changed bool | |
| return | ||
| } | ||
|
|
||
| // IsBootableImage determines if the image is a bootable (new container formet) image, or a wrapper (old container format) | ||
| func (r *RpmOstreeClient) IsBootableImage(imgURL string) (bool, error) { | ||
|
|
||
| // TODO(jkyros): This is duplicated-ish from Rebase(), do we still need to carry this around? | ||
| var isBootableImage string | ||
| var imageData *types.ImageInspectInfo | ||
| var err error | ||
| if imageData, err = imageInspect(imgURL); err != nil { | ||
| if err != nil { | ||
| var podmanImgData *imageInspection | ||
| glog.Infof("Falling back to using podman inspect") | ||
|
|
||
| if podmanImgData, err = podmanInspect(imgURL); err != nil { | ||
| return false, err | ||
| } | ||
| isBootableImage = podmanImgData.Labels["ostree.bootable"] | ||
| } | ||
| } else { | ||
| isBootableImage = imageData.Labels["ostree.bootable"] | ||
| } | ||
| // We may have pulled in OSContainer image as fallback during podmanCopy() or podmanInspect() | ||
| defer exec.Command("podman", "rmi", imgURL).Run() | ||
|
|
||
| return isBootableImage == "true", nil | ||
| } | ||
|
|
||
| // RebaseLayered rebases system or errors if already rebased | ||
| func (r *RpmOstreeClient) RebaseLayered(imgURL string) (err error) { | ||
| glog.Infof("Executing rebase to %s", imgURL) | ||
|
|
||
| // For now, just let ostree use the kublet config.json, | ||
| err = useKubeletConfigSecrets() | ||
| if err != nil { | ||
| return fmt.Errorf("Error while ensuring access to kublet config.json pull secrets: %w", err) | ||
| } | ||
|
|
||
| return runRpmOstree("rebase", "--experimental", "ostree-unverified-registry:"+imgURL) | ||
| } | ||
|
|
||
| // useKubeletConfigSecrets gives the rpm-ostree client access to secrets in the kubelet config.json by symlinking so that | ||
| // rpm-ostree can use those secrets to pull images. It does this by symlinking the kubelet's config.json into /run/ostree. | ||
| func useKubeletConfigSecrets() error { | ||
| if _, err := os.Stat("/run/ostree/auth.json"); err != nil { | ||
|
|
||
| if errors.Is(err, os.ErrNotExist) { | ||
|
|
||
| err := os.MkdirAll("/run/ostree", 0o544) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| err = os.Symlink(kubeletAuthFile, "/run/ostree/auth.json") | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // truncate a string using runes/codepoints as limits. | ||
| // This specifically will avoid breaking a UTF-8 value. | ||
| func truncate(input string, limit int) string { | ||
|
|
@@ -303,3 +373,23 @@ func runGetOut(command string, args ...string) ([]byte, error) { | |
| } | ||
| return rawOut, nil | ||
| } | ||
|
|
||
| func (state *rpmOstreeState) getBootedDeployment() (*RpmOstreeDeployment, error) { | ||
|
Member
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. (Tangentially related to this I was kind of thinking about splitting out a github.com/coreos/rpmostree-client-go repository) |
||
| for num := range state.Deployments { | ||
| deployment := state.Deployments[num] | ||
| if deployment.Booted { | ||
| return &deployment, nil | ||
| } | ||
| } | ||
| return &RpmOstreeDeployment{}, fmt.Errorf("not currently booted in a deployment") | ||
| } | ||
|
|
||
| func (state *rpmOstreeState) getStagedDeployment() *RpmOstreeDeployment { | ||
| for num := range state.Deployments { | ||
| deployment := state.Deployments[num] | ||
| if deployment.Staged { | ||
| return &deployment | ||
| } | ||
| } | ||
| return &RpmOstreeDeployment{} | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
will this always be the case?
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.
I think at least for the time being we know there will be a prefix, but I don't know that it will always be explicitly the "ostree-unverified-registry" prefix.
I can just scrape the prefix of "ostree-unverified-registry" and move on, but then if the prefix changes, we're broken. This here, however, will break if the prefix is ever completely absent, so that's not 100% future-proof either.
We talked about this when we put this in the layering branch -- we were trying to avoid having to regex this, but I can?
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.
So...well, yes this is a bit messy.
It actually does open up the question of how the user specifies security-related settings for this image. (Not just for the ostree-level signatures, but also e.g. TLS)
For the moment, I have to say that we hardcode injecting
ostree-unverified-registry:as a prefix on the URL they provide.We're planning to introduce a CRD, and that's probably the right place to have explicit settings for this.
That said, there is an argument that the interface to this
containers-policy.json- and we shouldn't try to treat the OS image container specially at all.But I dunno...it is different because we're going to boot it.
Anyways yeah my instinct right now is to inject
ostree-unverified-registry:on the container image reference they provide.Parsing the value by splitting on the first
:is certainly something we can rely on right now.But yes, this is all still technically experimental and change-able. But we wouldn't change it without getting the MCO to work with the new way first!