Skip to content

Conversation

@croissanne
Copy link
Member

Opened in conjunction with osbuild/images#1966, to see if ppl think this is a good approach.

Changes with 0.207.0
----------------
  - Enable fedora 43 unit testing (osbuild/images#1954)
    - Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza
  - fedora: update cloud_kernel_options (osbuild/images#1953)
    - Author: Sanne Raymaekers, Reviewers: Achilleas Koutsou, Simon de Vlieger
  - test/data/repos/rhel-10.2: fix copy & paste error (osbuild/images#1956)
    - Author: Tomáš Hozza, Reviewers: Achilleas Koutsou, Simon de Vlieger

Changes with 0.208.0
----------------
  - Schutzfile: switch CI runner to Fedora 42 (osbuild/images#1955)
    - Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza
  - Support uploading to IBM Cloud (osbuild/images#1924)
    - Author: Jakub Kadlčík, Reviewers: Achilleas Koutsou, Simon de Vlieger
  - pkg/osbuild: generate osbuild result from status scanner entries (osbuild/images#1941)
    - Author: Sanne Raymaekers, Reviewers: Nobody

Changes with 0.209.0
----------------
  - gitlab: run ostree manifest generation and builds only when needed (osbuild/images#1961)
    - Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza
  - osbuild/osbuild-exec: extract building the osbuild cmd to helper (osbuild/images#1963)
    - Author: Sanne Raymaekers, Reviewers: Achilleas Koutsou, Simon de Vlieger
  - rhel10: add ism secret & top secret oscap profiles (HMS-9507) (osbuild/images#1962)
    - Author: Gianluca Zuccarelli, Reviewers: Lukáš Zapletal, Sanne Raymaekers
libvirt.org/go/libvirt v1.11006.0 // indirect
)

replace github.com/osbuild/images => github.com/croissanne/images v0.0.0-20251023114920-81eefc443b5e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is still draft, this is just to show what it would look like with osbuild/images#1966. Not actually intending to merge this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure was just highlighting it, I guess we have a linter for that. Or not, depends on the repo :-)

github.com/osbuild/images v0.209.0/go.mod h1:tZqcrs3eNUA0VPs1h3YCnbnpAskVVfo36CIi2USSfDs=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not have been in this commit, there is a separate one I guess you accidentally squashed it in.

if st.Trace != "" {
tracesMsgs = append(tracesMsgs, st.Trace)
mu.Lock()
defer mu.Unlock()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using defer does not seem correct there is a double lock if both variables are not empty.

mw = &stdio
var mu sync.Mutex
buildLog := opts.BuildLog
opts.BuildLogMu = &mu
Copy link
Contributor

@lzap lzap Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can someone explain why newSyncedWriter was written in a way it accepts a mutex? I do not understand why a mutex could be shared for this decorator design pattern. It should have been:

type SyncedWriter struct {
	mu sync.Mutex
	w  io.Writer
}

func NewSyncedWriter(w io.Writer) *SyncedWriter {
	return &SyncedWriter{w: w}
}

func (sw *SyncedWriter) Write(p []byte) (n int, err error) {
	sw.mu.Lock()
	defer sw.mu.Unlock()

	return sw.w.Write(p)
}

Than we could drop this passing of mutex, it is created on stack either way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 reasons:

  1. ibcli needs to write to the buildlog itself, it needs access to the mutex. So passing the mutex to the synced writer is needed, or we need to retrieve the mutex from the writer. It's ugly, but I can't think of an alternative.

  2. 2 separate instances of synced writer need to share this mutex

mw = newSyncedWriter(&writeMu, io.MultiWriter(&stdio, opts.BuildLog))
buildLog = newSyncedWriter(&writeMu, opts.BuildLog)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 2nd reason is actually no longer the case with osbuild/images#1966 ; but we still need to pass along the mutex, unless we don't care about the ordering for these extra statements ibcli adds to the buildlog.

Copy link
Contributor

@lzap lzap Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, right. Well, how about to tee before sync so each writer has its individual mutex that can be shared? Something like:

syncedStdio := newSyncedWriter(&stdio)
syncedBuildLog := newSyncedWriter(opts.BuildLog)
io.MultiWriter(syncedStdio, syncedBuildLog)

Then use syncedBuildLog to write separately only to the build log independent of stdio. The example assumes newSyncedWriter no longer takes a shared mutex.

Copy link
Member Author

@croissanne croissanne Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the flow should be

stdout → syncw → multiw → stdoutw or os stdout     
stderr ↗↗↗              → buildlog

If we create the syncw after the mw we get

stdout → multiw → syncw
stderr ↗↗↗      → syncw

I think by having both stdout and stderr go via the multiw into syncw we're already out of order? Unsure.

Copy link
Member Author

@croissanne croissanne Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh actually this works in images, I guess io.MultiWriter isn't racy?

	if opts.BuildLog != nil {
		// There is a slight wrinkle here: when requesting a buildlog we can no longer write
		// to separate stdout/stderr streams without being racy and give potential
		// out-of-order output (which is very bad and confusing in a log). The reason is
		// that if cmd.Std{out,err} are different "go" will start two go-routine to
		// monitor/copy those are racy when both stdout,stderr output happens close together
		// (TestRunOSBuildWithBuildlog demos that). We cannot have our cake and eat it so
		// here we need to combine osbuilds stderr into our stdout.
		// stdout → syncw → multiw → stdoutw or os stdout
		// stderr ↗↗↗             → buildlog
		//
		//
		// stdout → syncw → multiw → stdoutw or os stdout
		// stderr ↗↗↗             → buildlog
		// mu := common.ValueOrEmpty(opts.BuildLogMu)
		var mu1 sync.Mutex
		var mu2 sync.Mutex
		mw := io.MultiWriter(newSyncedWriter(&mu1, stdout), newSyncedWriter(&mu2, opts.BuildLog))
		cmd.Stdout = mw
		cmd.Stderr = mw
	}

The only problem is still writing the the buildlog from ibcli if we actually wanna move the synced writer over to images.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reversing multiwriter and syncedwriter can work, test pass with go test -race iwth this in images:

		if opts.BuildLogMu == nil {
			var mu sync.Mutex
			opts.BuildLogMu = &mu
		}

		var syncedStdio, syncedBuildlog io.Writer
		syncedStdio = newSyncedWriter(opts.BuildLogMu, stdout)
		syncedBuildlog = newSyncedWriter(opts.BuildLogMu, opts.BuildLog)
		mw := io.MultiWriter(syncedStdio, syncedBuildlog)
		cmd.Stdout = mw
		cmd.Stderr = mw

But this doesn't solve problem 2 :/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image maybe helpful

The following moved into images:
- OSBuildOptions;
- construction of the osbuild command;
- build log support;
- synced writer;
- monitor support.

See osbuild/images#1966.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants