diff options
33 files changed, 1309 insertions, 325 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 9c13f5303..e09db2a81 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -579,6 +579,29 @@ remote_system_test_task: TEST_FLAVOR: sys PODBIN_NAME: remote +buildah_bud_test_task: + name: *std_name_fmt + alias: buildah_bud_test + skip: *tags + only_if: *not_docs + depends_on: + - local_integration_test + env: + TEST_FLAVOR: bud + DISTRO_NV: ${FEDORA_NAME} + # Not used here, is used in other tasks + VM_IMAGE_NAME: ${FEDORA_CACHE_IMAGE_NAME} + CTR_FQIN: ${FEDORA_CONTAINER_FQIN} + # ID for re-use of build output + _BUILD_CACHE_HANDLE: ${FEDORA_NAME}-build-${CIRRUS_BUILD_ID} + PODBIN_NAME: podman + gce_instance: *standardvm + timeout_in: 45m + clone_script: *noop + gopath_cache: *ro_gopath_cache + setup_script: *setup + main_script: *main + always: *int_logs_artifacts rootless_system_test_task: name: *std_name_fmt @@ -687,6 +710,7 @@ success_task: - remote_system_test - rootless_system_test - upgrade_test + - buildah_bud_test - meta container: *smallcontainer env: diff --git a/cmd/podman/system/prune.go b/cmd/podman/system/prune.go index 136c15304..3020a541b 100644 --- a/cmd/podman/system/prune.go +++ b/cmd/podman/system/prune.go @@ -55,22 +55,17 @@ func init() { func prune(cmd *cobra.Command, args []string) error { var err error - // Prompt for confirmation if --force is not set if !force { reader := bufio.NewReader(os.Stdin) volumeString := "" if pruneOptions.Volume { volumeString = ` - - all volumes not used by at least one container` + - all volumes not used by at least one container` } - fmt.Printf(` -WARNING! This will remove: - - all stopped containers%s - - all stopped pods - - all dangling images - - all build cache -Are you sure you want to continue? [y/N] `, volumeString) + + fmt.Printf(createPruneWarningMessage(pruneOptions), volumeString, "Are you sure you want to continue? [y/N] ") + answer, err := reader.ReadString('\n') if err != nil { return err @@ -115,3 +110,22 @@ Are you sure you want to continue? [y/N] `, volumeString) fmt.Printf("Total reclaimed space: %s\n", units.HumanSize((float64)(response.ReclaimedSpace))) return nil } + +func createPruneWarningMessage(pruneOpts entities.SystemPruneOptions) string { + if pruneOpts.All { + return `WARNING! This will remove: + - all stopped containers + - all networks not used by at least one container%s + - all images without at least one container associated to them + - all build cache + +%s` + } + return `WARNING! This will remove: + - all stopped containers + - all networks not used by at least one container%s + - all dangling images + - all dangling build cache + +%s` +} diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh index fca9aff93..507d22e13 100755 --- a/contrib/cirrus/runner.sh +++ b/contrib/cirrus/runner.sh @@ -74,6 +74,10 @@ function _run_upgrade_test() { bats test/upgrade |& logformatter } +function _run_bud() { + ./test/buildah-bud/run-buildah-bud-tests |& logformatter +} + function _run_bindings() { # shellcheck disable=SC2155 export PATH=$PATH:$GOSRC/hack diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index 64ea3b7b4..fcb1284e7 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -201,6 +201,7 @@ case "$TEST_FLAVOR" in int) ;& sys) ;& upgrade_test) ;& + bud) ;& bindings) ;& endpoint) # Use existing host bits when testing is to happen inside a container diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md index 24093d414..8fcfe555e 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -650,6 +650,10 @@ If --userns-gid-map-group is specified, but --userns-uid-map-user is not specified, `podman` will assume that the specified group name is also a suitable user name to use as the default setting for this option. +**NOTE:** When this option is specified by a rootless user, the specified +mappings are relative to the rootless usernamespace in the container, rather +than being relative to the host as it would be when run rootful. + #### **--userns-gid-map-group**=*group* Specifies that a GID mapping which should be used to set ownership, at the @@ -661,6 +665,10 @@ If --userns-uid-map-user is specified, but --userns-gid-map-group is not specified, `podman` will assume that the specified user name is also a suitable group name to use as the default setting for this option. +**NOTE:** When this option is specified by a rootless user, the specified +mappings are relative to the rootless usernamespace in the container, rather +than being relative to the host as it would be when run rootful. + #### **--uts**=*how* Sets the configuration for UTS namespaces when the handling `RUN` instructions. @@ -17,7 +17,7 @@ require ( github.com/containers/ocicrypt v1.1.0 github.com/containers/psgo v1.5.2 github.com/containers/storage v1.28.0 - github.com/coreos/go-systemd/v22 v22.1.0 + github.com/coreos/go-systemd/v22 v22.3.0 github.com/cri-o/ocicni v0.2.1-0.20210301205850-541cf7c703cf github.com/cyphar/filepath-securejoin v0.2.2 github.com/davecgh/go-spew v1.1.1 @@ -67,6 +67,6 @@ require ( golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect - k8s.io/api v0.20.1 + k8s.io/api v0.20.5 k8s.io/apimachinery v0.20.5 ) @@ -214,8 +214,9 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.0 h1:C8u/Ljj8G8O6rqWJh2J8cDyeEFBMWvXlvJ/ccMyzcqw= +github.com/coreos/go-systemd/v22 v22.3.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -749,7 +750,6 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -1169,8 +1169,9 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.20.1 h1:ud1c3W3YNzGd6ABJlbFfKXBKXO+1KdGfcgGGNgFR03E= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.5 h1:zsMTffV0Le2EiI0aKvlTHEnXGxk1HiqGRhJcCPiI7JI= +k8s.io/api v0.20.5/go.mod h1:FQjAceXnVaWDeov2YUWhOb6Yt+5UjErkp6UO3nczO1Y= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.5 h1:wO/FxMVRn223rAKxnBbwCyuN96bS9MFTIvP0e/V7cps= k8s.io/apimachinery v0.20.5/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index 90b11f8ca..13ac42e7d 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -313,15 +313,23 @@ func (r *Runtime) LoadImageFromSingleImageArchive(ctx context.Context, writer io func() (types.ImageReference, error) { return layout.NewReference(inputFile, "") }, + func() (types.ImageReference, error) { + // This item needs to be last to break out of loop and report meaningful error message + return nil, + errors.New("payload does not match any of the supported image formats (oci-archive, oci-dir, docker-archive, docker-dir)") + }, } { src, err := referenceFn() - if err == nil && src != nil { - newImages, err := r.ImageRuntime().LoadFromArchiveReference(ctx, src, signaturePolicy, writer) - if err == nil { - return getImageNames(newImages), nil - } + if err != nil { saveErr = err + continue + } + + newImages, err := r.ImageRuntime().LoadFromArchiveReference(ctx, src, signaturePolicy, writer) + if err == nil { + return getImageNames(newImages), nil } + saveErr = err } return "", errors.Wrapf(saveErr, "error pulling image") } diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index d3277b815..e7146a5d8 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -19,6 +19,7 @@ import ( "github.com/containers/podman/v3/pkg/domain/infra/abi" "github.com/containers/podman/v3/pkg/ps" "github.com/containers/podman/v3/pkg/signal" + "github.com/containers/podman/v3/pkg/util" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/go-connections/nat" @@ -92,23 +93,24 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - All bool `schema:"all"` - Limit int `schema:"limit"` - Size bool `schema:"size"` - Filters map[string][]string `schema:"filters"` + All bool `schema:"all"` + Limit int `schema:"limit"` + Size bool `schema:"size"` }{ // override any golang type defaults } - if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + filterMap, err := util.PrepareFilters(r) + + if dErr := decoder.Decode(&query, r.URL.Query()); dErr != nil || err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } - filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters)) + filterFuncs := make([]libpod.ContainerFilter, 0, len(*filterMap)) all := query.All || query.Limit > 0 - if len(query.Filters) > 0 { - for k, v := range query.Filters { + if len((*filterMap)) > 0 { + for k, v := range *filterMap { generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime) if err != nil { utils.InternalServerError(w, err) @@ -120,7 +122,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { // Docker thinks that if status is given as an input, then we should override // the all setting and always deal with all containers. - if len(query.Filters["status"]) > 0 { + if len((*filterMap)["status"]) > 0 { all = true } if !all { diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go index dc4d53af6..e37929d27 100644 --- a/pkg/api/handlers/compat/containers_prune.go +++ b/pkg/api/handlers/compat/containers_prune.go @@ -9,23 +9,20 @@ import ( "github.com/containers/podman/v3/pkg/api/handlers/utils" "github.com/containers/podman/v3/pkg/domain/entities/reports" "github.com/containers/podman/v3/pkg/domain/filters" - "github.com/gorilla/schema" + "github.com/containers/podman/v3/pkg/util" "github.com/pkg/errors" ) func PruneContainers(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) - decoder := r.Context().Value("decoder").(*schema.Decoder) - - query := struct { - Filters map[string][]string `schema:"filters"` - }{} - if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + filtersMap, err := util.PrepareFilters(r) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } - filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters)) - for k, v := range query.Filters { + + filterFuncs := make([]libpod.ContainerFilter, 0, len(*filtersMap)) + for k, v := range *filtersMap { generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime) if err != nil { utils.InternalServerError(w, err) diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index 01b9ec101..77269db8b 100644 --- a/pkg/api/handlers/libpod/containers.go +++ b/pkg/api/handlers/libpod/containers.go @@ -11,6 +11,7 @@ import ( "github.com/containers/podman/v3/pkg/api/handlers/utils" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/infra/abi" + "github.com/containers/podman/v3/pkg/util" "github.com/gorilla/schema" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -59,20 +60,21 @@ func ContainerExists(w http.ResponseWriter, r *http.Request) { func ListContainers(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - All bool `schema:"all"` - External bool `schema:"external"` - Filters map[string][]string `schema:"filters"` - Last int `schema:"last"` // alias for limit - Limit int `schema:"limit"` - Namespace bool `schema:"namespace"` - Size bool `schema:"size"` - Sync bool `schema:"sync"` + All bool `schema:"all"` + External bool `schema:"external"` + Last int `schema:"last"` // alias for limit + Limit int `schema:"limit"` + Namespace bool `schema:"namespace"` + Size bool `schema:"size"` + Sync bool `schema:"sync"` }{ // override any golang type defaults } - if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, + filterMap, err := util.PrepareFilters(r) + + if dErr := decoder.Decode(&query, r.URL.Query()); dErr != nil || err != nil { + utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } @@ -94,7 +96,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { opts := entities.ContainerListOptions{ All: query.All, External: query.External, - Filters: query.Filters, + Filters: *filterMap, Last: limit, Namespace: query.Namespace, // Always return Pod, should not be part of the API. diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index 83fe23621..1f306a533 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -319,18 +319,6 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { func ImagesLoad(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) - decoder := r.Context().Value("decoder").(*schema.Decoder) - query := struct { - Reference string `schema:"reference"` - }{ - // Add defaults here once needed. - } - - if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, - errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) - return - } tmpfile, err := ioutil.TempFile("", "libpod-images-load.tar") if err != nil { @@ -338,14 +326,15 @@ func ImagesLoad(w http.ResponseWriter, r *http.Request) { return } defer os.Remove(tmpfile.Name()) - defer tmpfile.Close() - if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF { + _, err = io.Copy(tmpfile, r.Body) + tmpfile.Close() + + if err != nil && err != io.EOF { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file")) return } - tmpfile.Close() loadedImage, err := runtime.LoadImage(context.Background(), tmpfile.Name(), os.Stderr, "") if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to load image")) diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 3d86e5d38..423766bd8 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -810,11 +810,14 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // summary: Load image // description: Load an image (oci-archive or docker-archive) stream. // parameters: - // - in: formData + // - in: body // name: upload - // description: tarball of container image - // type: file // required: true + // description: tarball of container image + // schema: + // type: string + // consumes: + // - application/x-tar // produces: // - application/json // responses: diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at index 478717700..9030f0095 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -280,6 +280,32 @@ t GET containers/json 200 \ podman stop bar +#compat api list containers sanity checks +t GET containers/json?filters='garb1age}' 500 \ + .cause="invalid character 'g' looking for beginning of value" +t GET containers/json?filters='{"label":["testl' 500 \ + .cause="unexpected end of JSON input" + +#libpod api list containers sanity checks +t GET libpod/containers/json?filters='garb1age}' 500 \ + .cause="invalid character 'g' looking for beginning of value" +t GET libpod/containers/json?filters='{"label":["testl' 500 \ + .cause="unexpected end of JSON input" + +# Prune containers - bad filter input +t POST containers/prune?filters='garb1age}' 500 \ + .cause="invalid character 'g' looking for beginning of value" +t POST libpod/containers/prune?filters='garb1age}' 500 \ + .cause="invalid character 'g' looking for beginning of value" + +## Prune containers with illformed label +t POST containers/prune?filters='{"label":["tes' 500 \ + .cause="unexpected end of JSON input" +t POST libpod/containers/prune?filters='{"label":["tes' 500 \ + .cause="unexpected end of JSON input" + +t GET libpod/containers/json?filters='{"label":["testlabel"]}' 200 length=0 + # Test CPU limit (NanoCPUs) t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 201 \ .Id~[0-9a-f]\\{64\\} diff --git a/test/buildah-bud/README.md b/test/buildah-bud/README.md new file mode 100644 index 000000000..88e4bbc3c --- /dev/null +++ b/test/buildah-bud/README.md @@ -0,0 +1,82 @@ +buildah-bud tests under podman +============================== + +This directory contains tools for running 'buildah bud' tests +under podman. The key concept of the workflow is: + +* Pull buildah @ version specified in go.mod +* Apply a small set of patches to buildah's tests directory, such that + * BATS will use 'podman build' instead of 'buildah bud'; and + * some not-applicable-under-podman tests are skipped + +It's a teeny bit more complicated than that, but that's really most of +what you need to know for most purposes. The tests run in podman CI, +and for the most part are expected to just pass. + +Troubleshooting +--------------- + +If you're reading this, it's probably because something went wrong. +At the time of this writing (March 2021, initial commit) it is +impossible to foresee what typical failures will look like, but +my prediction is that they will fit one of two categories: + +* Failure when vendoring new buildah (e.g., by dependabot) +* Other failure + +Let's examine those in reverse order: + +Failure when not vendoring +-------------------------- + +Aside from flakes, my only guess here is that you broke 'podman build'. +If this is the case, it is very likely that you are aware of what you +did; and if this is the case, your change likely falls into one of +these two categories: + +* "OOPS! I didn't mean to break that". Solution: fix it! +* "Uh, yeah, this is deliberate, and we choose to be incompatible with buildah". In this case, you'll need to skip or edit the failing test(s); see below. + +If neither of those is the case, then I'm sorry, you're on your own. +When you figure it out, please remember to update these instructions. + + +Failure when vendoring new buildah +---------------------------------- + +This is what I predict will be the usual case; and I predict that +failures will fall into one of two bins: + +* failure to apply the patch +* failure because there are new buildah tests for functionality not in podman + +In either case, the process for solving is the same: + +* Start with a checked-out podman tree with the failing PR applied +* run `./test/buildah-bud/run-buildah-bud-tests` + +Presumably, something will fail here. Whatever the failure, your next step is: + +* `cd test-buildah-v<TAB>` (this is a new directory created by the script) + +If the failure was in `git am`, solve it (left as exercise for the reader). + +If the failure was in tests run, solve it (either by adding `skip`s to +failing tests in bud.bats, or less preferably, by making other tweaks +to the test code). + +You now have modified files. THOSE SHOULD ONLY BE test/bud.bats or +test/helpers.bash! If you changed any other file, that is a sign that +something is very wrong! + +Commit your changes: `git commit --all --amend` + +Push those changes to the podman repo: `./make-new-buildah-diffs` + +cd back up to the podman repo + +As necessary, rerun `run-buildah-bud-tests`. You can use `--no-checkout` +to run tests immediately, without rerunning the git checkout. + +If you're happy with the diffs, `git add` the modified `.diff` file +and submit it as part of your PR. diff --git a/test/buildah-bud/buildah-tests.diff b/test/buildah-bud/buildah-tests.diff new file mode 100644 index 000000000..92adabcac --- /dev/null +++ b/test/buildah-bud/buildah-tests.diff @@ -0,0 +1,192 @@ +From c85882a8f7fb6efbf4d59dfe8340bfbef57ccd48 Mon Sep 17 00:00:00 2001 +From: Ed Santiago <santiago@redhat.com> +Date: Tue, 9 Feb 2021 17:28:05 -0700 +Subject: [PATCH] tweaks for running buildah tests under podman + +Signed-off-by: Ed Santiago <santiago@redhat.com> +--- + tests/bud.bats | 26 ++++++++++++++++---------- + tests/helpers.bash | 28 ++++++++++++++++++++++++---- + 2 files changed, 40 insertions(+), 14 deletions(-) + +diff --git a/tests/bud.bats b/tests/bud.bats +index 1efc3c58..9a39d594 100644 +--- a/tests/bud.bats ++++ b/tests/bud.bats +@@ -4,7 +4,7 @@ load helpers + + @test "bud with a path to a Dockerfile (-f) containing a non-directory entry" { + run_buildah 125 bud -f ${TESTSDIR}/bud/non-directory-in-path/non-directory/Dockerfile +- expect_output --substring "non-directory/Dockerfile: not a directory" ++ expect_output --substring "Error: context must be a directory:" + } + + @test "bud with --dns* flags" { +@@ -95,6 +95,7 @@ symlink(subdir)" + } + + @test "bud-flags-order-verification" { ++ skip "N/A under podman" + run_buildah 125 bud /tmp/tmpdockerfile/ -t blabla + check_options_flag_err "-t" + +@@ -1324,13 +1325,13 @@ function _test_http() { + @test "bud with dir for file but no Dockerfile in dir" { + target=alpine-image + run_buildah 125 bud --signature-policy ${TESTSDIR}/policy.json -t ${target} -f ${TESTSDIR}/bud/empty-dir ${TESTSDIR}/bud/empty-dir +- expect_output --substring "no such file or directory" ++ expect_output --substring "Error: context must be a directory:" + } + + @test "bud with bad dir Dockerfile" { + target=alpine-image + run_buildah 125 bud --signature-policy ${TESTSDIR}/policy.json -t ${target} -f ${TESTSDIR}/baddirname ${TESTSDIR}/baddirname +- expect_output --substring "no such file or directory" ++ expect_output --substring "Error: context must be a directory:" + } + + @test "bud with ARG before FROM default value" { +@@ -1742,7 +1743,9 @@ _EOF + run_buildah bud --signature-policy ${TESTSDIR}/policy.json --layers -t test-img-2 --build-arg TEST=foo -f Dockerfile4 ${TESTSDIR}/bud/build-arg + run_buildah inspect -f '{{.FromImageID}}' test-img-2 + argsid="$output" +- [[ "$argsid" != "$initialid" ]] ++ if [[ "$argsid" == "$initialid" ]]; then ++ die ".FromImageID of test-img-2 ($argsid) == same as test-img, it should be different" ++ fi + + # Set the build-arg via an ENV in the local environment and verify that the cached layers are not used + export TEST=bar +@@ -1795,6 +1798,7 @@ _EOF + } + + @test "bud without any arguments should succeed" { ++ skip "does not work under podman" + cd ${TESTSDIR}/bud/from-scratch + run_buildah bud --signature-policy ${TESTSDIR}/policy.json + } +@@ -1802,7 +1806,7 @@ _EOF + @test "bud without any arguments should fail when no Dockerfile exist" { + cd $(mktemp -d) + run_buildah 125 bud --signature-policy ${TESTSDIR}/policy.json +- expect_output --substring "no such file or directory" ++ expect_output "Error: no context directory and no Containerfile specified" + } + + @test "bud with specified context should fail if directory contains no Dockerfile" { +@@ -1815,16 +1819,17 @@ _EOF + DIR=$(mktemp -d) + mkdir -p "$DIR"/Dockerfile + run_buildah 125 bud --signature-policy ${TESTSDIR}/policy.json "$DIR" +- expect_output --substring "is not a file" ++ expect_output --substring "Error: open .*: no such file or directory" + } + + @test "bud with specified context should fail if context contains not-existing Dockerfile" { + DIR=$(mktemp -d) + run_buildah 125 bud --signature-policy ${TESTSDIR}/policy.json "$DIR"/Dockerfile +- expect_output --substring "no such file or directory" ++ expect_output --substring "context must be a directory" + } + + @test "bud with specified context should succeed if context contains existing Dockerfile" { ++ skip "podman requires a directory, not a Dockerfile" + DIR=$(mktemp -d) + echo "FROM alpine" > "$DIR"/Dockerfile + run_buildah 0 bud --signature-policy ${TESTSDIR}/policy.json "$DIR"/Dockerfile +@@ -1876,7 +1881,7 @@ _EOF + + @test "bud-squash-hardlinks" { + _prefetch busybox +- run_buildah bud --signature-policy ${TESTSDIR}/policy.json --squash ${TESTSDIR}/bud/layers-squash/Dockerfile.hardlinks ++ run_buildah bud --signature-policy ${TESTSDIR}/policy.json --squash -f Dockerfile.hardlinks ${TESTSDIR}/bud/layers-squash + } + + @test "bud with additional directory of devices" { +@@ -2023,6 +2028,7 @@ _EOF + } + + @test "bud pull never" { ++ skip "FIXME: podman issue #9573" + target=pull + run_buildah 125 bud --signature-policy ${TESTSDIR}/policy.json -t ${target} --pull-never ${TESTSDIR}/bud/pull + expect_output --substring "pull policy is \"never\" but \"" +@@ -2042,6 +2048,7 @@ _EOF + } + + @test "bud with Containerfile should fail with nonexistent authfile" { ++ skip "FIXME: podman issue #9572" + target=alpine-image + run_buildah 125 bud --authfile /tmp/nonexistent --signature-policy ${TESTSDIR}/policy.json -t ${target} ${TESTSDIR}/bud/containerfile + } +@@ -2169,6 +2176,7 @@ EOM + } + + @test "bud with encrypted FROM image" { ++ skip "Too much effort to spin up a local registry" + _prefetch busybox + mkdir ${TESTDIR}/tmp + openssl genrsa -out ${TESTDIR}/tmp/mykey.pem 1024 +@@ -2241,8 +2249,6 @@ EOM + _prefetch alpine + run_buildah bud --timestamp=0 --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json -t timestamp -f Dockerfile.1 ${TESTSDIR}/bud/cache-stages + cid=$output +- run_buildah inspect --format '{{ .Docker.Created }}' timestamp +- expect_output --substring "1970-01-01" + run_buildah inspect --format '{{ .OCIv1.Created }}' timestamp + expect_output --substring "1970-01-01" + run_buildah inspect --format '{{ .History }}' timestamp +diff --git a/tests/helpers.bash b/tests/helpers.bash +index 5623a0e7..9683360f 100644 +--- a/tests/helpers.bash ++++ b/tests/helpers.bash +@@ -70,7 +70,7 @@ function _prefetch() { + mkdir -p ${_BUILDAH_IMAGE_CACHEDIR} + fi + +- local _podman_opts="--root ${TESTDIR}/root --storage-driver ${STORAGE_DRIVER}" ++ local _podman_opts="--root ${TESTDIR}/root --runroot ${TESTDIR}/runroot --storage-driver ${STORAGE_DRIVER}" + + for img in "$@"; do + echo "# [checking for: $img]" >&2 +@@ -138,15 +138,35 @@ function run_buildah() { + --retry) retry=3; shift;; # retry network flakes + esac + ++ local podman_or_buildah=${BUILDAH_BINARY} ++ if [[ $1 == "bud" || $1 == "build-using-dockerfile" ]]; then ++ shift ++ # podman defaults to --layers=true; buildah to --false. ++ # If command line includes explicit --layers, leave it untouched, ++ # but otherwise update command line so podman mimics buildah default. ++ if [[ "$*" =~ --layers || "$*" =~ --squash ]]; then ++ set "build" "--force-rm=false" "$@" ++ else ++ set "build" "--force-rm=false" "--layers=false" "$@" ++ fi ++ podman_or_buildah=${PODMAN_BINARY} ++ ++ # podman always exits 125 where buildah exits 1 or 2 ++ case $expected_rc in ++ 1|2) expected_rc=125 ;; ++ esac ++ fi ++ local cmd_basename=$(basename ${podman_or_buildah}) ++ + # Remember command args, for possible use in later diagnostic messages +- MOST_RECENT_BUILDAH_COMMAND="buildah $*" ++ MOST_RECENT_BUILDAH_COMMAND="$cmd_basename $*" + + while [ $retry -gt 0 ]; do + retry=$(( retry - 1 )) + + # stdout is only emitted upon error; this echo is to help a debugger +- echo "\$ $BUILDAH_BINARY $*" +- run timeout --foreground --kill=10 $BUILDAH_TIMEOUT ${BUILDAH_BINARY} --registries-conf ${TESTSDIR}/registries.conf --root ${TESTDIR}/root --runroot ${TESTDIR}/runroot --storage-driver ${STORAGE_DRIVER} "$@" ++ echo "\$ $cmd_basename $*" ++ run timeout --foreground --kill=10 $BUILDAH_TIMEOUT ${podman_or_buildah} --registries-conf ${TESTSDIR}/registries.conf --root ${TESTDIR}/root --runroot ${TESTDIR}/runroot --storage-driver ${STORAGE_DRIVER} "$@" + # without "quotes", multiple lines are glommed together into one + if [ -n "$output" ]; then + echo "$output" +-- +2.30.2 diff --git a/test/buildah-bud/make-new-buildah-diffs b/test/buildah-bud/make-new-buildah-diffs new file mode 100644 index 000000000..1191f4597 --- /dev/null +++ b/test/buildah-bud/make-new-buildah-diffs @@ -0,0 +1,63 @@ +#!/bin/bash +# +# This script is intended to help developers get buildah-tests-under-podman +# working again in case of failure. +# +ME=$(basename $0) + +die() { + echo "$ME: $*" >&2 + exit 1 +} + +# Confirm that we're in a test-buildah* subdir of podman +whereami=$(basename $(pwd)) +if [[ ! $whereami =~ test-buildah-v ]]; then + die "Please run me while cd'ed to a test-buildah-vN.M directory" +fi + +# FIXME: check that git repo is buildah +git remote -v | grep -q [BUILDAHREPO] \ + || die "This does not look like a buildah repo (git remote -v)" + +# We could do the commit automatically, but it's prudent to require human +# involvement. +modified=$(git status --untracked=no --porcelain) +if [[ -n "$modified" ]]; then + echo $modified + die "Please commit your changes: git commit --amend --all" +fi + +# Remove any 00??-*.patch files +rm -f 0001-*.patch + +# Check count of commits, barf if need to squash +n_commits=$(git log --pretty=format:%h [BASETAG]..HEAD | wc -l) +if [[ $n_commits -gt 1 ]]; then + die "Please squash your commits" +fi + +# Scope check: make sure the only files changed are under tests/ +changes=$(git diff --name-status [BASETAG]..HEAD | egrep -v '\stests/') +if [[ -n "$changes" ]]; then + echo $changes + die "Found modified files other than under 'tests/'" +fi + +############################################################################### +# All right - things look good. Generate the patch, and copy it into place. + +git format-patch [BASETAG] + +# Once again, make sure there's exactly one and only one commit +shopt -s nullglob +patch2=$(echo 0002-*.patch) +if [[ -n "$patch2" ]]; then + die "Internal error: I thought I checked for squashed commits, but still see $patch2" +fi + +# All looks good. Now write that patch into its proper place in the +# podman repo. The sed and tac mess strips trailing whitespace and +# empty lines; we need to do this to pass github CI checks. +sed -e 's/ \+$//' <0001-*.patch |\ + tac | sed -e '/./,$!d' | tac >| ../test/buildah-bud/buildah-tests.diff diff --git a/test/buildah-bud/run-buildah-bud-tests b/test/buildah-bud/run-buildah-bud-tests new file mode 100755 index 000000000..67c8fdfa4 --- /dev/null +++ b/test/buildah-bud/run-buildah-bud-tests @@ -0,0 +1,166 @@ +#!/bin/bash + +ME=$(basename $0) + +############################################################################### +# BEGIN user-customizable section + +# Buildah main repository; unlikely to change often +BUILDAH_REPO=github.com/containers/buildah + +# Tag name used to identify the base checkout +BASE_TAG=buildah-bud-in-podman + +# END user-customizable section +############################################################################### + +usage="Usage: $ME [--help] [--no-checkout] [--no-test] +" + +# Parse command-line options (used in development only, not in CI) +do_checkout=y +do_test=y +for i; do + case "$i" in + --no-checkout) do_checkout= ; shift;; + --no-test) do_test= ; shift;; + -h|--help) echo "$usage"; exit 0;; + *) echo "$ME: Unrecognized option '$i'" >&2; exit 1;; + esac +done + +# Patches helpers.bash and potentially other files (bud.bats? Dockerfiles?) +# +# The patch file is horrible to generate: +# 1) cd to the checked-out buildah/tests directory +# 2) make your edits +# 3) git commit -asm 'blah blah blah' +# 3a) if checked-out directory already includes earlier patches, +# you may need to 'git commit --amend' instead +# 4) git format-patch HEAD^ +# 5) sed -e 's/ \+$//' 0001* >../PATCH-FILE-PATH +# 6) vim that file, remove trailing empty newlines +# 7) cd back out of buildah directory, and git-commit this new patch file +# +# FIXME: this makes me nervous. The diff will probably need tweaking +# over time. I don't think we need to version it, because we +# *have* to be in lockstep with a specific buildah version, +# so problems should only arise when we re-vendor. +# But I'm still nervous and can't put my finger on the reason. +# +# Complicated invocation needed because we 'cd' down below. +BUD_TEST_DIR=$(realpath $(dirname ${BASH_SOURCE[0]})) +PATCHES=${BUD_TEST_DIR}/buildah-tests.diff + +# Friendlier relative path to our buildah-tests dir +BUD_TEST_DIR_REL=$(dirname $(git ls-files --full-name ${BASH_SOURCE[0]})) +# Path to podman binary; again, do it before we cd +PODMAN_BINARY=$(pwd)/bin/podman +REMOTE= +# If remote, start server & change path +if [[ "${PODBIN_NAME:-}" = "remote" ]]; then + REMOTE=1 + echo "$ME: remote tests are not working yet" >&2 + exit 1 +fi + +function die() { + failhint= + echo "$ME: $*" >&2 + exit 1 +} + +# From here on out, any unexpected abort will try to offer helpful hints +failhint= +trap 'if [[ $? != 0 ]]; then if [[ -n $failhint ]]; then echo;echo "***************************************";echo $failhint;echo;echo "Please see $BUD_TEST_DIR_REL/README.md for advice";fi;fi' 0 + +# Find the version of buildah we've vendored in, so we can run the right tests +buildah_version=$(awk "\$1 == \"$BUILDAH_REPO\" { print \$2 }" <go.mod) + +if [[ -z "$buildah_version" ]]; then + # This should not happen + die "Did not find '$BUILDAH_REPO' in go.mod" +fi + +# From here on out, any error is fatal +set -e + +# Before pulling buildah (while still cd'ed to podman repo), try to determine +# if this is a PR, and if so if it's a revendoring of buildah. We use this to +# try to offer a helpful hint on failure. +is_revendor= +if [[ -n $CIRRUS_CHANGE_IN_REPO ]]; then + if [[ -n $DEST_BRANCH ]]; then + head=${CIRRUS_CHANGE_IN_REPO} + # Base of this PR. + base=$(set -x;git merge-base ${DEST_BRANCH} $head) + changes=$(set -x;git diff --name-status $base $head) + if [[ -n $changes ]]; then + if [[ $changes =~ vendor/$BUILDAH_REPO ]]; then + is_revendor=y + fi + fi + fi +fi + +# Pull buildah, including tests +buildah_dir=test-buildah-$buildah_version +if [[ -n $do_checkout ]]; then + if [[ -d $buildah_dir ]]; then + die "Directory already exists: $buildah_dir" + fi + + failhint="'git clone' failed - this should never happen!" + (set -x;git clone -q --branch $buildah_version https://$BUILDAH_REPO $buildah_dir) + + cd $buildah_dir + + # Give it a recognizable tag; this will be useful if we need to update + # the set of patches + (set -x;git tag $BASE_TAG) + + # Build buildah + failhint="error building buildah. This should never happen." + (set -x;make bin/buildah) + + # Apply custom patches. We do this _after_ building, although it shouldn't + # matter because these patches should only apply to test scripts. + failhint=" +Error applying patch file. This can happen when you vendor in a new buildah." + (set -x;git am <$PATCHES) + + failhint= + sed -e "s,\[BASETAG\],${BASE_TAG},g" \ + -e "s,\[BUILDAHREPO\],${BUILDAH_REPO},g" \ + < ${BUD_TEST_DIR}/make-new-buildah-diffs \ + > make-new-buildah-diffs + chmod 755 make-new-buildah-diffs +else + # Called with --no-checkout + test -d $buildah_dir || die "Called with --no-checkout, but $buildah_dir does not exist" + + cd $buildah_dir +fi + +if [[ -n $do_test ]]; then + failhint="Error running buildah bud tests under podman." + if [[ -n $is_revendor ]]; then + failhint+=" + +It looks like you're vendoring in a new buildah. The likely failure +here is that there's a new test in bud.bats that uses functionality +not (yet) in podman build. You will likely need to 'skip' that test. +" + else + failhint+=" + +Is it possible that your PR breaks podman build in some way? Please +review the test failure and double-check your changes. +" + fi + + (set -x;sudo env TMPDIR=/var/tmp \ + PODMAN_BINARY=$PODMAN_BINARY \ + BUILDAH_BINARY=$(pwd)/bin/buildah \ + bats tests/bud.bats) +fi diff --git a/test/python/docker/compat/test_images.py b/test/python/docker/compat/test_images.py index 4a90069a9..571b31881 100644 --- a/test/python/docker/compat/test_images.py +++ b/test/python/docker/compat/test_images.py @@ -1,4 +1,5 @@ import collections +import io import os import subprocess import sys @@ -6,6 +7,7 @@ import time import unittest from docker import DockerClient, errors +from docker.errors import APIError from test.python.docker import Podman from test.python.docker.compat import common, constant @@ -79,9 +81,7 @@ class TestImages(unittest.TestCase): self.assertEqual(len(self.client.images.list()), 2) # List images with filter - self.assertEqual( - len(self.client.images.list(filters={"reference": "alpine"})), 1 - ) + self.assertEqual(len(self.client.images.list(filters={"reference": "alpine"})), 1) def test_search_image(self): """Search for image""" @@ -149,15 +149,22 @@ class TestImages(unittest.TestCase): self.assertEqual(len(self.client.images.list()), 2) + def test_load_corrupt_image(self): + """Import|Load Image failure""" + tarball = io.BytesIO("This is a corrupt tarball".encode("utf-8")) + with self.assertRaises(APIError): + self.client.images.load(tarball) + def test_build_image(self): labels = {"apple": "red", "grape": "green"} - _ = self.client.images.build(path="test/python/docker/build_labels", labels=labels, tag="labels") + _ = self.client.images.build( + path="test/python/docker/build_labels", labels=labels, tag="labels" + ) image = self.client.images.get("labels") self.assertEqual(image.labels["apple"], labels["apple"]) self.assertEqual(image.labels["grape"], labels["grape"]) - if __name__ == "__main__": # Setup temporary space unittest.main() diff --git a/test/system/120-load.bats b/test/system/120-load.bats index 95113c4a6..d29be462d 100644 --- a/test/system/120-load.bats +++ b/test/system/120-load.bats @@ -32,7 +32,7 @@ verify_iid_and_name() { echo "I am an invalid file and should cause a podman-load error" > $invalid run_podman 125 load -i $invalid # podman and podman-remote emit different messages; this is a common string - is "$output" ".*error pulling image: unable to pull .*" \ + is "$output" ".*payload does not match any of the supported image formats .*" \ "load -i INVALID fails with expected diagnostic" } @@ -137,6 +137,13 @@ verify_iid_and_name() { "Diagnostic from 'podman load' without redirection or -i" } +@test "podman load - redirect corrupt payload" { + run_podman 125 load <<< "Danger, Will Robinson!! This is a corrupt tarball!" + is "$output" \ + ".*payload does not match any of the supported image formats .*" \ + "Diagnostic from 'podman load' unknown/corrupt payload" +} + @test "podman load - multi-image archive" { img1="quay.io/libpod/testimage:00000000" img2="quay.io/libpod/testimage:20200902" diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index 51835e4a3..c65449212 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -18,10 +18,6 @@ function teardown() { @test "podman pod top - containers in different PID namespaces" { - if is_remote && is_rootless; then - skip "FIXME: pending #7139" - fi - # With infra=false, we don't get a /pause container (we also # don't pull k8s.gcr.io/pause ) no_infra='--infra=false' @@ -55,10 +51,6 @@ function teardown() { @test "podman pod - communicating between pods" { - if is_remote && is_rootless; then - skip "FIXME: pending #7139" - fi - podname=pod$(random_string) run_podman 1 pod exists $podname run_podman pod create --infra=true --name=$podname @@ -117,10 +109,6 @@ function teardown() { } @test "podman pod - communicating via /dev/shm " { - if is_remote && is_rootless; then - skip "FIXME: pending #7139" - fi - podname=pod$(random_string) run_podman 1 pod exists $podname run_podman pod create --infra=true --name=$podname @@ -168,10 +156,6 @@ function random_ip() { } @test "podman pod create - hashtag AllTheOptions" { - if is_remote && is_rootless; then - skip "FIXME: pending #7139" - fi - mac=$(random_mac) add_host_ip=$(random_ip) add_host_n=$(random_string | tr A-Z a-z).$(random_string | tr A-Z a-z).xyz diff --git a/test/system/220-healthcheck.bats b/test/system/220-healthcheck.bats index 3405029c1..f929c6770 100644 --- a/test/system/220-healthcheck.bats +++ b/test/system/220-healthcheck.bats @@ -25,8 +25,6 @@ function _check_health { @test "podman healthcheck" { - skip_if_remote "FIXME: pending #7137" - # Create an image with a healthcheck script; said script will # pass until the file /uh-oh gets created (by us, via exec) cat >${PODMAN_TMPDIR}/healthcheck <<EOF diff --git a/test/system/410-selinux.bats b/test/system/410-selinux.bats index 49743ff33..4a2c7b7a4 100644 --- a/test/system/410-selinux.bats +++ b/test/system/410-selinux.bats @@ -61,9 +61,6 @@ function check_label() { # SELinux not enabled on Ubuntu, so we should never get here die "WHOA! SELinux enabled, but no /usr/bin/rpm!" fi - if [[ "$cs_version" < "2.146" ]]; then - skip "FIXME: #7939: requires container-selinux-2.146.0 (currently installed: $cs_version)" - fi fi # FIXME FIXME FIXME: delete up to here, leaving just check_label diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index 0d976a6af..4868ad6a0 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -97,7 +97,6 @@ load helpers # "network create" now works rootless, with the help of a special container @test "podman network create" { - skip_if_remote "FIXME: pending #7808" myport=54322 local mynetname=testnet-$(random_string 10) diff --git a/vendor/github.com/coreos/go-systemd/v22/activation/files.go b/vendor/github.com/coreos/go-systemd/v22/activation/files_unix.go index 29dd18def..fc7db98fb 100644 --- a/vendor/github.com/coreos/go-systemd/v22/activation/files.go +++ b/vendor/github.com/coreos/go-systemd/v22/activation/files_unix.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build !windows + // Package activation implements primitives for systemd socket activation. package activation diff --git a/vendor/github.com/coreos/go-systemd/v22/activation/files_windows.go b/vendor/github.com/coreos/go-systemd/v22/activation/files_windows.go new file mode 100644 index 000000000..d391bf00c --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/v22/activation/files_windows.go @@ -0,0 +1,21 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package activation + +import "os" + +func Files(unsetEnv bool) []*os.File { + return nil +} diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go b/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go index 91584a166..e843a4613 100644 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go +++ b/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go @@ -16,6 +16,7 @@ package dbus import ( + "context" "encoding/hex" "fmt" "os" @@ -112,39 +113,63 @@ type Conn struct { // New establishes a connection to any available bus and authenticates. // Callers should call Close() when done with the connection. +// Deprecated: use NewWithContext instead func New() (*Conn, error) { - conn, err := NewSystemConnection() + return NewWithContext(context.Background()) +} + +// NewWithContext same as New with context +func NewWithContext(ctx context.Context) (*Conn, error) { + conn, err := NewSystemConnectionContext(ctx) if err != nil && os.Geteuid() == 0 { - return NewSystemdConnection() + return NewSystemdConnectionContext(ctx) } return conn, err } // NewSystemConnection establishes a connection to the system bus and authenticates. // Callers should call Close() when done with the connection +// Deprecated: use NewSystemConnectionContext instead func NewSystemConnection() (*Conn, error) { + return NewSystemConnectionContext(context.Background()) +} + +// NewSystemConnectionContext same as NewSystemConnection with context +func NewSystemConnectionContext(ctx context.Context) (*Conn, error) { return NewConnection(func() (*dbus.Conn, error) { - return dbusAuthHelloConnection(dbus.SystemBusPrivate) + return dbusAuthHelloConnection(ctx, dbus.SystemBusPrivate) }) } // NewUserConnection establishes a connection to the session bus and // authenticates. This can be used to connect to systemd user instances. // Callers should call Close() when done with the connection. +// Deprecated: use NewUserConnectionContext instead func NewUserConnection() (*Conn, error) { + return NewUserConnectionContext(context.Background()) +} + +// NewUserConnectionContext same as NewUserConnection with context +func NewUserConnectionContext(ctx context.Context) (*Conn, error) { return NewConnection(func() (*dbus.Conn, error) { - return dbusAuthHelloConnection(dbus.SessionBusPrivate) + return dbusAuthHelloConnection(ctx, dbus.SessionBusPrivate) }) } // NewSystemdConnection establishes a private, direct connection to systemd. // This can be used for communicating with systemd without a dbus daemon. // Callers should call Close() when done with the connection. +// Deprecated: use NewSystemdConnectionContext instead func NewSystemdConnection() (*Conn, error) { + return NewSystemdConnectionContext(context.Background()) +} + +// NewSystemdConnectionContext same as NewSystemdConnection with context +func NewSystemdConnectionContext(ctx context.Context) (*Conn, error) { return NewConnection(func() (*dbus.Conn, error) { // We skip Hello when talking directly to systemd. - return dbusAuthConnection(func(opts ...dbus.ConnOption) (*dbus.Conn, error) { - return dbus.Dial("unix:path=/run/systemd/private") + return dbusAuthConnection(ctx, func(opts ...dbus.ConnOption) (*dbus.Conn, error) { + return dbus.Dial("unix:path=/run/systemd/private", opts...) }) }) } @@ -201,8 +226,8 @@ func (c *Conn) GetManagerProperty(prop string) (string, error) { return variant.String(), nil } -func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := createBus() +func dbusAuthConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := createBus(dbus.WithContext(ctx)) if err != nil { return nil, err } @@ -221,8 +246,8 @@ func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, err return conn, nil } -func dbusAuthHelloConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := dbusAuthConnection(createBus) +func dbusAuthHelloConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := dbusAuthConnection(ctx, createBus) if err != nil { return nil, err } diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go b/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go index e38659d7b..01879ba15 100644 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go +++ b/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go @@ -15,6 +15,7 @@ package dbus import ( + "context" "errors" "fmt" "path" @@ -23,6 +24,18 @@ import ( "github.com/godbus/dbus/v5" ) +// Who can be used to specify which process to kill in the unit via the KillUnitWithTarget API +type Who string + +const ( + // All sends the signal to all processes in the unit + All Who = "all" + // Main sends the signal to the main process of the unit + Main Who = "main" + // Control sends the signal to the control process of the unit + Control Who = "control" +) + func (c *Conn) jobComplete(signal *dbus.Signal) { var id uint32 var job dbus.ObjectPath @@ -38,14 +51,14 @@ func (c *Conn) jobComplete(signal *dbus.Signal) { c.jobListener.Unlock() } -func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) { +func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args ...interface{}) (int, error) { if ch != nil { c.jobListener.Lock() defer c.jobListener.Unlock() } var p dbus.ObjectPath - err := c.sysobj.Call(job, 0, args...).Store(&p) + err := c.sysobj.CallWithContext(ctx, job, 0, args...).Store(&p) if err != nil { return 0, err } @@ -90,43 +103,85 @@ func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, // should not be considered authoritative. // // If an error does occur, it will be returned to the user alongside a job ID of 0. +// Deprecated: use StartUnitContext instead func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) + return c.StartUnitContext(context.Background(), name, mode, ch) +} + +// StartUnitContext same as StartUnit with context +func (c *Conn) StartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) } // StopUnit is similar to StartUnit but stops the specified unit rather // than starting it. +// Deprecated: use StopUnitContext instead func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) + return c.StopUnitContext(context.Background(), name, mode, ch) +} + +// StopUnitContext same as StopUnit with context +func (c *Conn) StopUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) } // ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise. +// Deprecated: use ReloadUnitContext instead func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) + return c.ReloadUnitContext(context.Background(), name, mode, ch) +} + +// ReloadUnitContext same as ReloadUnit with context +func (c *Conn) ReloadUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) } // RestartUnit restarts a service. If a service is restarted that isn't // running it will be started. +// Deprecated: use RestartUnitContext instead func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) + return c.RestartUnitContext(context.Background(), name, mode, ch) +} + +// RestartUnitContext same as RestartUnit with context +func (c *Conn) RestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) } // TryRestartUnit is like RestartUnit, except that a service that isn't running // is not affected by the restart. +// Deprecated: use TryRestartUnitContext instead func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) + return c.TryRestartUnitContext(context.Background(), name, mode, ch) +} + +// TryRestartUnitContext same as TryRestartUnit with context +func (c *Conn) TryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) } // ReloadOrRestartUnit attempts a reload if the unit supports it and use a restart // otherwise. +// Deprecated: use ReloadOrRestartUnitContext instead func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) + return c.ReloadOrRestartUnitContext(context.Background(), name, mode, ch) +} + +// ReloadOrRestartUnitContext same as ReloadOrRestartUnit with context +func (c *Conn) ReloadOrRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) } // ReloadOrTryRestartUnit attempts a reload if the unit supports it and use a "Try" // flavored restart otherwise. +// Deprecated: use ReloadOrTryRestartUnitContext instead func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) + return c.ReloadOrTryRestartUnitContext(context.Background(), name, mode, ch) +} + +// ReloadOrTryRestartUnitContext same as ReloadOrTryRestartUnit with context +func (c *Conn) ReloadOrTryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) } // StartTransientUnit() may be used to create and start a transient unit, which @@ -134,28 +189,57 @@ func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string // system is rebooted. name is the unit name including suffix, and must be // unique. mode is the same as in StartUnit(), properties contains properties // of the unit. +// Deprecated: use StartTransientUnitContext instead func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) + return c.StartTransientUnitContext(context.Background(), name, mode, properties, ch) +} + +// StartTransientUnitContext same as StartTransientUnit with context +func (c *Conn) StartTransientUnitContext(ctx context.Context, name string, mode string, properties []Property, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) } // KillUnit takes the unit name and a UNIX signal number to send. All of the unit's // processes are killed. +// Deprecated: use KillUnitContext instead func (c *Conn) KillUnit(name string, signal int32) { - c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store() + c.KillUnitContext(context.Background(), name, signal) +} + +// KillUnitContext same as KillUnit with context +func (c *Conn) KillUnitContext(ctx context.Context, name string, signal int32) { + c.KillUnitWithTarget(ctx, name, All, signal) +} + +// KillUnitWithTarget is like KillUnitContext, but allows you to specify which process in the unit to send the signal to +func (c *Conn) KillUnitWithTarget(ctx context.Context, name string, target Who, signal int32) error { + return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.KillUnit", 0, name, string(target), signal).Store() } // ResetFailedUnit resets the "failed" state of a specific unit. +// Deprecated: use ResetFailedUnitContext instead func (c *Conn) ResetFailedUnit(name string) error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() + return c.ResetFailedUnitContext(context.Background(), name) +} + +// ResetFailedUnitContext same as ResetFailedUnit with context +func (c *Conn) ResetFailedUnitContext(ctx context.Context, name string) error { + return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() } // SystemState returns the systemd state. Equivalent to `systemctl is-system-running`. +// Deprecated: use SystemStateContext instead func (c *Conn) SystemState() (*Property, error) { + return c.SystemStateContext(context.Background()) +} + +// SystemStateContext same as SystemState with context +func (c *Conn) SystemStateContext(ctx context.Context) (*Property, error) { var err error var prop dbus.Variant obj := c.sysconn.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1") - err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop) + err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop) if err != nil { return nil, err } @@ -164,7 +248,7 @@ func (c *Conn) SystemState() (*Property, error) { } // getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface -func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) { +func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) { var err error var props map[string]dbus.Variant @@ -173,7 +257,7 @@ func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[st } obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props) + err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props) if err != nil { return nil, err } @@ -187,23 +271,41 @@ func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[st } // GetUnitProperties takes the (unescaped) unit name and returns all of its dbus object properties. +// Deprecated: use GetUnitPropertiesContext instead func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { + return c.GetUnitPropertiesContext(context.Background(), unit) +} + +// GetUnitPropertiesContext same as GetUnitPropertiesContext with context +func (c *Conn) GetUnitPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { path := unitPath(unit) - return c.getProperties(path, "org.freedesktop.systemd1.Unit") + return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") } // GetUnitPathProperties takes the (escaped) unit path and returns all of its dbus object properties. +// Deprecated: use GetUnitPathPropertiesContext instead func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) { - return c.getProperties(path, "org.freedesktop.systemd1.Unit") + return c.GetUnitPathPropertiesContext(context.Background(), path) +} + +// GetUnitPathPropertiesContext same as GetUnitPathProperties with context +func (c *Conn) GetUnitPathPropertiesContext(ctx context.Context, path dbus.ObjectPath) (map[string]interface{}, error) { + return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") } // GetAllProperties takes the (unescaped) unit name and returns all of its dbus object properties. +// Deprecated: use GetAllPropertiesContext instead func (c *Conn) GetAllProperties(unit string) (map[string]interface{}, error) { + return c.GetAllPropertiesContext(context.Background(), unit) +} + +// GetAllPropertiesContext same as GetAllProperties with context +func (c *Conn) GetAllPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { path := unitPath(unit) - return c.getProperties(path, "") + return c.getProperties(ctx, path, "") } -func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) { +func (c *Conn) getProperty(ctx context.Context, unit string, dbusInterface string, propertyName string) (*Property, error) { var err error var prop dbus.Variant @@ -213,7 +315,7 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin } obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop) + err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop) if err != nil { return nil, err } @@ -221,21 +323,39 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin return &Property{Name: propertyName, Value: prop}, nil } +// Deprecated: use GetUnitPropertyContext instead func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) { - return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName) + return c.GetUnitPropertyContext(context.Background(), unit, propertyName) +} + +// GetUnitPropertyContext same as GetUnitProperty with context +func (c *Conn) GetUnitPropertyContext(ctx context.Context, unit string, propertyName string) (*Property, error) { + return c.getProperty(ctx, unit, "org.freedesktop.systemd1.Unit", propertyName) } // GetServiceProperty returns property for given service name and property name +// Deprecated: use GetServicePropertyContext instead func (c *Conn) GetServiceProperty(service string, propertyName string) (*Property, error) { - return c.getProperty(service, "org.freedesktop.systemd1.Service", propertyName) + return c.GetServicePropertyContext(context.Background(), service, propertyName) +} + +// GetServicePropertyContext same as GetServiceProperty with context +func (c *Conn) GetServicePropertyContext(ctx context.Context, service string, propertyName string) (*Property, error) { + return c.getProperty(ctx, service, "org.freedesktop.systemd1.Service", propertyName) } // GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type. // Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope // return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit +// Deprecated: use GetUnitTypePropertiesContext instead func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) { + return c.GetUnitTypePropertiesContext(context.Background(), unit, unitType) +} + +// GetUnitTypePropertiesContext same as GetUnitTypeProperties with context +func (c *Conn) GetUnitTypePropertiesContext(ctx context.Context, unit string, unitType string) (map[string]interface{}, error) { path := unitPath(unit) - return c.getProperties(path, "org.freedesktop.systemd1."+unitType) + return c.getProperties(ctx, path, "org.freedesktop.systemd1."+unitType) } // SetUnitProperties() may be used to modify certain unit properties at runtime. @@ -245,12 +365,24 @@ func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]i // case the settings only apply until the next reboot. name is the name of the unit // to modify. properties are the settings to set, encoded as an array of property // name and value pairs. +// Deprecated: use SetUnitPropertiesContext instead func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store() + return c.SetUnitPropertiesContext(context.Background(), name, runtime, properties...) } +// SetUnitPropertiesContext same as SetUnitProperties with context +func (c *Conn) SetUnitPropertiesContext(ctx context.Context, name string, runtime bool, properties ...Property) error { + return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store() +} + +// Deprecated: use GetUnitTypePropertyContext instead func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) { - return c.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName) + return c.GetUnitTypePropertyContext(context.Background(), unit, unitType, propertyName) +} + +// GetUnitTypePropertyContext same as GetUnitTypeProperty with context +func (c *Conn) GetUnitTypePropertyContext(ctx context.Context, unit string, unitType string, propertyName string) (*Property, error) { + return c.getProperty(ctx, unit, "org.freedesktop.systemd1."+unitType, propertyName) } type UnitStatus struct { @@ -299,22 +431,40 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { // be more unit names loaded than actual units behind them. // Also note that a unit is only loaded if it is active and/or enabled. // Units that are both disabled and inactive will thus not be returned. +// Deprecated: use ListUnitsContext instead func (c *Conn) ListUnits() ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store) + return c.ListUnitsContext(context.Background()) +} + +// ListUnitsContext same as ListUnits with context +func (c *Conn) ListUnitsContext(ctx context.Context) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnits", 0).Store) } // ListUnitsFiltered returns an array with units filtered by state. // It takes a list of units' statuses to filter. +// Deprecated: use ListUnitsFilteredContext instead func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) + return c.ListUnitsFilteredContext(context.Background(), states) +} + +// ListUnitsFilteredContext same as ListUnitsFiltered with context +func (c *Conn) ListUnitsFilteredContext(ctx context.Context, states []string) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) } // ListUnitsByPatterns returns an array with units. // It takes a list of units' statuses and names to filter. // Note that units may be known by multiple names at the same time, // and hence there might be more unit names loaded than actual units behind them. +// Deprecated: use ListUnitsByPatternsContext instead func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) + return c.ListUnitsByPatternsContext(context.Background(), states, patterns) +} + +// ListUnitsByPatternsContext same as ListUnitsByPatterns with context +func (c *Conn) ListUnitsByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) } // ListUnitsByNames returns an array with units. It takes a list of units' @@ -322,8 +472,14 @@ func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitSt // method, this method returns statuses even for inactive or non-existing // units. Input array should contain exact unit names, but not patterns. // Note: Requires systemd v230 or higher +// Deprecated: use ListUnitsByNamesContext instead func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) + return c.ListUnitsByNamesContext(context.Background(), units) +} + +// ListUnitsByNamesContext same as ListUnitsByNames with context +func (c *Conn) ListUnitsByNamesContext(ctx context.Context, units []string) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) } type UnitFile struct { @@ -358,13 +514,25 @@ func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) { } // ListUnitFiles returns an array of all available units on disk. +// Deprecated: use ListUnitFilesContext instead func (c *Conn) ListUnitFiles() ([]UnitFile, error) { - return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) + return c.ListUnitFilesContext(context.Background()) +} + +// ListUnitFilesContext same as ListUnitFiles with context +func (c *Conn) ListUnitFilesContext(ctx context.Context) ([]UnitFile, error) { + return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) } // ListUnitFilesByPatterns returns an array of all available units on disk matched the patterns. +// Deprecated: use ListUnitFilesByPatternsContext instead func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) { - return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) + return c.ListUnitFilesByPatternsContext(context.Background(), states, patterns) +} + +// ListUnitFilesByPatternsContext same as ListUnitFilesByPatterns with context +func (c *Conn) ListUnitFilesByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitFile, error) { + return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) } type LinkUnitFileChange EnableUnitFileChange @@ -383,9 +551,15 @@ type LinkUnitFileChange EnableUnitFileChange // structures with three strings: the type of the change (one of symlink // or unlink), the file name of the symlink and the destination of the // symlink. +// Deprecated: use LinkUnitFilesContext instead func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { + return c.LinkUnitFilesContext(context.Background(), files, runtime, force) +} + +// LinkUnitFilesContext same as LinkUnitFiles with context +func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) if err != nil { return nil, err } @@ -425,11 +599,17 @@ func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUn // structures with three strings: the type of the change (one of symlink // or unlink), the file name of the symlink and the destination of the // symlink. +// Deprecated: use EnableUnitFilesContext instead func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { + return c.EnableUnitFilesContext(context.Background(), files, runtime, force) +} + +// EnableUnitFilesContext same as EnableUnitFiles with context +func (c *Conn) EnableUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { var carries_install_info bool result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result) if err != nil { return false, nil, err } @@ -471,9 +651,15 @@ type EnableUnitFileChange struct { // consists of structures with three strings: the type of the change (one of // symlink or unlink), the file name of the symlink and the destination of the // symlink. +// Deprecated: use DisableUnitFilesContext instead func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) { + return c.DisableUnitFilesContext(context.Background(), files, runtime) +} + +// DisableUnitFilesContext same as DisableUnitFiles with context +func (c *Conn) DisableUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]DisableUnitFileChange, error) { result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) if err != nil { return nil, err } @@ -512,9 +698,15 @@ type DisableUnitFileChange struct { // * runtime to specify whether the unit was enabled for runtime // only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) // * force flag +// Deprecated: use MaskUnitFilesContext instead func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { + return c.MaskUnitFilesContext(context.Background(), files, runtime, force) +} + +// MaskUnitFilesContext same as MaskUnitFiles with context +func (c *Conn) MaskUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) if err != nil { return nil, err } @@ -552,9 +744,15 @@ type MaskUnitFileChange struct { // the usual unit search paths) // * runtime to specify whether the unit was enabled for runtime // only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) +// Deprecated: use UnmaskUnitFilesContext instead func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileChange, error) { + return c.UnmaskUnitFilesContext(context.Background(), files, runtime) +} + +// UnmaskUnitFilesContext same as UnmaskUnitFiles with context +func (c *Conn) UnmaskUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]UnmaskUnitFileChange, error) { result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) if err != nil { return nil, err } @@ -586,8 +784,14 @@ type UnmaskUnitFileChange struct { // Reload instructs systemd to scan for and reload unit files. This is // equivalent to a 'systemctl daemon-reload'. +// Deprecated: use ReloadContext instead func (c *Conn) Reload() error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store() + return c.ReloadContext(context.Background()) +} + +// ReloadContext same as Reload with context +func (c *Conn) ReloadContext(ctx context.Context) error { + return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.Reload", 0).Store() } func unitPath(name string) dbus.ObjectPath { @@ -598,3 +802,48 @@ func unitPath(name string) dbus.ObjectPath { func unitName(dpath dbus.ObjectPath) string { return pathBusUnescape(path.Base(string(dpath))) } + +// Currently queued job definition +type JobStatus struct { + Id uint32 // The numeric job id + Unit string // The primary unit name for this job + JobType string // The job type as string + Status string // The job state as string + JobPath dbus.ObjectPath // The job object path + UnitPath dbus.ObjectPath // The unit object path +} + +// ListJobs returns an array with all currently queued jobs +// Deprecated: use ListJobsContext instead +func (c *Conn) ListJobs() ([]JobStatus, error) { + return c.ListJobsContext(context.Background()) +} + +// ListJobsContext same as ListJobs with context +func (c *Conn) ListJobsContext(ctx context.Context) ([]JobStatus, error) { + return c.listJobsInternal(ctx) +} + +func (c *Conn) listJobsInternal(ctx context.Context) ([]JobStatus, error) { + result := make([][]interface{}, 0) + if err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListJobs", 0).Store(&result); err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + status := make([]JobStatus, len(result)) + statusInterface := make([]interface{}, len(status)) + for i := range status { + statusInterface[i] = &status[i] + } + + if err := dbus.Store(resultInterface, statusInterface...); err != nil { + return nil, err + } + + return status, nil +} diff --git a/vendor/github.com/coreos/go-systemd/v22/journal/journal.go b/vendor/github.com/coreos/go-systemd/v22/journal/journal.go index a0f4837a0..ac24c7767 100644 --- a/vendor/github.com/coreos/go-systemd/v22/journal/journal.go +++ b/vendor/github.com/coreos/go-systemd/v22/journal/journal.go @@ -23,20 +23,7 @@ package journal import ( - "bytes" - "encoding/binary" - "errors" "fmt" - "io" - "io/ioutil" - "net" - "os" - "strconv" - "strings" - "sync" - "sync/atomic" - "syscall" - "unsafe" ) // Priority of a journal message @@ -53,173 +40,7 @@ const ( PriDebug ) -var ( - // This can be overridden at build-time: - // https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable - journalSocket = "/run/systemd/journal/socket" - - // unixConnPtr atomically holds the local unconnected Unix-domain socket. - // Concrete safe pointer type: *net.UnixConn - unixConnPtr unsafe.Pointer - // onceConn ensures that unixConnPtr is initialized exactly once. - onceConn sync.Once -) - -func init() { - onceConn.Do(initConn) -} - -// Enabled checks whether the local systemd journal is available for logging. -func Enabled() bool { - onceConn.Do(initConn) - - if (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) == nil { - return false - } - - if _, err := net.Dial("unixgram", journalSocket); err != nil { - return false - } - - return true -} - -// Send a message to the local systemd journal. vars is a map of journald -// fields to values. Fields must be composed of uppercase letters, numbers, -// and underscores, but must not start with an underscore. Within these -// restrictions, any arbitrary field name may be used. Some names have special -// significance: see the journalctl documentation -// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) -// for more details. vars may be nil. -func Send(message string, priority Priority, vars map[string]string) error { - conn := (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) - if conn == nil { - return errors.New("could not initialize socket to journald") - } - - socketAddr := &net.UnixAddr{ - Name: journalSocket, - Net: "unixgram", - } - - data := new(bytes.Buffer) - appendVariable(data, "PRIORITY", strconv.Itoa(int(priority))) - appendVariable(data, "MESSAGE", message) - for k, v := range vars { - appendVariable(data, k, v) - } - - _, _, err := conn.WriteMsgUnix(data.Bytes(), nil, socketAddr) - if err == nil { - return nil - } - if !isSocketSpaceError(err) { - return err - } - - // Large log entry, send it via tempfile and ancillary-fd. - file, err := tempFd() - if err != nil { - return err - } - defer file.Close() - _, err = io.Copy(file, data) - if err != nil { - return err - } - rights := syscall.UnixRights(int(file.Fd())) - _, _, err = conn.WriteMsgUnix([]byte{}, rights, socketAddr) - if err != nil { - return err - } - - return nil -} - // Print prints a message to the local systemd journal using Send(). func Print(priority Priority, format string, a ...interface{}) error { return Send(fmt.Sprintf(format, a...), priority, nil) } - -func appendVariable(w io.Writer, name, value string) { - if err := validVarName(name); err != nil { - fmt.Fprintf(os.Stderr, "variable name %s contains invalid character, ignoring\n", name) - } - if strings.ContainsRune(value, '\n') { - /* When the value contains a newline, we write: - * - the variable name, followed by a newline - * - the size (in 64bit little endian format) - * - the data, followed by a newline - */ - fmt.Fprintln(w, name) - binary.Write(w, binary.LittleEndian, uint64(len(value))) - fmt.Fprintln(w, value) - } else { - /* just write the variable and value all on one line */ - fmt.Fprintf(w, "%s=%s\n", name, value) - } -} - -// validVarName validates a variable name to make sure journald will accept it. -// The variable name must be in uppercase and consist only of characters, -// numbers and underscores, and may not begin with an underscore: -// https://www.freedesktop.org/software/systemd/man/sd_journal_print.html -func validVarName(name string) error { - if name == "" { - return errors.New("Empty variable name") - } else if name[0] == '_' { - return errors.New("Variable name begins with an underscore") - } - - for _, c := range name { - if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') { - return errors.New("Variable name contains invalid characters") - } - } - return nil -} - -// isSocketSpaceError checks whether the error is signaling -// an "overlarge message" condition. -func isSocketSpaceError(err error) bool { - opErr, ok := err.(*net.OpError) - if !ok || opErr == nil { - return false - } - - sysErr, ok := opErr.Err.(*os.SyscallError) - if !ok || sysErr == nil { - return false - } - - return sysErr.Err == syscall.EMSGSIZE || sysErr.Err == syscall.ENOBUFS -} - -// tempFd creates a temporary, unlinked file under `/dev/shm`. -func tempFd() (*os.File, error) { - file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX") - if err != nil { - return nil, err - } - err = syscall.Unlink(file.Name()) - if err != nil { - return nil, err - } - return file, nil -} - -// initConn initializes the global `unixConnPtr` socket. -// It is meant to be called exactly once, at program startup. -func initConn() { - autobind, err := net.ResolveUnixAddr("unixgram", "") - if err != nil { - return - } - - sock, err := net.ListenUnixgram("unixgram", autobind) - if err != nil { - return - } - - atomic.StorePointer(&unixConnPtr, unsafe.Pointer(sock)) -} diff --git a/vendor/github.com/coreos/go-systemd/v22/journal/journal_unix.go b/vendor/github.com/coreos/go-systemd/v22/journal/journal_unix.go new file mode 100644 index 000000000..7233ecfc7 --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/v22/journal/journal_unix.go @@ -0,0 +1,208 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !windows + +// Package journal provides write bindings to the local systemd journal. +// It is implemented in pure Go and connects to the journal directly over its +// unix socket. +// +// To read from the journal, see the "sdjournal" package, which wraps the +// sd-journal a C API. +// +// http://www.freedesktop.org/software/systemd/man/systemd-journald.service.html +package journal + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "os" + "strconv" + "strings" + "sync" + "sync/atomic" + "syscall" + "unsafe" +) + +var ( + // This can be overridden at build-time: + // https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable + journalSocket = "/run/systemd/journal/socket" + + // unixConnPtr atomically holds the local unconnected Unix-domain socket. + // Concrete safe pointer type: *net.UnixConn + unixConnPtr unsafe.Pointer + // onceConn ensures that unixConnPtr is initialized exactly once. + onceConn sync.Once +) + +func init() { + onceConn.Do(initConn) +} + +// Enabled checks whether the local systemd journal is available for logging. +func Enabled() bool { + onceConn.Do(initConn) + + if (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) == nil { + return false + } + + if _, err := net.Dial("unixgram", journalSocket); err != nil { + return false + } + + return true +} + +// Send a message to the local systemd journal. vars is a map of journald +// fields to values. Fields must be composed of uppercase letters, numbers, +// and underscores, but must not start with an underscore. Within these +// restrictions, any arbitrary field name may be used. Some names have special +// significance: see the journalctl documentation +// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) +// for more details. vars may be nil. +func Send(message string, priority Priority, vars map[string]string) error { + conn := (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) + if conn == nil { + return errors.New("could not initialize socket to journald") + } + + socketAddr := &net.UnixAddr{ + Name: journalSocket, + Net: "unixgram", + } + + data := new(bytes.Buffer) + appendVariable(data, "PRIORITY", strconv.Itoa(int(priority))) + appendVariable(data, "MESSAGE", message) + for k, v := range vars { + appendVariable(data, k, v) + } + + _, _, err := conn.WriteMsgUnix(data.Bytes(), nil, socketAddr) + if err == nil { + return nil + } + if !isSocketSpaceError(err) { + return err + } + + // Large log entry, send it via tempfile and ancillary-fd. + file, err := tempFd() + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(file, data) + if err != nil { + return err + } + rights := syscall.UnixRights(int(file.Fd())) + _, _, err = conn.WriteMsgUnix([]byte{}, rights, socketAddr) + if err != nil { + return err + } + + return nil +} + +func appendVariable(w io.Writer, name, value string) { + if err := validVarName(name); err != nil { + fmt.Fprintf(os.Stderr, "variable name %s contains invalid character, ignoring\n", name) + } + if strings.ContainsRune(value, '\n') { + /* When the value contains a newline, we write: + * - the variable name, followed by a newline + * - the size (in 64bit little endian format) + * - the data, followed by a newline + */ + fmt.Fprintln(w, name) + binary.Write(w, binary.LittleEndian, uint64(len(value))) + fmt.Fprintln(w, value) + } else { + /* just write the variable and value all on one line */ + fmt.Fprintf(w, "%s=%s\n", name, value) + } +} + +// validVarName validates a variable name to make sure journald will accept it. +// The variable name must be in uppercase and consist only of characters, +// numbers and underscores, and may not begin with an underscore: +// https://www.freedesktop.org/software/systemd/man/sd_journal_print.html +func validVarName(name string) error { + if name == "" { + return errors.New("Empty variable name") + } else if name[0] == '_' { + return errors.New("Variable name begins with an underscore") + } + + for _, c := range name { + if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') { + return errors.New("Variable name contains invalid characters") + } + } + return nil +} + +// isSocketSpaceError checks whether the error is signaling +// an "overlarge message" condition. +func isSocketSpaceError(err error) bool { + opErr, ok := err.(*net.OpError) + if !ok || opErr == nil { + return false + } + + sysErr, ok := opErr.Err.(*os.SyscallError) + if !ok || sysErr == nil { + return false + } + + return sysErr.Err == syscall.EMSGSIZE || sysErr.Err == syscall.ENOBUFS +} + +// tempFd creates a temporary, unlinked file under `/dev/shm`. +func tempFd() (*os.File, error) { + file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX") + if err != nil { + return nil, err + } + err = syscall.Unlink(file.Name()) + if err != nil { + return nil, err + } + return file, nil +} + +// initConn initializes the global `unixConnPtr` socket. +// It is meant to be called exactly once, at program startup. +func initConn() { + autobind, err := net.ResolveUnixAddr("unixgram", "") + if err != nil { + return + } + + sock, err := net.ListenUnixgram("unixgram", autobind) + if err != nil { + return + } + + atomic.StorePointer(&unixConnPtr, unsafe.Pointer(sock)) +} diff --git a/vendor/github.com/coreos/go-systemd/v22/journal/journal_windows.go b/vendor/github.com/coreos/go-systemd/v22/journal/journal_windows.go new file mode 100644 index 000000000..677aca68e --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/v22/journal/journal_windows.go @@ -0,0 +1,35 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package journal provides write bindings to the local systemd journal. +// It is implemented in pure Go and connects to the journal directly over its +// unix socket. +// +// To read from the journal, see the "sdjournal" package, which wraps the +// sd-journal a C API. +// +// http://www.freedesktop.org/software/systemd/man/systemd-journald.service.html +package journal + +import ( + "errors" +) + +func Enabled() bool { + return false +} + +func Send(message string, priority Priority, vars map[string]string) error { + return errors.New("could not initialize socket to journald") +} diff --git a/vendor/github.com/coreos/go-systemd/v22/sdjournal/journal.go b/vendor/github.com/coreos/go-systemd/v22/sdjournal/journal.go index 7f840def8..344016ebe 100644 --- a/vendor/github.com/coreos/go-systemd/v22/sdjournal/journal.go +++ b/vendor/github.com/coreos/go-systemd/v22/sdjournal/journal.go @@ -300,6 +300,24 @@ package sdjournal // return sd_journal_get_catalog(j, ret); // } // +// int +// my_sd_id128_get_boot(void *f, sd_id128_t *boot_id) +// { +// int(*sd_id128_get_boot)(sd_id128_t *); +// +// sd_id128_get_boot = f; +// return sd_id128_get_boot(boot_id); +// } +// +// char * +// my_sd_id128_to_string(void *f, sd_id128_t boot_id, char s[SD_ID128_STRING_MAX]) +// { +// char *(*sd_id128_to_string)(sd_id128_t, char *); +// +// sd_id128_to_string = f; +// return sd_id128_to_string(boot_id, s); +// } +// import "C" import ( "bytes" @@ -928,7 +946,7 @@ func (j *Journal) SeekHead() error { } // SeekTail may be used to seek to the end of the journal, i.e. the most recent -// available entry. This call must be followed by a call to Next before any +// available entry. This call must be followed by a call to Previous before any // call to Get* will return data about the last element. func (j *Journal) SeekTail() error { sd_journal_seek_tail, err := getFunction("sd_journal_seek_tail") @@ -1118,3 +1136,34 @@ func (j *Journal) GetCatalog() (string, error) { return catalog, nil } + +// GetBootID get systemd boot id +func (j *Journal) GetBootID() (string, error) { + sd_id128_get_boot, err := getFunction("sd_id128_get_boot") + if err != nil { + return "", err + } + + var boot_id C.sd_id128_t + r := C.my_sd_id128_get_boot(sd_id128_get_boot, &boot_id) + if r < 0 { + return "", fmt.Errorf("failed to get boot id: %s", syscall.Errno(-r).Error()) + } + + sd_id128_to_string, err := getFunction("sd_id128_to_string") + if err != nil { + return "", err + } + + id128StringMax := C.ulong(C.SD_ID128_STRING_MAX) + c := (*C.char)(C.malloc(id128StringMax)) + defer C.free(unsafe.Pointer(c)) + C.my_sd_id128_to_string(sd_id128_to_string, boot_id, c) + + bootID := C.GoString(c) + if len(bootID) <= 0 { + return "", fmt.Errorf("get boot id %s is not valid", bootID) + } + + return bootID, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 759ce2c16..02c5d7867 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -233,7 +233,7 @@ github.com/containers/storage/types github.com/coreos/go-iptables/iptables # github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e github.com/coreos/go-systemd/activation -# github.com/coreos/go-systemd/v22 v22.1.0 +# github.com/coreos/go-systemd/v22 v22.3.0 github.com/coreos/go-systemd/v22/activation github.com/coreos/go-systemd/v22/daemon github.com/coreos/go-systemd/v22/dbus @@ -750,7 +750,7 @@ gopkg.in/tomb.v1 gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 gopkg.in/yaml.v3 -# k8s.io/api v0.20.1 +# k8s.io/api v0.20.5 k8s.io/api/apps/v1 k8s.io/api/core/v1 # k8s.io/apimachinery v0.20.5 |