github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/hooks/exec/runtimeconfigfilter.go (about)

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