1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
package exec
import (
"bytes"
"context"
"encoding/json"
"fmt"
"reflect"
"time"
"github.com/davecgh/go-spew/spew"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pmezard/go-difflib/difflib"
"github.com/sirupsen/logrus"
)
var spewConfig = spew.ConfigState{
Indent: " ",
DisablePointerAddresses: true,
DisableCapacities: true,
SortKeys: true,
}
// RuntimeConfigFilter calls a series of hooks. But instead of
// passing container state on their standard input,
// RuntimeConfigFilter passes the proposed runtime configuration (and
// reads back a possibly-altered form from their standard output).
func RuntimeConfigFilter(ctx context.Context, hooks []spec.Hook, config *spec.Spec, postKillTimeout time.Duration) (hookErr, err error) {
data, err := json.Marshal(config)
if err != nil {
return nil, err
}
for i, hook := range hooks {
hook := hook
var stdout bytes.Buffer
hookErr, err = Run(ctx, &hook, data, &stdout, nil, postKillTimeout)
if err != nil {
return hookErr, err
}
data = stdout.Bytes()
var newConfig spec.Spec
err = json.Unmarshal(data, &newConfig)
if err != nil {
logrus.Debugf("invalid JSON from config-filter hook %d:\n%s", i, string(data))
return nil, fmt.Errorf("unmarshal output from config-filter hook %d: %w", i, err)
}
if !reflect.DeepEqual(config, &newConfig) {
oldConfig := spewConfig.Sdump(config)
newConfig := spewConfig.Sdump(&newConfig)
diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(oldConfig),
B: difflib.SplitLines(newConfig),
FromFile: "Old",
FromDate: "",
ToFile: "New",
ToDate: "",
Context: 1,
})
if err == nil {
logrus.Debugf("precreate hook %d made configuration changes:\n%s", i, diff)
} else {
logrus.Warnf("Precreate hook %d made configuration changes, but we could not compute a diff: %v", i, err)
}
}
*config = newConfig
}
return nil, nil
}
|