From 8df9274e028f50ac4021add2dc90e73fabfa1a28 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Tue, 20 Mar 2018 13:29:40 -0700 Subject: [PATCH 1/3] Remove rktnetes code rktnetes is scheduled to be deprecated in 1.10 (#53601). According to the deprecation policy for beta CLI and flags, we can remove the feature in 1.11. Fixes #58721 --- cmd/kubelet/app/options/container_runtime.go | 3 - hack/.golint_failures | 1 - pkg/kubelet/BUILD | 2 - pkg/kubelet/cadvisor/helpers_linux.go | 2 - pkg/kubelet/cadvisor/util.go | 3 +- pkg/kubelet/config/flags.go | 20 +- pkg/kubelet/kubelet.go | 256 +- pkg/kubelet/rkt/BUILD | 108 - pkg/kubelet/rkt/OWNERS | 3 - pkg/kubelet/rkt/cap.go | 110 - pkg/kubelet/rkt/config.go | 108 - pkg/kubelet/rkt/container_id.go | 55 - pkg/kubelet/rkt/doc.go | 18 - pkg/kubelet/rkt/fake_rkt_interface_test.go | 218 -- pkg/kubelet/rkt/image.go | 294 -- pkg/kubelet/rkt/log.go | 123 - pkg/kubelet/rkt/rkt.go | 2643 ------------------ pkg/kubelet/rkt/rkt_test.go | 2130 -------------- pkg/kubelet/rkt/systemd.go | 92 - pkg/kubelet/rkt/version.go | 111 - pkg/kubelet/sysctl/runtime.go | 9 - pkg/kubelet/types/constants.go | 1 - 22 files changed, 107 insertions(+), 6203 deletions(-) delete mode 100644 pkg/kubelet/rkt/BUILD delete mode 100644 pkg/kubelet/rkt/OWNERS delete mode 100644 pkg/kubelet/rkt/cap.go delete mode 100644 pkg/kubelet/rkt/config.go delete mode 100644 pkg/kubelet/rkt/container_id.go delete mode 100644 pkg/kubelet/rkt/doc.go delete mode 100644 pkg/kubelet/rkt/fake_rkt_interface_test.go delete mode 100644 pkg/kubelet/rkt/image.go delete mode 100644 pkg/kubelet/rkt/log.go delete mode 100644 pkg/kubelet/rkt/rkt.go delete mode 100644 pkg/kubelet/rkt/rkt_test.go delete mode 100644 pkg/kubelet/rkt/systemd.go delete mode 100644 pkg/kubelet/rkt/version.go diff --git a/cmd/kubelet/app/options/container_runtime.go b/cmd/kubelet/app/options/container_runtime.go index 4225e8dd507..63508da3c15 100644 --- a/cmd/kubelet/app/options/container_runtime.go +++ b/cmd/kubelet/app/options/container_runtime.go @@ -29,8 +29,6 @@ const ( // When these values are updated, also update test/e2e/framework/util.go defaultPodSandboxImageName = "k8s.gcr.io/pause" defaultPodSandboxImageVersion = "3.1" - // From pkg/kubelet/rkt/rkt.go to avoid circular import - defaultRktAPIServiceEndpoint = "localhost:15441" ) var ( @@ -54,7 +52,6 @@ func NewContainerRuntimeOptions() *config.ContainerRuntimeOptions { DockerDisableSharedPID: true, PodSandboxImage: defaultPodSandboxImage, ImagePullProgressDeadline: metav1.Duration{Duration: 1 * time.Minute}, - RktAPIEndpoint: defaultRktAPIServiceEndpoint, ExperimentalDockershim: false, } } diff --git a/hack/.golint_failures b/hack/.golint_failures index 2f2baf2eb08..70ddf57a792 100644 --- a/hack/.golint_failures +++ b/hack/.golint_failures @@ -196,7 +196,6 @@ pkg/kubelet/prober/results pkg/kubelet/prober/testing pkg/kubelet/qos pkg/kubelet/remote -pkg/kubelet/rkt pkg/kubelet/secret pkg/kubelet/server pkg/kubelet/server/portforward diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index 6a8b3028001..6662eafe72e 100644 --- a/pkg/kubelet/BUILD +++ b/pkg/kubelet/BUILD @@ -74,7 +74,6 @@ go_library( "//pkg/kubelet/prober:go_default_library", "//pkg/kubelet/prober/results:go_default_library", "//pkg/kubelet/remote:go_default_library", - "//pkg/kubelet/rkt:go_default_library", "//pkg/kubelet/secret:go_default_library", "//pkg/kubelet/server:go_default_library", "//pkg/kubelet/server/portforward:go_default_library", @@ -281,7 +280,6 @@ filegroup( "//pkg/kubelet/prober:all-srcs", "//pkg/kubelet/qos:all-srcs", "//pkg/kubelet/remote:all-srcs", - "//pkg/kubelet/rkt:all-srcs", "//pkg/kubelet/secret:all-srcs", "//pkg/kubelet/server:all-srcs", "//pkg/kubelet/stats:all-srcs", diff --git a/pkg/kubelet/cadvisor/helpers_linux.go b/pkg/kubelet/cadvisor/helpers_linux.go index bff89894c5e..dba38022d25 100644 --- a/pkg/kubelet/cadvisor/helpers_linux.go +++ b/pkg/kubelet/cadvisor/helpers_linux.go @@ -38,8 +38,6 @@ func (i *imageFsInfoProvider) ImageFsInfoLabel() (string, error) { switch i.runtime { case types.DockerContainerRuntime: return cadvisorfs.LabelDockerImages, nil - case types.RktContainerRuntime: - return cadvisorfs.LabelRktImages, nil case types.RemoteContainerRuntime: // This is a temporary workaround to get stats for cri-o from cadvisor // and should be removed. diff --git a/pkg/kubelet/cadvisor/util.go b/pkg/kubelet/cadvisor/util.go index e4107d5b4a7..16596daa9d9 100644 --- a/pkg/kubelet/cadvisor/util.go +++ b/pkg/kubelet/cadvisor/util.go @@ -75,7 +75,6 @@ func EphemeralStorageCapacityFromFsInfo(info cadvisorapi2.FsInfo) v1.ResourceLis // https://github.com/kubernetes/kubernetes/issues/51798 // UsingLegacyCadvisorStats returns true if container stats are provided by cadvisor instead of through the CRI func UsingLegacyCadvisorStats(runtime, runtimeEndpoint string) bool { - return runtime == kubetypes.RktContainerRuntime || - (runtime == kubetypes.DockerContainerRuntime && goruntime.GOOS == "linux") || + return (runtime == kubetypes.DockerContainerRuntime && goruntime.GOOS == "linux") || runtimeEndpoint == CrioSocket } diff --git a/pkg/kubelet/config/flags.go b/pkg/kubelet/config/flags.go index fc8d3a85ba8..b3fdf60c995 100644 --- a/pkg/kubelet/config/flags.go +++ b/pkg/kubelet/config/flags.go @@ -67,16 +67,6 @@ type ContainerRuntimeOptions struct { // CNIBinDir is the full path of the directory in which to search for // CNI plugin binaries CNIBinDir string - - // rkt-specific options. - - // rktPath is the path of rkt binary. Leave empty to use the first rkt in $PATH. - RktPath string - // rktApiEndpoint is the endpoint of the rkt API service to communicate with. - RktAPIEndpoint string - // rktStage1Image is the image to use as stage1. Local paths and - // http/https URLs are supported. - RktStage1Image string } func (s *ContainerRuntimeOptions) AddFlags(fs *pflag.FlagSet) { @@ -95,17 +85,9 @@ func (s *ContainerRuntimeOptions) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.DockerEndpoint, "docker-endpoint", s.DockerEndpoint, "Use this for the docker endpoint to communicate with") fs.DurationVar(&s.ImagePullProgressDeadline.Duration, "image-pull-progress-deadline", s.ImagePullProgressDeadline.Duration, "If no pulling progress is made before this deadline, the image pulling will be cancelled.") - // Network plugin settings. Shared by both docker and rkt. + // Network plugin settings for Docker. fs.StringVar(&s.NetworkPluginName, "network-plugin", s.NetworkPluginName, " The name of the network plugin to be invoked for various events in kubelet/pod lifecycle") fs.StringVar(&s.CNIConfDir, "cni-conf-dir", s.CNIConfDir, " The full path of the directory in which to search for CNI config files. Default: /etc/cni/net.d") fs.StringVar(&s.CNIBinDir, "cni-bin-dir", s.CNIBinDir, " A comma-separated list of full paths of directories in which to search for CNI plugin binaries. Default: /opt/cni/bin") fs.Int32Var(&s.NetworkPluginMTU, "network-plugin-mtu", s.NetworkPluginMTU, " The MTU to be passed to the network plugin, to override the default. Set to 0 to use the default 1460 MTU.") - - // Rkt-specific settings. - fs.StringVar(&s.RktPath, "rkt-path", s.RktPath, "Path of rkt binary. Leave empty to use the first rkt in $PATH. Only used if --container-runtime='rkt'.") - fs.MarkDeprecated("rkt-path", "will be removed in a future version. Rktnetes has been deprecated in favor of rktlet (https://github.com/kubernetes-incubator/rktlet).") - fs.StringVar(&s.RktAPIEndpoint, "rkt-api-endpoint", s.RktAPIEndpoint, "The endpoint of the rkt API service to communicate with. Only used if --container-runtime='rkt'.") - fs.MarkDeprecated("rkt-api-endpoint", "will be removed in a future version. Rktnetes has been deprecated in favor of rktlet (https://github.com/kubernetes-incubator/rktlet).") - fs.StringVar(&s.RktStage1Image, "rkt-stage1-image", s.RktStage1Image, "image to use as stage1. Local paths and http/https URLs are supported. If empty, the 'stage1.aci' in the same directory as '--rkt-path' will be used.") - fs.MarkDeprecated("rkt-stage1-image", "will be removed in a future version. Rktnetes has been deprecated in favor of rktlet (https://github.com/kubernetes-incubator/rktlet).") } diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 7f7d81165b5..57a1d273a3f 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -87,7 +87,6 @@ import ( "k8s.io/kubernetes/pkg/kubelet/prober" proberesults "k8s.io/kubernetes/pkg/kubelet/prober/results" "k8s.io/kubernetes/pkg/kubelet/remote" - "k8s.io/kubernetes/pkg/kubelet/rkt" "k8s.io/kubernetes/pkg/kubelet/secret" "k8s.io/kubernetes/pkg/kubelet/server" serverstats "k8s.io/kubernetes/pkg/kubelet/server/stats" @@ -600,145 +599,104 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, var nl *NoOpLegacyHost pluginSettings.LegacyRuntimeHost = nl - if containerRuntime == kubetypes.RktContainerRuntime { - glog.Warningln("rktnetes has been deprecated in favor of rktlet. Please see https://github.com/kubernetes-incubator/rktlet for more information.") + if containerRuntime == "rkt" { + glog.Fatalln("rktnetes has been deprecated in favor of rktlet. Please see https://github.com/kubernetes-incubator/rktlet for more information.") } - // rktnetes cannot be run with CRI. - if containerRuntime != kubetypes.RktContainerRuntime { - // kubelet defers to the runtime shim to setup networking. Setting - // this to nil will prevent it from trying to invoke the plugin. - // It's easier to always probe and initialize plugins till cri - // becomes the default. - klet.networkPlugin = nil - // if left at nil, that means it is unneeded - var legacyLogProvider kuberuntime.LegacyLogProvider + // kubelet defers to the runtime shim to setup networking. Setting + // this to nil will prevent it from trying to invoke the plugin. + // It's easier to always probe and initialize plugins till cri + // becomes the default. + klet.networkPlugin = nil + // if left at nil, that means it is unneeded + var legacyLogProvider kuberuntime.LegacyLogProvider - switch containerRuntime { - case kubetypes.DockerContainerRuntime: - // Create and start the CRI shim running as a grpc server. - streamingConfig := getStreamingConfig(kubeCfg, kubeDeps) - ds, err := dockershim.NewDockerService(kubeDeps.DockerClientConfig, crOptions.PodSandboxImage, streamingConfig, - &pluginSettings, runtimeCgroups, kubeCfg.CgroupDriver, crOptions.DockershimRootDirectory, - crOptions.DockerDisableSharedPID) - if err != nil { - return nil, err - } - // For now, the CRI shim redirects the streaming requests to the - // kubelet, which handles the requests using DockerService.. - klet.criHandler = ds - - // The unix socket for kubelet <-> dockershim communication. - glog.V(5).Infof("RemoteRuntimeEndpoint: %q, RemoteImageEndpoint: %q", - remoteRuntimeEndpoint, - remoteImageEndpoint) - glog.V(2).Infof("Starting the GRPC server for the docker CRI shim.") - server := dockerremote.NewDockerServer(remoteRuntimeEndpoint, ds) - if err := server.Start(); err != nil { - return nil, err - } - - // Create dockerLegacyService when the logging driver is not supported. - supported, err := ds.IsCRISupportedLogDriver() - if err != nil { - return nil, err - } - if !supported { - klet.dockerLegacyService = ds - legacyLogProvider = ds - } - case kubetypes.RemoteContainerRuntime: - // No-op. - break - default: - return nil, fmt.Errorf("unsupported CRI runtime: %q", containerRuntime) - } - runtimeService, imageService, err := getRuntimeAndImageServices(remoteRuntimeEndpoint, remoteImageEndpoint, kubeCfg.RuntimeRequestTimeout) + switch containerRuntime { + case kubetypes.DockerContainerRuntime: + // Create and start the CRI shim running as a grpc server. + streamingConfig := getStreamingConfig(kubeCfg, kubeDeps) + ds, err := dockershim.NewDockerService(kubeDeps.DockerClientConfig, crOptions.PodSandboxImage, streamingConfig, + &pluginSettings, runtimeCgroups, kubeCfg.CgroupDriver, crOptions.DockershimRootDirectory, + crOptions.DockerDisableSharedPID) if err != nil { return nil, err } - klet.runtimeService = runtimeService - runtime, err := kuberuntime.NewKubeGenericRuntimeManager( - kubecontainer.FilterEventRecorder(kubeDeps.Recorder), - klet.livenessManager, - seccompProfileRoot, - containerRefManager, - machineInfo, - klet, - kubeDeps.OSInterface, - klet, - httpClient, - imageBackOff, - kubeCfg.SerializeImagePulls, - float32(kubeCfg.RegistryPullQPS), - int(kubeCfg.RegistryBurst), - kubeCfg.CPUCFSQuota, - runtimeService, - imageService, - kubeDeps.ContainerManager.InternalContainerLifecycle(), - legacyLogProvider, - ) - if err != nil { - return nil, err - } - klet.containerRuntime = runtime - klet.runner = runtime + // For now, the CRI shim redirects the streaming requests to the + // kubelet, which handles the requests using DockerService.. + klet.criHandler = ds - if cadvisor.UsingLegacyCadvisorStats(containerRuntime, remoteRuntimeEndpoint) { - klet.StatsProvider = stats.NewCadvisorStatsProvider( - klet.cadvisor, - klet.resourceAnalyzer, - klet.podManager, - klet.runtimeCache, - klet.containerRuntime) - } else { - klet.StatsProvider = stats.NewCRIStatsProvider( - klet.cadvisor, - klet.resourceAnalyzer, - klet.podManager, - klet.runtimeCache, - runtimeService, - imageService, - stats.NewLogMetricsService()) + // The unix socket for kubelet <-> dockershim communication. + glog.V(5).Infof("RemoteRuntimeEndpoint: %q, RemoteImageEndpoint: %q", + remoteRuntimeEndpoint, + remoteImageEndpoint) + glog.V(2).Infof("Starting the GRPC server for the docker CRI shim.") + server := dockerremote.NewDockerServer(remoteRuntimeEndpoint, ds) + if err := server.Start(); err != nil { + return nil, err } - } else { - // rkt uses the legacy, non-CRI, integration. Configure it the old way. - // TODO: Include hairpin mode settings in rkt? - conf := &rkt.Config{ - Path: crOptions.RktPath, - Stage1Image: crOptions.RktStage1Image, - InsecureOptions: "image,ondisk", - } - runtime, err := rkt.New( - crOptions.RktAPIEndpoint, - conf, - klet, - kubeDeps.Recorder, - containerRefManager, - klet, - klet.livenessManager, - httpClient, - klet.networkPlugin, - hairpinMode == kubeletconfiginternal.HairpinVeth, - utilexec.New(), - kubecontainer.RealOS{}, - imageBackOff, - kubeCfg.SerializeImagePulls, - float32(kubeCfg.RegistryPullQPS), - int(kubeCfg.RegistryBurst), - kubeCfg.RuntimeRequestTimeout.Duration, - ) + + // Create dockerLegacyService when the logging driver is not supported. + supported, err := ds.IsCRISupportedLogDriver() if err != nil { return nil, err } - klet.containerRuntime = runtime - klet.runner = kubecontainer.DirectStreamingRunner(runtime) + if !supported { + klet.dockerLegacyService = ds + legacyLogProvider = ds + } + case kubetypes.RemoteContainerRuntime: + // No-op. + break + default: + return nil, fmt.Errorf("unsupported CRI runtime: %q", containerRuntime) + } + runtimeService, imageService, err := getRuntimeAndImageServices(remoteRuntimeEndpoint, remoteImageEndpoint, kubeCfg.RuntimeRequestTimeout) + if err != nil { + return nil, err + } + klet.runtimeService = runtimeService + runtime, err := kuberuntime.NewKubeGenericRuntimeManager( + kubecontainer.FilterEventRecorder(kubeDeps.Recorder), + klet.livenessManager, + seccompProfileRoot, + containerRefManager, + machineInfo, + klet, + kubeDeps.OSInterface, + klet, + httpClient, + imageBackOff, + kubeCfg.SerializeImagePulls, + float32(kubeCfg.RegistryPullQPS), + int(kubeCfg.RegistryBurst), + kubeCfg.CPUCFSQuota, + runtimeService, + imageService, + kubeDeps.ContainerManager.InternalContainerLifecycle(), + legacyLogProvider, + ) + if err != nil { + return nil, err + } + klet.containerRuntime = runtime + klet.runner = runtime + + if cadvisor.UsingLegacyCadvisorStats(containerRuntime, remoteRuntimeEndpoint) { klet.StatsProvider = stats.NewCadvisorStatsProvider( klet.cadvisor, klet.resourceAnalyzer, klet.podManager, klet.runtimeCache, klet.containerRuntime) + } else { + klet.StatsProvider = stats.NewCRIStatsProvider( + klet.cadvisor, + klet.resourceAnalyzer, + klet.podManager, + klet.runtimeCache, + runtimeService, + imageService, + stats.NewLogMetricsService()) } klet.pleg = pleg.NewGenericPLEG(klet.containerRuntime, plegChannelCapacity, plegRelistPeriod, klet.podCache, clock.RealClock{}) @@ -2108,34 +2066,30 @@ func (kl *Kubelet) updateRuntimeUp() { glog.Errorf("Container runtime sanity check failed: %v", err) return } - // rkt uses the legacy, non-CRI integration. Don't check the runtime - // conditions for it. - if kl.containerRuntimeName != kubetypes.RktContainerRuntime { - if s == nil { - glog.Errorf("Container runtime status is nil") - return - } - // Periodically log the whole runtime status for debugging. - // TODO(random-liu): Consider to send node event when optional - // condition is unmet. - glog.V(4).Infof("Container runtime status: %v", s) - networkReady := s.GetRuntimeCondition(kubecontainer.NetworkReady) - if networkReady == nil || !networkReady.Status { - glog.Errorf("Container runtime network not ready: %v", networkReady) - kl.runtimeState.setNetworkState(fmt.Errorf("runtime network not ready: %v", networkReady)) - } else { - // Set nil if the container runtime network is ready. - kl.runtimeState.setNetworkState(nil) - } - // TODO(random-liu): Add runtime error in runtimeState, and update it - // when runtime is not ready, so that the information in RuntimeReady - // condition will be propagated to NodeReady condition. - runtimeReady := s.GetRuntimeCondition(kubecontainer.RuntimeReady) - // If RuntimeReady is not set or is false, report an error. - if runtimeReady == nil || !runtimeReady.Status { - glog.Errorf("Container runtime not ready: %v", runtimeReady) - return - } + if s == nil { + glog.Errorf("Container runtime status is nil") + return + } + // Periodically log the whole runtime status for debugging. + // TODO(random-liu): Consider to send node event when optional + // condition is unmet. + glog.V(4).Infof("Container runtime status: %v", s) + networkReady := s.GetRuntimeCondition(kubecontainer.NetworkReady) + if networkReady == nil || !networkReady.Status { + glog.Errorf("Container runtime network not ready: %v", networkReady) + kl.runtimeState.setNetworkState(fmt.Errorf("runtime network not ready: %v", networkReady)) + } else { + // Set nil if the container runtime network is ready. + kl.runtimeState.setNetworkState(nil) + } + // TODO(random-liu): Add runtime error in runtimeState, and update it + // when runtime is not ready, so that the information in RuntimeReady + // condition will be propagated to NodeReady condition. + runtimeReady := s.GetRuntimeCondition(kubecontainer.RuntimeReady) + // If RuntimeReady is not set or is false, report an error. + if runtimeReady == nil || !runtimeReady.Status { + glog.Errorf("Container runtime not ready: %v", runtimeReady) + return } kl.oneTimeInitializer.Do(kl.initializeRuntimeDependentModules) kl.runtimeState.setRuntimeSync(kl.clock.Now()) diff --git a/pkg/kubelet/rkt/BUILD b/pkg/kubelet/rkt/BUILD deleted file mode 100644 index efd1a3de510..00000000000 --- a/pkg/kubelet/rkt/BUILD +++ /dev/null @@ -1,108 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) - -go_library( - name = "go_default_library", - srcs = [ - "cap.go", - "config.go", - "container_id.go", - "doc.go", - "image.go", - "log.go", - "rkt.go", - "systemd.go", - "version.go", - ], - importpath = "k8s.io/kubernetes/pkg/kubelet/rkt", - deps = [ - "//pkg/credentialprovider:go_default_library", - "//pkg/credentialprovider/secrets:go_default_library", - "//pkg/kubelet/container:go_default_library", - "//pkg/kubelet/events:go_default_library", - "//pkg/kubelet/images:go_default_library", - "//pkg/kubelet/leaky:go_default_library", - "//pkg/kubelet/lifecycle:go_default_library", - "//pkg/kubelet/network:go_default_library", - "//pkg/kubelet/network/hairpin:go_default_library", - "//pkg/kubelet/prober/results:go_default_library", - "//pkg/kubelet/types:go_default_library", - "//pkg/kubelet/util/format:go_default_library", - "//pkg/securitycontext:go_default_library", - "//pkg/util/parsers:go_default_library", - "//pkg/util/selinux:go_default_library", - "//pkg/util/strings:go_default_library", - "//pkg/util/term:go_default_library", - "//pkg/util/version:go_default_library", - "//vendor/github.com/appc/spec/schema:go_default_library", - "//vendor/github.com/appc/spec/schema/types:go_default_library", - "//vendor/github.com/coreos/go-systemd/dbus:go_default_library", - "//vendor/github.com/coreos/go-systemd/unit:go_default_library", - "//vendor/github.com/coreos/rkt/api/v1alpha:go_default_library", - "//vendor/github.com/docker/docker/api/types:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/google.golang.org/grpc:go_default_library", - "//vendor/k8s.io/api/core/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//vendor/k8s.io/client-go/tools/record:go_default_library", - "//vendor/k8s.io/client-go/tools/remotecommand:go_default_library", - "//vendor/k8s.io/client-go/util/flowcontrol:go_default_library", - "//vendor/k8s.io/utils/exec:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = [ - "fake_rkt_interface_test.go", - "rkt_test.go", - ], - embed = [":go_default_library"], - deps = [ - "//pkg/kubelet/container:go_default_library", - "//pkg/kubelet/container/testing:go_default_library", - "//pkg/kubelet/lifecycle:go_default_library", - "//pkg/kubelet/network:go_default_library", - "//pkg/kubelet/network/kubenet:go_default_library", - "//pkg/kubelet/network/testing:go_default_library", - "//pkg/kubelet/types:go_default_library", - "//vendor/github.com/appc/spec/schema:go_default_library", - "//vendor/github.com/appc/spec/schema/types:go_default_library", - "//vendor/github.com/coreos/go-systemd/dbus:go_default_library", - "//vendor/github.com/coreos/go-systemd/unit:go_default_library", - "//vendor/github.com/coreos/rkt/api/v1alpha:go_default_library", - "//vendor/github.com/golang/mock/gomock:go_default_library", - "//vendor/github.com/stretchr/testify/assert:go_default_library", - "//vendor/google.golang.org/grpc:go_default_library", - "//vendor/k8s.io/api/core/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", - "//vendor/k8s.io/client-go/util/testing:go_default_library", - "//vendor/k8s.io/utils/exec:go_default_library", - "//vendor/k8s.io/utils/exec/testing:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], -) diff --git a/pkg/kubelet/rkt/OWNERS b/pkg/kubelet/rkt/OWNERS deleted file mode 100644 index 9b15beaf072..00000000000 --- a/pkg/kubelet/rkt/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -approvers: -- euank -- yifan-gu diff --git a/pkg/kubelet/rkt/cap.go b/pkg/kubelet/rkt/cap.go deleted file mode 100644 index bbf7cdb552f..00000000000 --- a/pkg/kubelet/rkt/cap.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 rkt - -// TODO(yifan): Export this to higher level package. -const ( - CAP_CHOWN = iota - CAP_DAC_OVERRIDE - CAP_DAC_READ_SEARCH - CAP_FOWNER - CAP_FSETID - CAP_KILL - CAP_SETGID - CAP_SETUID - CAP_SETPCAP - CAP_LINUX_IMMUTABLE - CAP_NET_BIND_SERVICE - CAP_NET_BROADCAST - CAP_NET_ADMIN - CAP_NET_RAW - CAP_IPC_LOCK - CAP_IPC_OWNER - CAP_SYS_MODULE - CAP_SYS_RAWIO - CAP_SYS_CHROOT - CAP_SYS_PTRACE - CAP_SYS_PACCT - CAP_SYS_ADMIN - CAP_SYS_BOOT - CAP_SYS_NICE - CAP_SYS_RESOURCE - CAP_SYS_TIME - CAP_SYS_TTY_CONFIG - CAP_MKNOD - CAP_LEASE - CAP_AUDIT_WRITE - CAP_AUDIT_CONTROL - CAP_SETFCAP - CAP_MAC_OVERRIDE - CAP_MAC_ADMIN - CAP_SYSLOG - CAP_WAKE_ALARM - CAP_BLOCK_SUSPEND - CAP_AUDIT_READ -) - -// TODO(yifan): Export this to higher level package. -var capabilityList = map[int]string{ - CAP_CHOWN: "CAP_CHOWN", - CAP_DAC_OVERRIDE: "CAP_DAC_OVERRIDE", - CAP_DAC_READ_SEARCH: "CAP_DAC_READ_SEARCH", - CAP_FOWNER: "CAP_FOWNER", - CAP_FSETID: "CAP_FSETID", - CAP_KILL: "CAP_KILL", - CAP_SETGID: "CAP_SETGID", - CAP_SETUID: "CAP_SETUID", - CAP_SETPCAP: "CAP_SETPCAP", - CAP_LINUX_IMMUTABLE: "CAP_LINUX_IMMUTABLE", - CAP_NET_BIND_SERVICE: "CAP_NET_BIND_SERVICE", - CAP_NET_BROADCAST: "CAP_NET_BROADCAST", - CAP_NET_ADMIN: "CAP_NET_ADMIN", - CAP_NET_RAW: "CAP_NET_RAW", - CAP_IPC_LOCK: "CAP_IPC_LOCK", - CAP_IPC_OWNER: "CAP_IPC_OWNER", - CAP_SYS_MODULE: "CAP_SYS_MODULE", - CAP_SYS_RAWIO: "CAP_SYS_RAWIO", - CAP_SYS_CHROOT: "CAP_SYS_CHROOT", - CAP_SYS_PTRACE: "CAP_SYS_PTRACE", - CAP_SYS_PACCT: "CAP_SYS_PACCT", - CAP_SYS_ADMIN: "CAP_SYS_ADMIN", - CAP_SYS_BOOT: "CAP_SYS_BOOT", - CAP_SYS_NICE: "CAP_SYS_NICE", - CAP_SYS_RESOURCE: "CAP_SYS_RESOURCE", - CAP_SYS_TIME: "CAP_SYS_TIME", - CAP_SYS_TTY_CONFIG: "CAP_SYS_TTY_CONFIG", - CAP_MKNOD: "CAP_MKNOD", - CAP_LEASE: "CAP_LEASE", - CAP_AUDIT_WRITE: "CAP_AUDIT_WRITE", - CAP_AUDIT_CONTROL: "CAP_AUDIT_CONTROL", - CAP_SETFCAP: "CAP_SETFCAP", - CAP_MAC_OVERRIDE: "CAP_MAC_OVERRIDE", - CAP_MAC_ADMIN: "CAP_MAC_ADMIN", - CAP_SYSLOG: "CAP_SYSLOG", - CAP_WAKE_ALARM: "CAP_WAKE_ALARM", - CAP_BLOCK_SUSPEND: "CAP_BLOCK_SUSPEND", - CAP_AUDIT_READ: "CAP_AUDIT_READ", -} - -// allCapabilities returns the capability list with all capabilities. -func allCapabilities() []string { - var capabilities []string - for _, cap := range capabilityList { - capabilities = append(capabilities, cap) - } - return capabilities -} diff --git a/pkg/kubelet/rkt/config.go b/pkg/kubelet/rkt/config.go deleted file mode 100644 index 993b79b4fc4..00000000000 --- a/pkg/kubelet/rkt/config.go +++ /dev/null @@ -1,108 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 rkt - -import ( - "context" - "fmt" - - rktapi "github.com/coreos/rkt/api/v1alpha" -) - -// Config stores the global configuration for the rkt runtime. -// Detailed documents can be found at: -// https://github.com/coreos/rkt/blob/master/Documentation/commands.md#global-options -type Config struct { - // The absolute path to the binary, or leave empty to find it in $PATH. - Path string - // The rkt data directory. - Dir string - // The image to use as stage1. - Stage1Image string - // The debug flag for rkt. - Debug bool - // Comma-separated list of security features to disable. - // Allowed values: "none", "image", "tls", "ondisk", "http", "all". - InsecureOptions string - // The local config directory. - LocalConfigDir string - // The user config directory. - UserConfigDir string - // The system config directory. - SystemConfigDir string -} - -// buildGlobalOptions returns an array of global command line options. -func (c *Config) buildGlobalOptions() []string { - var result []string - if c == nil { - return result - } - - if c.Debug { - result = append(result, "--debug=true") - } - if c.InsecureOptions != "" { - result = append(result, fmt.Sprintf("--insecure-options=%s", c.InsecureOptions)) - } - if c.LocalConfigDir != "" { - result = append(result, fmt.Sprintf("--local-config=%s", c.LocalConfigDir)) - } - if c.UserConfigDir != "" { - result = append(result, fmt.Sprintf("--user-config=%s", c.UserConfigDir)) - } - if c.SystemConfigDir != "" { - result = append(result, fmt.Sprintf("--system-config=%s", c.SystemConfigDir)) - } - if c.Dir != "" { - result = append(result, fmt.Sprintf("--dir=%s", c.Dir)) - } - return result -} - -// getConfig gets configurations from the rkt API service -// and merge it with the existing config. The merge rule is -// that the fields in the provided config will override the -// result that get from the rkt api service. -func (r *Runtime) getConfig(cfg *Config) (*Config, error) { - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - resp, err := r.apisvc.GetInfo(ctx, &rktapi.GetInfoRequest{}) - if err != nil { - return nil, err - } - - flags := resp.Info.GlobalFlags - - if flags.Dir != "" { - cfg.Dir = flags.Dir - } - if flags.LocalConfigDir != "" { - cfg.LocalConfigDir = flags.LocalConfigDir - } - if flags.UserConfigDir != "" { - cfg.UserConfigDir = flags.UserConfigDir - } - if flags.SystemConfigDir != "" { - cfg.SystemConfigDir = flags.SystemConfigDir - } - if flags.InsecureFlags != "" { - cfg.InsecureOptions = fmt.Sprintf("%s,%s", cfg.InsecureOptions, flags.InsecureFlags) - } - - return cfg, nil -} diff --git a/pkg/kubelet/rkt/container_id.go b/pkg/kubelet/rkt/container_id.go deleted file mode 100644 index ac37c1815c1..00000000000 --- a/pkg/kubelet/rkt/container_id.go +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 rkt - -import ( - "fmt" - "strings" - - kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" -) - -// containerID defines the ID of rkt containers, it will -// be returned to kubelet, and kubelet will use this for -// container level operations. -type containerID struct { - uuid string // rkt uuid of the pod. - appName string // Name of the app in that pod. -} - -// buildContainerID constructs the containers's ID using containerID, -// which consists of the pod uuid and the container name. -// The result can be used to uniquely identify a container. -func buildContainerID(c *containerID) kubecontainer.ContainerID { - return kubecontainer.ContainerID{ - Type: RktType, - ID: fmt.Sprintf("%s:%s", c.uuid, c.appName), - } -} - -// parseContainerID parses the containerID into pod uuid and the container name. The -// results can be used to get more information of the container. -func parseContainerID(id kubecontainer.ContainerID) (*containerID, error) { - tuples := strings.Split(id.ID, ":") - if len(tuples) != 2 { - return nil, fmt.Errorf("rkt: cannot parse container ID for: %q, required format is [UUID:APPNAME]", id) - } - return &containerID{ - uuid: tuples[0], - appName: tuples[1], - }, nil -} diff --git a/pkg/kubelet/rkt/doc.go b/pkg/kubelet/rkt/doc.go deleted file mode 100644 index ac3ca36369d..00000000000 --- a/pkg/kubelet/rkt/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 rkt contains the Containerruntime interface implementation for rkt. -package rkt // import "k8s.io/kubernetes/pkg/kubelet/rkt" diff --git a/pkg/kubelet/rkt/fake_rkt_interface_test.go b/pkg/kubelet/rkt/fake_rkt_interface_test.go deleted file mode 100644 index 077e4ebd8b8..00000000000 --- a/pkg/kubelet/rkt/fake_rkt_interface_test.go +++ /dev/null @@ -1,218 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 rkt - -import ( - "context" - "fmt" - "strconv" - "strings" - "sync" - - "github.com/coreos/go-systemd/dbus" - rktapi "github.com/coreos/rkt/api/v1alpha" - "google.golang.org/grpc" - "k8s.io/apimachinery/pkg/types" - kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" -) - -// fakeRktInterface mocks the rktapi.PublicAPIClient interface for testing purpose. -type fakeRktInterface struct { - sync.Mutex - info rktapi.Info - images []*rktapi.Image - podFilters []*rktapi.PodFilter - pods []*rktapi.Pod - called []string - err error -} - -func newFakeRktInterface() *fakeRktInterface { - return &fakeRktInterface{} -} - -func (f *fakeRktInterface) CleanCalls() { - f.Lock() - defer f.Unlock() - f.called = nil -} - -func (f *fakeRktInterface) GetInfo(ctx context.Context, in *rktapi.GetInfoRequest, opts ...grpc.CallOption) (*rktapi.GetInfoResponse, error) { - f.Lock() - defer f.Unlock() - - f.called = append(f.called, "GetInfo") - return &rktapi.GetInfoResponse{Info: &f.info}, f.err -} - -func (f *fakeRktInterface) ListPods(ctx context.Context, in *rktapi.ListPodsRequest, opts ...grpc.CallOption) (*rktapi.ListPodsResponse, error) { - f.Lock() - defer f.Unlock() - - f.called = append(f.called, "ListPods") - f.podFilters = in.Filters - return &rktapi.ListPodsResponse{Pods: f.pods}, f.err -} - -func (f *fakeRktInterface) InspectPod(ctx context.Context, in *rktapi.InspectPodRequest, opts ...grpc.CallOption) (*rktapi.InspectPodResponse, error) { - f.Lock() - defer f.Unlock() - - f.called = append(f.called, "InspectPod") - for _, pod := range f.pods { - if pod.Id == in.Id { - return &rktapi.InspectPodResponse{Pod: pod}, f.err - } - } - return &rktapi.InspectPodResponse{}, fmt.Errorf("pod %q not found", in.Id) -} - -func (f *fakeRktInterface) ListImages(ctx context.Context, in *rktapi.ListImagesRequest, opts ...grpc.CallOption) (*rktapi.ListImagesResponse, error) { - f.Lock() - defer f.Unlock() - - f.called = append(f.called, "ListImages") - return &rktapi.ListImagesResponse{Images: f.images}, f.err -} - -func (f *fakeRktInterface) InspectImage(ctx context.Context, in *rktapi.InspectImageRequest, opts ...grpc.CallOption) (*rktapi.InspectImageResponse, error) { - return nil, fmt.Errorf("Not implemented") -} - -func (f *fakeRktInterface) ListenEvents(ctx context.Context, in *rktapi.ListenEventsRequest, opts ...grpc.CallOption) (rktapi.PublicAPI_ListenEventsClient, error) { - return nil, fmt.Errorf("Not implemented") -} - -func (f *fakeRktInterface) GetLogs(ctx context.Context, in *rktapi.GetLogsRequest, opts ...grpc.CallOption) (rktapi.PublicAPI_GetLogsClient, error) { - return nil, fmt.Errorf("Not implemented") -} - -// fakeSystemd mocks the systemdInterface for testing purpose. -// TODO(yifan): Remove this once we have a package for launching rkt pods. -// See https://github.com/coreos/rkt/issues/1769. -type fakeSystemd struct { - sync.Mutex - called []string - resetFailedUnits []string - version string - err error -} - -func newFakeSystemd() *fakeSystemd { - return &fakeSystemd{} -} - -func (f *fakeSystemd) CleanCalls() { - f.Lock() - defer f.Unlock() - f.called = nil -} - -func (f *fakeSystemd) Version() (systemdVersion, error) { - f.Lock() - defer f.Unlock() - - f.called = append(f.called, "Version") - v, _ := strconv.Atoi(f.version) - return systemdVersion(v), f.err -} - -func (f *fakeSystemd) ListUnits() ([]dbus.UnitStatus, error) { - return nil, fmt.Errorf("Not implemented") -} - -func (f *fakeSystemd) StopUnit(name string, mode string, ch chan<- string) (int, error) { - return 0, fmt.Errorf("Not implemented") -} - -func (f *fakeSystemd) RestartUnit(name string, mode string, ch chan<- string) (int, error) { - return 0, fmt.Errorf("Not implemented") -} - -func (f *fakeSystemd) ResetFailedUnit(name string) error { - f.called = append(f.called, "ResetFailedUnit") - f.resetFailedUnits = append(f.resetFailedUnits, name) - return f.err -} - -type fakeRktCli struct { - sync.Mutex - cmds []string - result []string - err error -} - -func newFakeRktCli() *fakeRktCli { - return &fakeRktCli{ - cmds: []string{}, - result: []string{}, - } -} - -func (f *fakeRktCli) RunCommand(config *Config, args ...string) (result []string, err error) { - f.Lock() - defer f.Unlock() - cmd := append([]string{"rkt"}, args...) - f.cmds = append(f.cmds, strings.Join(cmd, " ")) - return f.result, f.err -} - -func (f *fakeRktCli) Reset() { - f.cmds = []string{} - f.result = []string{} - f.err = nil -} - -type fakePodDeletionProvider struct { - pods map[types.UID]struct{} -} - -func newFakePodDeletionProvider() *fakePodDeletionProvider { - return &fakePodDeletionProvider{ - pods: make(map[types.UID]struct{}), - } -} - -func (f *fakePodDeletionProvider) IsPodDeleted(uid types.UID) bool { - _, found := f.pods[uid] - return !found -} - -type fakeUnitGetter struct { - networkNamespace kubecontainer.ContainerID -} - -func newfakeUnitGetter() *fakeUnitGetter { - return &fakeUnitGetter{ - networkNamespace: kubecontainer.ContainerID{}, - } -} - -func (f *fakeUnitGetter) getNetworkNamespace(uid types.UID, latestPod *rktapi.Pod) (kubecontainer.ContainerID, error) { - return kubecontainer.ContainerID{ID: "42"}, nil -} - -func (f *fakeUnitGetter) getKubernetesDirective(serviceFilePath string) (podServiceDirective, error) { - podService := podServiceDirective{ - id: "fake", - name: "fake", - namespace: "fake", - hostNetwork: true, - networkNamespace: kubecontainer.ContainerID{ID: "42"}, - } - return podService, nil -} diff --git a/pkg/kubelet/rkt/image.go b/pkg/kubelet/rkt/image.go deleted file mode 100644 index 25d17ca8e0b..00000000000 --- a/pkg/kubelet/rkt/image.go +++ /dev/null @@ -1,294 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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. -*/ - -// This file contains all image related functions for rkt runtime. -package rkt - -import ( - "context" - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "sort" - "strings" - - appcschema "github.com/appc/spec/schema" - appctypes "github.com/appc/spec/schema/types" - rktapi "github.com/coreos/rkt/api/v1alpha" - dockertypes "github.com/docker/docker/api/types" - "github.com/golang/glog" - - "k8s.io/api/core/v1" - "k8s.io/kubernetes/pkg/credentialprovider" - credentialprovidersecrets "k8s.io/kubernetes/pkg/credentialprovider/secrets" - kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" - "k8s.io/kubernetes/pkg/util/parsers" -) - -// PullImage invokes 'rkt fetch' to download an aci. -// TODO(yifan): Now we only support docker images, this should be changed -// once the format of image is landed, see: -// -// http://issue.k8s.io/7203 -// -func (r *Runtime) PullImage(image kubecontainer.ImageSpec, pullSecrets []v1.Secret) (string, error) { - img := image.Image - // TODO(yifan): The credential operation is a copy from dockertools package, - // Need to resolve the code duplication. - repoToPull, _, _, err := parsers.ParseImageName(img) - if err != nil { - return "", err - } - - keyring, err := credentialprovidersecrets.MakeDockerKeyring(pullSecrets, r.dockerKeyring) - if err != nil { - return "", err - } - - creds, ok := keyring.Lookup(repoToPull) - if !ok { - glog.V(1).Infof("Pulling image %s without credentials", img) - } - - userConfigDir, err := ioutil.TempDir("", "rktnetes-user-config-dir-") - if err != nil { - return "", fmt.Errorf("rkt: Cannot create a temporary user-config directory: %v", err) - } - defer os.RemoveAll(userConfigDir) - - config := *r.config - config.UserConfigDir = userConfigDir - - if err := r.writeDockerAuthConfig(img, creds, userConfigDir); err != nil { - return "", err - } - - // Today, `--no-store` will fetch the remote image regardless of whether the content of the image - // has changed or not. This causes performance downgrades when the image tag is ':latest' and - // the image pull policy is 'always'. The issue is tracked in https://github.com/coreos/rkt/issues/2937. - if _, err := r.cli.RunCommand(&config, "fetch", "--no-store", dockerPrefix+img); err != nil { - glog.Errorf("Failed to fetch: %v", err) - return "", err - } - return r.getImageID(img) -} - -func (r *Runtime) GetImageRef(image kubecontainer.ImageSpec) (string, error) { - images, err := r.listImages(image.Image, false) - if err != nil { - return "", err - } - if len(images) == 0 { - return "", nil - } - return images[0].Id, nil -} - -// ListImages lists all the available appc images on the machine by invoking 'rkt image list'. -func (r *Runtime) ListImages() ([]kubecontainer.Image, error) { - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - listResp, err := r.apisvc.ListImages(ctx, &rktapi.ListImagesRequest{}) - if err != nil { - return nil, fmt.Errorf("couldn't list images: %v", err) - } - - images := make([]kubecontainer.Image, len(listResp.Images)) - for i, image := range listResp.Images { - images[i] = kubecontainer.Image{ - ID: image.Id, - RepoTags: []string{buildImageName(image)}, - Size: image.Size, - } - } - return images, nil -} - -// RemoveImage removes an on-disk image using 'rkt image rm'. -func (r *Runtime) RemoveImage(image kubecontainer.ImageSpec) error { - imageID, err := r.getImageID(image.Image) - if err != nil { - return err - } - if _, err := r.cli.RunCommand(nil, "image", "rm", imageID); err != nil { - return err - } - return nil -} - -// buildImageName constructs the image name for kubecontainer.Image. -// If the annotations contain the docker2aci metadata for this image, those are -// used instead as they may be more accurate in some cases, namely if a -// non-appc valid character is present -func buildImageName(img *rktapi.Image) string { - registry := "" - repository := "" - for _, anno := range img.Annotations { - if anno.Key == appcDockerRegistryURL { - registry = anno.Value - } - if anno.Key == appcDockerRepository { - repository = anno.Value - } - } - if registry != "" && repository != "" { - // TODO(euank): This could do the special casing for dockerhub and library images - return fmt.Sprintf("%s/%s:%s", registry, repository, img.Version) - } - - return fmt.Sprintf("%s:%s", img.Name, img.Version) -} - -// getImageID tries to find the image ID for the given image name. -// imageName should be in the form of 'name[:version]', e.g., 'example.com/app:latest'. -// The name should matches the result of 'rkt image list'. If the version is empty, -// then 'latest' is assumed. -func (r *Runtime) getImageID(imageName string) (string, error) { - images, err := r.listImages(imageName, false) - if err != nil { - return "", err - } - if len(images) == 0 { - return "", fmt.Errorf("cannot find the image %q", imageName) - } - return images[0].Id, nil -} - -type sortByImportTime []*rktapi.Image - -func (s sortByImportTime) Len() int { return len(s) } -func (s sortByImportTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s sortByImportTime) Less(i, j int) bool { return s[i].ImportTimestamp < s[j].ImportTimestamp } - -// listImages lists the images that have the given name. If detail is true, -// then image manifest is also included in the result. -// Note that there could be more than one images that have the given name, we -// will return the result reversely sorted by the import time, so that the latest -// image comes first. -func (r *Runtime) listImages(image string, detail bool) ([]*rktapi.Image, error) { - repoToPull, tag, _, err := parsers.ParseImageName(image) - if err != nil { - return nil, err - } - - imageFilters := []*rktapi.ImageFilter{ - { - // TODO(yifan): Add a field in the ImageFilter to match the whole name, - // not just keywords. - // https://github.com/coreos/rkt/issues/1872#issuecomment-166456938 - Keywords: []string{repoToPull}, - Labels: []*rktapi.KeyValue{{Key: "version", Value: tag}}, - }, - } - - // If the repo name is not a valid ACIdentifier (namely if it has a port), - // then it will have a different name in the store. Search for both the - // original name and this modified name in case we choose to also change the - // api-service to do this un-conversion on its end. - if appcRepoToPull, err := appctypes.SanitizeACIdentifier(repoToPull); err != nil { - glog.Warningf("could not convert %v to an aci identifier: %v", err) - } else { - imageFilters = append(imageFilters, &rktapi.ImageFilter{ - Keywords: []string{appcRepoToPull}, - Labels: []*rktapi.KeyValue{{Key: "version", Value: tag}}, - }) - } - - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - listResp, err := r.apisvc.ListImages(ctx, &rktapi.ListImagesRequest{ - Detail: detail, - Filters: imageFilters, - }) - if err != nil { - return nil, fmt.Errorf("couldn't list images: %v", err) - } - - // TODO(yifan): Let the API service to sort the result: - // See https://github.com/coreos/rkt/issues/1911. - sort.Sort(sort.Reverse(sortByImportTime(listResp.Images))) - return listResp.Images, nil -} - -// getImageManifest retrieves the image manifest for the given image. -func (r *Runtime) getImageManifest(image string) (*appcschema.ImageManifest, error) { - var manifest appcschema.ImageManifest - - images, err := r.listImages(image, true) - if err != nil { - return nil, err - } - if len(images) == 0 { - return nil, fmt.Errorf("cannot find the image %q", image) - } - - return &manifest, json.Unmarshal(images[0].Manifest, &manifest) -} - -// TODO(yifan): This is very racy, inefficient, and unsafe, we need to provide -// different namespaces. See: https://github.com/coreos/rkt/issues/836. -func (r *Runtime) writeDockerAuthConfig(image string, credsSlice []credentialprovider.LazyAuthConfiguration, userConfigDir string) error { - if len(credsSlice) == 0 { - return nil - } - - creds := dockertypes.AuthConfig{} - // TODO handle multiple creds - if len(credsSlice) >= 1 { - creds = credentialprovider.LazyProvide(credsSlice[0]) - } - - registry := "index.docker.io" - // Image spec: [/]/[: 0 { - set, err := appctypes.NewLinuxCapabilitiesRetainSet(addCaps...) - if err != nil { - return err - } - isolator, err := set.AsIsolator() - if err != nil { - return err - } - isolators = append(isolators, *isolator) - } - if len(dropCaps) > 0 { - set, err := appctypes.NewLinuxCapabilitiesRevokeSet(dropCaps...) - if err != nil { - return err - } - isolator, err := set.AsIsolator() - if err != nil { - return err - } - isolators = append(isolators, *isolator) - } - } - - // Resources isolators. - type resource struct { - limit string - request string - } - - // If limit is empty, populate it with request and vice versa. - resources := make(map[v1.ResourceName]*resource) - for name, quantity := range c.Resources.Limits { - resources[name] = &resource{limit: quantity.String(), request: quantity.String()} - } - for name, quantity := range c.Resources.Requests { - r, ok := resources[name] - if ok { - r.request = quantity.String() - continue - } - resources[name] = &resource{limit: quantity.String(), request: quantity.String()} - } - - for name, res := range resources { - switch name { - case v1.ResourceCPU: - cpu, err := appctypes.NewResourceCPUIsolator(res.request, res.limit) - if err != nil { - return err - } - isolators = append(isolators, cpu.AsIsolator()) - case v1.ResourceMemory: - memory, err := appctypes.NewResourceMemoryIsolator(res.request, res.limit) - if err != nil { - return err - } - isolators = append(isolators, memory.AsIsolator()) - default: - return fmt.Errorf("resource type not supported: %v", name) - } - } - - if ok := securitycontext.AddNoNewPrivileges(ctx); ok { - isolator, err := newNoNewPrivilegesIsolator(true) - if err != nil { - return err - } - isolators = append(isolators, *isolator) - } - - mergeIsolators(app, isolators) - return nil -} - -// mergeIsolators replaces the app.Isolators with isolators. -func mergeIsolators(app *appctypes.App, isolators []appctypes.Isolator) { - for _, is := range isolators { - found := false - for j, js := range app.Isolators { - if is.Name.Equals(js.Name) { - switch is.Name { - case appctypes.LinuxCapabilitiesRetainSetName: - // TODO(yifan): More fine grain merge for capability set instead of override. - fallthrough - case appctypes.LinuxCapabilitiesRevokeSetName: - fallthrough - case appctypes.ResourceCPUName: - fallthrough - case appctypes.ResourceMemoryName: - app.Isolators[j] = is - default: - panic(fmt.Sprintf("unexpected isolator name: %v", is.Name)) - } - found = true - break - } - } - if !found { - app.Isolators = append(app.Isolators, is) - } - } -} - -// mergeEnv merges the optEnv with the image's environments. -// The environments defined in the image will be overridden by -// the ones with the same name in optEnv. -func mergeEnv(app *appctypes.App, optEnv []kubecontainer.EnvVar) { - envMap := make(map[string]string) - for _, e := range app.Environment { - envMap[e.Name] = e.Value - } - for _, e := range optEnv { - envMap[e.Name] = e.Value - } - app.Environment = nil - for name, value := range envMap { - app.Environment = append(app.Environment, appctypes.EnvironmentVariable{ - Name: name, - Value: value, - }) - } -} - -// mergeMounts merges the mountPoints with the image's mount points. -// The mount points defined in the image will be overridden by the ones -// with the same container path. -func mergeMounts(app *appctypes.App, mountPoints []appctypes.MountPoint) { - mountMap := make(map[string]appctypes.MountPoint) - for _, m := range app.MountPoints { - mountMap[m.Path] = m - } - for _, m := range mountPoints { - mountMap[m.Path] = m - } - app.MountPoints = nil - for _, mount := range mountMap { - app.MountPoints = append(app.MountPoints, mount) - } -} - -// mergePortMappings merges the containerPorts with the image's container ports. -// The port mappings defined in the image will be overridden by the ones -// with the same name in optPortMappings. -func mergePortMappings(app *appctypes.App, containerPorts []appctypes.Port) { - portMap := make(map[appctypes.ACName]appctypes.Port) - for _, p := range app.Ports { - portMap[p.Name] = p - } - for _, p := range containerPorts { - portMap[p.Name] = p - } - app.Ports = nil - for _, port := range portMap { - app.Ports = append(app.Ports, port) - } -} - -func verifyNonRoot(app *appctypes.App, ctx *v1.SecurityContext) error { - if ctx != nil && ctx.RunAsNonRoot != nil && *ctx.RunAsNonRoot { - if ctx.RunAsUser != nil && *ctx.RunAsUser == 0 { - return fmt.Errorf("container's runAsUser breaks non-root policy") - } - if ctx.RunAsUser == nil && app.User == "0" { - return fmt.Errorf("container has no runAsUser and image will run as root") - } - } - return nil -} - -func setSupplementalGIDs(app *appctypes.App, podCtx *v1.PodSecurityContext, supplementalGids []int64) { - if podCtx != nil || len(supplementalGids) != 0 { - app.SupplementaryGIDs = app.SupplementaryGIDs[:0] - } - if podCtx != nil { - for _, v := range podCtx.SupplementalGroups { - app.SupplementaryGIDs = append(app.SupplementaryGIDs, int(v)) - } - if podCtx.FSGroup != nil { - app.SupplementaryGIDs = append(app.SupplementaryGIDs, int(*podCtx.FSGroup)) - } - } - for _, v := range supplementalGids { - app.SupplementaryGIDs = append(app.SupplementaryGIDs, int(v)) - } -} - -// setApp merges the container spec with the image's manifest. -func setApp(imgManifest *appcschema.ImageManifest, c *v1.Container, - mountPoints []appctypes.MountPoint, containerPorts []appctypes.Port, envs []kubecontainer.EnvVar, - ctx *v1.SecurityContext, podCtx *v1.PodSecurityContext, supplementalGids []int64) error { - - app := imgManifest.App - - // Set up Exec. - var command, args []string - cmd, ok := imgManifest.Annotations.Get(appcDockerEntrypoint) - if ok { - err := json.Unmarshal([]byte(cmd), &command) - if err != nil { - return fmt.Errorf("cannot unmarshal ENTRYPOINT %q: %v", cmd, err) - } - } - ag, ok := imgManifest.Annotations.Get(appcDockerCmd) - if ok { - err := json.Unmarshal([]byte(ag), &args) - if err != nil { - return fmt.Errorf("cannot unmarshal CMD %q: %v", ag, err) - } - } - userCommand, userArgs := kubecontainer.ExpandContainerCommandAndArgs(c, envs) - - if len(userCommand) > 0 { - command = userCommand - args = nil // If 'command' is specified, then drop the default args. - } - if len(userArgs) > 0 { - args = userArgs - } - - exec := append(command, args...) - if len(exec) > 0 { - app.Exec = exec - } - - // Set UID and GIDs. - if err := verifyNonRoot(app, ctx); err != nil { - return err - } - if ctx != nil && ctx.RunAsUser != nil { - app.User = strconv.Itoa(int(*ctx.RunAsUser)) - } - setSupplementalGIDs(app, podCtx, supplementalGids) - - // If 'User' or 'Group' are still empty at this point, - // then apply the root UID and GID. - // TODO(yifan): If only the GID is empty, rkt should be able to determine the GID - // using the /etc/passwd file in the image. - // See https://github.com/appc/docker2aci/issues/175. - // Maybe we can remove this check in the future. - if app.User == "" { - app.User = "0" - app.Group = "0" - } - if app.Group == "" { - return fmt.Errorf("cannot determine the GID of the app %q", imgManifest.Name) - } - - // Set working directory. - if len(c.WorkingDir) > 0 { - app.WorkingDirectory = c.WorkingDir - } - - // Notes that we don't create Mounts section in the pod manifest here, - // as Mounts will be automatically generated by rkt. - mergeMounts(app, mountPoints) - mergeEnv(app, envs) - mergePortMappings(app, containerPorts) - - return setIsolators(app, c, ctx) -} - -// makePodManifest transforms a kubelet pod spec to the rkt pod manifest. -func (r *Runtime) makePodManifest(pod *v1.Pod, podIP string, pullSecrets []v1.Secret) (*appcschema.PodManifest, error) { - manifest := appcschema.BlankPodManifest() - - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - listResp, err := r.apisvc.ListPods(ctx, &rktapi.ListPodsRequest{ - Detail: true, - Filters: kubernetesPodFilters(pod.UID), - }) - if err != nil { - return nil, fmt.Errorf("couldn't list pods: %v", err) - } - - restartCount := 0 - for _, pod := range listResp.Pods { - manifest := &appcschema.PodManifest{} - err = json.Unmarshal(pod.Manifest, manifest) - if err != nil { - glog.Warningf("rkt: error unmatshaling pod manifest: %v", err) - continue - } - - if countString, ok := manifest.Annotations.Get(k8sRktRestartCountAnno); ok { - num, err := strconv.Atoi(countString) - if err != nil { - glog.Warningf("rkt: error reading restart count on pod: %v", err) - continue - } - if num+1 > restartCount { - restartCount = num + 1 - } - } - } - - requiresPrivileged := false - manifest.Annotations.Set(*appctypes.MustACIdentifier(k8sRktKubeletAnno), k8sRktKubeletAnnoValue) - manifest.Annotations.Set(*appctypes.MustACIdentifier(types.KubernetesPodUIDLabel), string(pod.UID)) - manifest.Annotations.Set(*appctypes.MustACIdentifier(types.KubernetesPodNameLabel), pod.Name) - manifest.Annotations.Set(*appctypes.MustACIdentifier(types.KubernetesPodNamespaceLabel), pod.Namespace) - manifest.Annotations.Set(*appctypes.MustACIdentifier(types.KubernetesContainerNameLabel), leaky.PodInfraContainerName) - manifest.Annotations.Set(*appctypes.MustACIdentifier(k8sRktRestartCountAnno), strconv.Itoa(restartCount)) - if stage1Name, ok := pod.Annotations[k8sRktStage1NameAnno]; ok { - requiresPrivileged = true - manifest.Annotations.Set(*appctypes.MustACIdentifier(k8sRktStage1NameAnno), stage1Name) - } - - for _, c := range pod.Spec.Containers { - err := r.newAppcRuntimeApp(pod, podIP, c, requiresPrivileged, pullSecrets, manifest) - if err != nil { - return nil, err - } - } - - // TODO(yifan): Set pod-level isolators once it's supported in kubernetes. - return manifest, nil -} - -func copyfile(src, dst string) error { - data, err := ioutil.ReadFile(src) - if err != nil { - return err - } - return ioutil.WriteFile(dst, data, 0644) -} - -// TODO(yifan): Can make rkt handle this when '--net=host'. See https://github.com/coreos/rkt/issues/2430. -func makeHostNetworkMount(opts *kubecontainer.RunContainerOptions) (*kubecontainer.Mount, *kubecontainer.Mount, error) { - mountHosts, mountResolvConf := true, true - for _, mnt := range opts.Mounts { - switch mnt.ContainerPath { - case etcHostsPath: - mountHosts = false - case etcResolvConfPath: - mountResolvConf = false - } - } - - var hostsMount, resolvMount kubecontainer.Mount - if mountHosts { - hostsPath := filepath.Join(opts.PodContainerDir, "etc-hosts") - if err := copyfile(etcHostsPath, hostsPath); err != nil { - return nil, nil, err - } - hostsMount = kubecontainer.Mount{ - Name: "kubernetes-hostnetwork-hosts-conf", - ContainerPath: etcHostsPath, - HostPath: hostsPath, - } - opts.Mounts = append(opts.Mounts, hostsMount) - } - - if mountResolvConf { - resolvPath := filepath.Join(opts.PodContainerDir, "etc-resolv-conf") - if err := copyfile(etcResolvConfPath, resolvPath); err != nil { - return nil, nil, err - } - resolvMount = kubecontainer.Mount{ - Name: "kubernetes-hostnetwork-resolv-conf", - ContainerPath: etcResolvConfPath, - HostPath: resolvPath, - } - opts.Mounts = append(opts.Mounts, resolvMount) - } - return &hostsMount, &resolvMount, nil -} - -// podFinishedMarkerPath returns the path to a file which should be used to -// indicate the pod exiting, and the time thereof. -// If the file at the path does not exist, the pod should not be exited. If it -// does exist, then the ctime of the file should indicate the time the pod -// exited. -func podFinishedMarkerPath(podDir string, rktUID string) string { - return filepath.Join(podDir, "finished-"+rktUID) -} - -func podFinishedMarkCommand(touchPath, podDir, rktUID string) string { - // TODO, if the path has a `'` character in it, this breaks. - return touchPath + " " + podFinishedMarkerPath(podDir, rktUID) -} - -// podFinishedAt returns the time that a pod exited, or a zero time if it has -// not. -func (r *Runtime) podFinishedAt(podUID kubetypes.UID, rktUID string) time.Time { - markerFile := podFinishedMarkerPath(r.runtimeHelper.GetPodDir(podUID), rktUID) - stat, err := r.os.Stat(markerFile) - if err != nil { - if !os.IsNotExist(err) { - glog.Warningf("rkt: unexpected fs error checking pod finished marker: %v", err) - } - return time.Time{} - } - return stat.ModTime() -} - -func (r *Runtime) makeContainerLogMount(opts *kubecontainer.RunContainerOptions, container *v1.Container) (*kubecontainer.Mount, error) { - if opts.PodContainerDir == "" || container.TerminationMessagePath == "" { - return nil, nil - } - - // In docker runtime, the container log path contains the container ID. - // However, for rkt runtime, we cannot get the container ID before the - // the container is launched, so here we generate a random uuid to enable - // us to map a container's termination message path to a unique log file - // on the disk. - randomUID := uuid.NewUUID() - containerLogPath := path.Join(opts.PodContainerDir, string(randomUID)) - fs, err := r.os.Create(containerLogPath) - if err != nil { - return nil, err - } - - if err := fs.Close(); err != nil { - return nil, err - } - - mnt := kubecontainer.Mount{ - // Use a random name for the termination message mount, so that - // when a container restarts, it will not overwrite the old termination - // message. - Name: fmt.Sprintf("termination-message-%s", randomUID), - ContainerPath: container.TerminationMessagePath, - HostPath: containerLogPath, - ReadOnly: false, - } - opts.Mounts = append(opts.Mounts, mnt) - - return &mnt, nil -} - -func (r *Runtime) newAppcRuntimeApp(pod *v1.Pod, podIP string, c v1.Container, requiresPrivileged bool, pullSecrets []v1.Secret, manifest *appcschema.PodManifest) error { - var annotations appctypes.Annotations = []appctypes.Annotation{ - { - Name: *appctypes.MustACIdentifier(k8sRktContainerHashAnno), - Value: strconv.FormatUint(kubecontainer.HashContainerLegacy(&c), 10), - }, - { - Name: *appctypes.MustACIdentifier(types.KubernetesContainerNameLabel), - Value: c.Name, - }, - } - - if requiresPrivileged && !securitycontext.HasPrivilegedRequest(&c) { - return fmt.Errorf("cannot make %q: running a custom stage1 requires a privileged security context", format.Pod(pod)) - } - imageRef, _, err := r.imagePuller.EnsureImageExists(pod, &c, pullSecrets) - if err != nil { - return err - } - imgManifest, err := r.getImageManifest(c.Image) - if err != nil { - return err - } - - if imgManifest.App == nil { - imgManifest.App = new(appctypes.App) - } - - hash, err := appctypes.NewHash(imageRef) - if err != nil { - return err - } - - // TODO: determine how this should be handled for rkt - opts, _, err := r.runtimeHelper.GenerateRunContainerOptions(pod, &c, podIP) - if err != nil { - return err - } - - // Create additional mount for termination message path. - mount, err := r.makeContainerLogMount(opts, &c) - if err != nil { - return err - } - mounts := append(opts.Mounts, *mount) - annotations = append(annotations, appctypes.Annotation{ - Name: *appctypes.MustACIdentifier(k8sRktTerminationMessagePathAnno), - Value: mount.HostPath, - }) - - // If run in 'hostnetwork' mode, then copy the host's /etc/resolv.conf and /etc/hosts, - // and add mounts. - if kubecontainer.IsHostNetworkPod(pod) { - hostsMount, resolvMount, err := makeHostNetworkMount(opts) - if err != nil { - return err - } - mounts = append(mounts, *hostsMount, *resolvMount) - } - - supplementalGids := r.runtimeHelper.GetExtraSupplementalGroupsForPod(pod) - ctx := securitycontext.DetermineEffectiveSecurityContext(pod, &c) - - volumes, mountPoints := convertKubeMounts(mounts) - containerPorts, hostPorts := convertKubePortMappings(opts.PortMappings) - - if err := setApp(imgManifest, &c, mountPoints, containerPorts, opts.Envs, ctx, pod.Spec.SecurityContext, supplementalGids); err != nil { - return err - } - - ra := appcschema.RuntimeApp{ - Name: convertToACName(c.Name), - Image: appcschema.RuntimeImage{ID: *hash}, - App: imgManifest.App, - Annotations: annotations, - } - - if c.SecurityContext != nil && c.SecurityContext.ReadOnlyRootFilesystem != nil { - ra.ReadOnlyRootFS = *c.SecurityContext.ReadOnlyRootFilesystem - } - - manifest.Apps = append(manifest.Apps, ra) - manifest.Volumes = append(manifest.Volumes, volumes...) - manifest.Ports = append(manifest.Ports, hostPorts...) - - return nil -} - -func runningKubernetesPodFilters(uid kubetypes.UID) []*rktapi.PodFilter { - return []*rktapi.PodFilter{ - { - States: []rktapi.PodState{ - rktapi.PodState_POD_STATE_RUNNING, - }, - Annotations: []*rktapi.KeyValue{ - { - Key: k8sRktKubeletAnno, - Value: k8sRktKubeletAnnoValue, - }, - { - Key: types.KubernetesPodUIDLabel, - Value: string(uid), - }, - }, - }, - } -} - -func kubernetesPodFilters(uid kubetypes.UID) []*rktapi.PodFilter { - return []*rktapi.PodFilter{ - { - Annotations: []*rktapi.KeyValue{ - { - Key: k8sRktKubeletAnno, - Value: k8sRktKubeletAnnoValue, - }, - { - Key: types.KubernetesPodUIDLabel, - Value: string(uid), - }, - }, - }, - } -} - -func kubernetesPodsFilters() []*rktapi.PodFilter { - return []*rktapi.PodFilter{ - { - Annotations: []*rktapi.KeyValue{ - { - Key: k8sRktKubeletAnno, - Value: k8sRktKubeletAnnoValue, - }, - }, - }, - } -} - -func newUnitOption(section, name, value string) *unit.UnitOption { - return &unit.UnitOption{Section: section, Name: name, Value: value} -} - -// apiPodToruntimePod converts an v1.Pod to kubelet/container.Pod. -func apiPodToruntimePod(uuid string, pod *v1.Pod) *kubecontainer.Pod { - p := &kubecontainer.Pod{ - ID: pod.UID, - Name: pod.Name, - Namespace: pod.Namespace, - } - for i := range pod.Spec.Containers { - c := &pod.Spec.Containers[i] - p.Containers = append(p.Containers, &kubecontainer.Container{ - ID: buildContainerID(&containerID{uuid, c.Name}), - Name: c.Name, - Image: c.Image, - Hash: kubecontainer.HashContainerLegacy(c), - }) - } - return p -} - -// serviceFilePath returns the absolute path of the service file. -func serviceFilePath(serviceName string) string { - return path.Join(systemdServiceDir, serviceName) -} - -// shouldCreateNetns returns true if: -// The pod does not run in host network. And -// The pod runs inside a netns created outside of rkt. -func (r *Runtime) shouldCreateNetns(pod *v1.Pod) bool { - return !kubecontainer.IsHostNetworkPod(pod) && r.network.PluginName() != network.DefaultPluginName -} - -// usesRktHostNetwork returns true if: -// The pod runs in the host network. Or -// The pod runs inside a netns created outside of rkt. -func (r *Runtime) usesRktHostNetwork(pod *v1.Pod) bool { - return kubecontainer.IsHostNetworkPod(pod) || r.shouldCreateNetns(pod) -} - -// generateRunCommand crafts a 'rkt run-prepared' command with necessary parameters. -func (r *Runtime) generateRunCommand(pod *v1.Pod, uuid, networkNamespaceID string) (string, error) { - config := *r.config - privileged := true - - for _, c := range pod.Spec.Containers { - ctx := securitycontext.DetermineEffectiveSecurityContext(pod, &c) - if ctx == nil || ctx.Privileged == nil || *ctx.Privileged == false { - privileged = false - break - } - } - - // Use "all-run" insecure option (https://github.com/coreos/rkt/pull/2983) to take care - // of privileged pod. - // TODO(yifan): Have more granular app-level control of the insecure options. - // See: https://github.com/coreos/rkt/issues/2996. - if privileged { - config.InsecureOptions = fmt.Sprintf("%s,%s", config.InsecureOptions, "all-run") - } - - runPrepared := buildCommand(&config, "run-prepared").Args - - var hostname string - var err error - - osInfos, err := getOSReleaseInfo() - if err != nil { - glog.Warningf("rkt: Failed to read the os release info: %v", err) - } else { - // Overlay fs is not supported for SELinux yet on many distros. - // See https://github.com/coreos/rkt/issues/1727#issuecomment-173203129. - // For now, coreos carries a patch to support it: https://github.com/coreos/coreos-overlay/pull/1703 - if osInfos["ID"] != "coreos" && pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.SELinuxOptions != nil { - runPrepared = append(runPrepared, "--no-overlay=true") - } - } - - // Apply '--net=host' to pod that is running on host network or inside a network namespace. - if r.usesRktHostNetwork(pod) { - runPrepared = append(runPrepared, "--net=host") - } else { - runPrepared = append(runPrepared, fmt.Sprintf("--net=%s", defaultNetworkName)) - } - - if kubecontainer.IsHostNetworkPod(pod) { - // TODO(yifan): Let runtimeHelper.GeneratePodHostNameAndDomain() to handle this. - hostname, err = r.os.Hostname() - if err != nil { - return "", err - } - } else { - // Setup DNS. - dnsConfig, err := r.runtimeHelper.GetPodDNS(pod) - if err != nil { - return "", err - } - for _, server := range dnsConfig.Servers { - runPrepared = append(runPrepared, fmt.Sprintf("--dns=%s", server)) - } - for _, search := range dnsConfig.Searches { - runPrepared = append(runPrepared, fmt.Sprintf("--dns-search=%s", search)) - } - if len(dnsConfig.Servers) > 0 || len(dnsConfig.Searches) > 0 { - runPrepared = append(runPrepared, fmt.Sprintf("--dns-opt=%s", defaultDNSOption)) - } - - // TODO(yifan): host domain is not being used. - hostname, _, err = r.runtimeHelper.GeneratePodHostNameAndDomain(pod) - if err != nil { - return "", err - } - } - - runPrepared = append(runPrepared, fmt.Sprintf("--hostname=%s", hostname)) - runPrepared = append(runPrepared, uuid) - - if r.shouldCreateNetns(pod) { - // Drop the `rkt run-prepared` into the network namespace we - // created. - // TODO: switch to 'ip netns exec' once we can depend on a new - // enough version that doesn't have bugs like - // https://bugzilla.redhat.com/show_bug.cgi?id=882047 - nsenterExec := []string{r.nsenterPath, "--net=" + netnsPathFromName(networkNamespaceID), "--"} - runPrepared = append(nsenterExec, runPrepared...) - } - - return strings.Join(runPrepared, " "), nil -} - -func (r *Runtime) cleanupPodNetwork(pod *v1.Pod, networkNamespace kubecontainer.ContainerID) error { - // No-op if the pod is not running in a created netns. - if !r.shouldCreateNetns(pod) { - return nil - } - - glog.V(3).Infof("Calling network plugin %s to tear down pod for %s", r.network.PluginName(), format.Pod(pod)) - teardownErr := r.network.TearDownPod(pod.Namespace, pod.Name, networkNamespace) - if teardownErr != nil { - glog.Error(teardownErr) - } - - if _, err := r.execer.Command("ip", "netns", "del", networkNamespace.ID).Output(); err != nil { - return fmt.Errorf("rkt: Failed to remove network namespace for pod %s: %v", format.Pod(pod), err) - } - - return teardownErr -} - -func (r *Runtime) preparePodArgs(manifest *appcschema.PodManifest, manifestFileName string) []string { - // Order of precedence for the stage1: - // 1) pod annotation (stage1 name) - // 2) kubelet configured stage1 (stage1 path) - // 3) empty; whatever rkt's compiled to default to - stage1ImageCmd := "" - if r.config.Stage1Image != "" { - stage1ImageCmd = "--stage1-name=" + r.config.Stage1Image - } - if stage1Name, ok := manifest.Annotations.Get(k8sRktStage1NameAnno); ok { - stage1ImageCmd = "--stage1-name=" + stage1Name - } - - // Run 'rkt prepare' to get the rkt UUID. - cmds := []string{"prepare", "--quiet", "--pod-manifest", manifestFileName} - if stage1ImageCmd != "" { - cmds = append(cmds, stage1ImageCmd) - } - return cmds -} - -func (r *Runtime) getSelinuxContext(opt *v1.SELinuxOptions) (string, error) { - selinuxRunner := selinux.NewSELinuxRunner() - str, err := selinuxRunner.Getfilecon(r.config.Dir) - if err != nil { - return "", err - } - - ctx := strings.SplitN(str, ":", 4) - if len(ctx) != 4 { - return "", fmt.Errorf("malformated selinux context") - } - - if opt.User != "" { - ctx[0] = opt.User - } - if opt.Role != "" { - ctx[1] = opt.Role - } - if opt.Type != "" { - ctx[2] = opt.Type - } - if opt.Level != "" { - ctx[3] = opt.Level - } - - return strings.Join(ctx, ":"), nil -} - -// From the generateName or the podName return a basename for improving the logging with the Journal -// journalctl -t podBaseName -func constructSyslogIdentifier(generateName string, podName string) string { - if len(generateName) > 1 && generateName[len(generateName)-1] == '-' { - return generateName[0 : len(generateName)-1] - } - if len(generateName) > 0 { - return generateName - } - return podName -} - -// Setup additional systemd field specified in the Pod Annotation -func setupSystemdCustomFields(annotations map[string]string, unitOptionArray []*unit.UnitOption) ([]*unit.UnitOption, error) { - // LimitNOFILE - if strSize := annotations[k8sRktLimitNoFileAnno]; strSize != "" { - size, err := strconv.Atoi(strSize) - if err != nil { - return unitOptionArray, err - } - if size < 1 { - return unitOptionArray, fmt.Errorf("invalid value for %s: %s", k8sRktLimitNoFileAnno, strSize) - } - unitOptionArray = append(unitOptionArray, newUnitOption("Service", "LimitNOFILE", strSize)) - } - - return unitOptionArray, nil -} - -// preparePod will: -// -// 1. Invoke 'rkt prepare' to prepare the pod, and get the rkt pod uuid. -// 2. Create the unit file and save it under systemdUnitDir. -// -// On success, it will return a string that represents name of the unit file -// and the runtime pod. -func (r *Runtime) preparePod(pod *v1.Pod, podIP string, pullSecrets []v1.Secret, networkNamespaceID string) (string, *kubecontainer.Pod, error) { - // Generate the appc pod manifest from the k8s pod spec. - manifest, err := r.makePodManifest(pod, podIP, pullSecrets) - if err != nil { - return "", nil, err - } - manifestFile, err := ioutil.TempFile("", fmt.Sprintf("manifest-%s-", pod.Name)) - if err != nil { - return "", nil, err - } - defer func() { - manifestFile.Close() - if err := r.os.Remove(manifestFile.Name()); err != nil { - glog.Warningf("rkt: Cannot remove temp manifest file %q: %v", manifestFile.Name(), err) - } - }() - - data, err := json.Marshal(manifest) - if err != nil { - return "", nil, err - } - - glog.V(4).Infof("Generating pod manifest for pod %q: %v", format.Pod(pod), string(data)) - // Since File.Write returns error if the written length is less than len(data), - // so check error is enough for us. - if _, err := manifestFile.Write(data); err != nil { - return "", nil, err - } - - prepareCmd := r.preparePodArgs(manifest, manifestFile.Name()) - output, err := r.cli.RunCommand(nil, prepareCmd...) - if err != nil { - return "", nil, err - } - if len(output) != 1 { - return "", nil, fmt.Errorf("invalid output from 'rkt prepare': %v", output) - } - uuid := output[0] - glog.V(4).Infof("'rkt prepare' returns %q", uuid) - - // Create systemd service file for the rkt pod. - runPrepared, err := r.generateRunCommand(pod, uuid, networkNamespaceID) - if err != nil { - return "", nil, fmt.Errorf("failed to generate 'rkt run-prepared' command: %v", err) - } - - // TODO handle pod.Spec.HostPID - // TODO handle pod.Spec.HostIPC - - // TODO per container finishedAt, not just per pod - markPodFinished := podFinishedMarkCommand(r.touchPath, r.runtimeHelper.GetPodDir(pod.UID), uuid) - - hostNetwork := kubecontainer.IsHostNetworkPod(pod) - units := []*unit.UnitOption{ - newUnitOption("Service", "ExecStart", runPrepared), - newUnitOption("Service", "ExecStopPost", markPodFinished), - // This enables graceful stop. - newUnitOption("Service", "KillMode", "mixed"), - newUnitOption("Service", "TimeoutStopSec", fmt.Sprintf("%ds", getPodTerminationGracePeriodInSecond(pod))), - // Ops helpers - newUnitOption("Unit", "Description", pod.Name), - newUnitOption("Service", "SyslogIdentifier", constructSyslogIdentifier(pod.GenerateName, pod.Name)), - // Track pod info for garbage collection - newUnitOption(unitKubernetesSection, unitPodUID, string(pod.UID)), - newUnitOption(unitKubernetesSection, unitPodName, pod.Name), - newUnitOption(unitKubernetesSection, unitPodNamespace, pod.Namespace), - newUnitOption(unitKubernetesSection, unitPodHostNetwork, fmt.Sprintf("%v", hostNetwork)), - newUnitOption(unitKubernetesSection, unitPodNetworkNamespace, networkNamespaceID), - } - - if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.SELinuxOptions != nil { - opt := pod.Spec.SecurityContext.SELinuxOptions - selinuxContext, err := r.getSelinuxContext(opt) - if err != nil { - glog.Errorf("rkt: Failed to construct selinux context with selinux option %q: %v", opt, err) - return "", nil, err - } - units = append(units, newUnitOption("Service", "SELinuxContext", selinuxContext)) - } - - units, err = setupSystemdCustomFields(pod.Annotations, units) - if err != nil { - glog.Warningf("fail to add custom systemd fields provided by pod Annotations: %q", err) - } - - serviceName := makePodServiceFileName(uuid) - glog.V(4).Infof("rkt: Creating service file %q for pod %q", serviceName, format.Pod(pod)) - serviceFile, err := r.os.Create(serviceFilePath(serviceName)) - if err != nil { - return "", nil, err - } - if _, err := io.Copy(serviceFile, unit.Serialize(units)); err != nil { - return "", nil, err - } - serviceFile.Close() - - return serviceName, apiPodToruntimePod(uuid, pod), nil -} - -// generateEvents is a helper function that generates some container -// life cycle events for containers in a pod. -func (r *Runtime) generateEvents(runtimePod *kubecontainer.Pod, reason string, failure error) { - // Set up container references. - for _, c := range runtimePod.Containers { - containerID := c.ID - id, err := parseContainerID(containerID) - if err != nil { - glog.Warningf("Invalid container ID %q", containerID) - continue - } - - ref, ok := r.containerRefManager.GetRef(containerID) - if !ok { - glog.Warningf("No ref for container %q", containerID) - continue - } - - // Note that 'rkt id' is the pod id. - uuid := utilstrings.ShortenString(id.uuid, 8) - switch reason { - case "Created": - r.recorder.Eventf(ref, v1.EventTypeNormal, events.CreatedContainer, "Created with rkt id %v", uuid) - case "Started": - r.recorder.Eventf(ref, v1.EventTypeNormal, events.StartedContainer, "Started with rkt id %v", uuid) - case "Failed": - r.recorder.Eventf(ref, v1.EventTypeWarning, events.FailedToStartContainer, "Failed to start with rkt id %v with error %v", uuid, failure) - case "Killing": - r.recorder.Eventf(ref, v1.EventTypeNormal, events.KillingContainer, "Killing with rkt id %v", uuid) - default: - glog.Errorf("rkt: Unexpected event %q", reason) - } - } - return -} - -// Generate a Network Namespace based on a New UUID -// to run the Pod and all of its containers inside a dedicated unique namespace -func generateNetworkNamespaceUUID() kubecontainer.ContainerID { - return kubecontainer.ContainerID{ID: fmt.Sprintf("%s%s", kubernetesUnitPrefix, uuid.NewUUID())} -} - -func netnsPathFromName(netnsName string) string { - return fmt.Sprintf("/var/run/netns/%s", netnsName) -} - -// setupPodNetwork creates a network namespace for the given pod and calls -// configured NetworkPlugin's setup function on it. -// It returns the namespace name, configured IP (if available), and an error if -// one occurred. -// -// If the pod is running in host network or is running using the no-op plugin, then nothing will be done. -func (r *Runtime) setupPodNetwork(pod *v1.Pod) (kubecontainer.ContainerID, string, error) { - glog.V(3).Infof("Calling network plugin %s to set up pod for %s", r.network.PluginName(), format.Pod(pod)) - - var networkNamespace kubecontainer.ContainerID - - // No-op if the pod is not running in a created netns. - if !r.shouldCreateNetns(pod) { - return networkNamespace, "", nil - } - - networkNamespace = generateNetworkNamespaceUUID() - glog.V(5).Infof("New network namespace %q generated for pod %s", networkNamespace.ID, format.Pod(pod)) - - // Create the network namespace for the pod - _, err := r.execer.Command("ip", "netns", "add", networkNamespace.ID).Output() - if err != nil { - return networkNamespace, "", fmt.Errorf("failed to create pod network namespace: %v", err) - } - - // Set up networking with the network plugin - err = r.network.SetUpPod(pod.Namespace, pod.Name, networkNamespace, pod.Annotations) - if err != nil { - return networkNamespace, "", err - } - status, err := r.network.GetPodNetworkStatus(pod.Namespace, pod.Name, networkNamespace) - if err != nil { - return networkNamespace, "", err - } - - if r.configureHairpinMode { - if err = hairpin.SetUpContainerPath(netnsPathFromName(networkNamespace.ID), network.DefaultInterfaceName); err != nil { - glog.Warningf("Hairpin setup failed for pod %q: %v", format.Pod(pod), err) - } - } - - return networkNamespace, status.IP.String(), nil -} - -// For a hostPath volume: rkt doesn't create any missing volume on the node/host so we need to create it -func createHostPathVolumes(pod *v1.Pod) (err error) { - for _, v := range pod.Spec.Volumes { - if v.VolumeSource.HostPath != nil { - _, err = os.Stat(v.HostPath.Path) - if os.IsNotExist(err) { - if err = os.MkdirAll(v.HostPath.Path, os.ModePerm); err != nil { - glog.Errorf("Create volume HostPath %q for Pod %q failed: %q", v.HostPath.Path, format.Pod(pod), err.Error()) - return err - } - glog.V(4).Infof("Created volume HostPath %q for Pod %q", v.HostPath.Path, format.Pod(pod)) - } - } - } - return nil -} - -// RunPod first creates the unit file for a pod, and then -// starts the unit over d-bus. -func (r *Runtime) RunPod(pod *v1.Pod, pullSecrets []v1.Secret) error { - glog.V(4).Infof("Rkt starts to run pod: name %q.", format.Pod(pod)) - - var err error - var networkNamespace kubecontainer.ContainerID - var podIP string - - err = createHostPathVolumes(pod) - if err != nil { - return err - } - - networkNamespace, podIP, err = r.setupPodNetwork(pod) - if err != nil { - r.cleanupPodNetwork(pod, networkNamespace) - return err - } - - name, runtimePod, prepareErr := r.preparePod(pod, podIP, pullSecrets, networkNamespace.ID) - - // Set container references and generate events. - // If preparedPod fails, then send out 'failed' events for each container. - // Otherwise, store the container references so we can use them later to send events. - for i, c := range pod.Spec.Containers { - ref, err := kubecontainer.GenerateContainerRef(pod, &c) - if err != nil { - glog.Errorf("Couldn't make a ref to pod %q, container %v: '%v'", format.Pod(pod), c.Name, err) - continue - } - if prepareErr != nil { - r.recorder.Eventf(ref, v1.EventTypeWarning, events.FailedToCreateContainer, "Failed to create rkt container with error: %v", prepareErr) - continue - } - containerID := runtimePod.Containers[i].ID - r.containerRefManager.SetRef(containerID, ref) - } - - if prepareErr != nil { - r.cleanupPodNetwork(pod, networkNamespace) - return prepareErr - } - - r.generateEvents(runtimePod, "Created", nil) - - // RestartUnit has the same effect as StartUnit if the unit is not running, besides it can restart - // a unit if the unit file is changed and reloaded. - reschan := make(chan string) - _, err = r.systemd.RestartUnit(name, "replace", reschan) - if err != nil { - r.generateEvents(runtimePod, "Failed", err) - r.cleanupPodNetwork(pod, networkNamespace) - return err - } - - res := <-reschan - if res != "done" { - err := fmt.Errorf("Failed to restart unit %q: %s", name, res) - r.generateEvents(runtimePod, "Failed", err) - r.cleanupPodNetwork(pod, networkNamespace) - return err - } - - r.generateEvents(runtimePod, "Started", nil) - - // This is a temporary solution until we have a clean design on how - // kubelet handles events. See https://github.com/kubernetes/kubernetes/issues/23084. - if err := r.runLifecycleHooks(pod, runtimePod, lifecyclePostStartHook); err != nil { - if errKill := r.KillPod(pod, *runtimePod, nil); errKill != nil { - return errors.NewAggregate([]error{err, errKill}) - } - r.cleanupPodNetwork(pod, networkNamespace) - return err - } - - return nil -} - -func (r *Runtime) runPreStopHook(containerID kubecontainer.ContainerID, pod *v1.Pod, container *v1.Container) error { - glog.V(4).Infof("rkt: Running pre-stop hook for container %q of pod %q", container.Name, format.Pod(pod)) - msg, err := r.runner.Run(containerID, pod, container, container.Lifecycle.PreStop) - if err != nil { - ref, ok := r.containerRefManager.GetRef(containerID) - if !ok { - glog.Warningf("No ref for container %q", containerID) - } else { - r.recorder.Eventf(ref, v1.EventTypeWarning, events.FailedPreStopHook, msg) - } - } - return err -} - -func (r *Runtime) runPostStartHook(containerID kubecontainer.ContainerID, pod *v1.Pod, container *v1.Container) error { - glog.V(4).Infof("rkt: Running post-start hook for container %q of pod %q", container.Name, format.Pod(pod)) - cid, err := parseContainerID(containerID) - if err != nil { - return fmt.Errorf("cannot parse container ID %v", containerID) - } - - isContainerRunning := func() (done bool, err error) { - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - resp, err := r.apisvc.InspectPod(ctx, &rktapi.InspectPodRequest{Id: cid.uuid}) - if err != nil { - return false, fmt.Errorf("failed to inspect rkt pod %q for pod %q", cid.uuid, format.Pod(pod)) - } - - for _, app := range resp.Pod.Apps { - if app.Name == cid.appName { - return app.State == rktapi.AppState_APP_STATE_RUNNING, nil - } - } - return false, fmt.Errorf("failed to find container %q in rkt pod %q", cid.appName, cid.uuid) - } - - // TODO(yifan): Polling the pod's state for now. - timeout := time.Second * 5 - pollInterval := time.Millisecond * 500 - if err := utilwait.Poll(pollInterval, timeout, isContainerRunning); err != nil { - return fmt.Errorf("rkt: Pod %q doesn't become running in %v: %v", format.Pod(pod), timeout, err) - } - - msg, err := r.runner.Run(containerID, pod, container, container.Lifecycle.PostStart) - if err != nil { - ref, ok := r.containerRefManager.GetRef(containerID) - if !ok { - glog.Warningf("No ref for container %q", containerID) - } else { - r.recorder.Eventf(ref, v1.EventTypeWarning, events.FailedPostStartHook, msg) - } - } - return err -} - -type lifecycleHookType string - -const ( - lifecyclePostStartHook lifecycleHookType = "post-start" - lifecyclePreStopHook lifecycleHookType = "pre-stop" -) - -func (r *Runtime) runLifecycleHooks(pod *v1.Pod, runtimePod *kubecontainer.Pod, typ lifecycleHookType) error { - var wg sync.WaitGroup - var errlist []error - errCh := make(chan error, len(pod.Spec.Containers)) - - wg.Add(len(pod.Spec.Containers)) - - for i, c := range pod.Spec.Containers { - var hookFunc func(kubecontainer.ContainerID, *v1.Pod, *v1.Container) error - - switch typ { - case lifecyclePostStartHook: - if c.Lifecycle != nil && c.Lifecycle.PostStart != nil { - hookFunc = r.runPostStartHook - } - case lifecyclePreStopHook: - if c.Lifecycle != nil && c.Lifecycle.PreStop != nil { - hookFunc = r.runPreStopHook - } - default: - errCh <- fmt.Errorf("Unrecognized lifecycle hook type %q for container %q in pod %q", typ, c.Name, format.Pod(pod)) - } - - if hookFunc == nil { - wg.Done() - continue - } - - container := &pod.Spec.Containers[i] - runtimeContainer := runtimePod.FindContainerByName(container.Name) - if runtimeContainer == nil { - // Container already gone. - wg.Done() - continue - } - containerID := runtimeContainer.ID - - go func() { - defer wg.Done() - if err := hookFunc(containerID, pod, container); err != nil { - glog.Errorf("rkt: Failed to run %s hook for container %q of pod %q: %v", typ, container.Name, format.Pod(pod), err) - errCh <- err - } else { - glog.V(4).Infof("rkt: %s hook completed successfully for container %q of pod %q", typ, container.Name, format.Pod(pod)) - } - }() - } - - wg.Wait() - close(errCh) - - for err := range errCh { - errlist = append(errlist, err) - } - return errors.NewAggregate(errlist) -} - -// convertRktPod will convert a rktapi.Pod to a kubecontainer.Pod -func (r *Runtime) convertRktPod(rktpod *rktapi.Pod) (*kubecontainer.Pod, error) { - manifest := &appcschema.PodManifest{} - err := json.Unmarshal(rktpod.Manifest, manifest) - if err != nil { - return nil, err - } - - podUID, ok := manifest.Annotations.Get(types.KubernetesPodUIDLabel) - if !ok { - return nil, fmt.Errorf("pod is missing annotation %s", types.KubernetesPodUIDLabel) - } - podName, ok := manifest.Annotations.Get(types.KubernetesPodNameLabel) - if !ok { - return nil, fmt.Errorf("pod is missing annotation %s", types.KubernetesPodNameLabel) - } - podNamespace, ok := manifest.Annotations.Get(types.KubernetesPodNamespaceLabel) - if !ok { - return nil, fmt.Errorf("pod is missing annotation %s", types.KubernetesPodNamespaceLabel) - } - - kubepod := &kubecontainer.Pod{ - ID: kubetypes.UID(podUID), - Name: podName, - Namespace: podNamespace, - } - - for i, app := range rktpod.Apps { - // The order of the apps is determined by the rkt pod manifest. - // TODO(yifan): Let the server to unmarshal the annotations? https://github.com/coreos/rkt/issues/1872 - hashStr, ok := manifest.Apps[i].Annotations.Get(k8sRktContainerHashAnno) - if !ok { - return nil, fmt.Errorf("app %q is missing annotation %s", app.Name, k8sRktContainerHashAnno) - } - containerHash, err := strconv.ParseUint(hashStr, 10, 64) - if err != nil { - return nil, fmt.Errorf("couldn't parse container's hash %q: %v", hashStr, err) - } - - kubepod.Containers = append(kubepod.Containers, &kubecontainer.Container{ - ID: buildContainerID(&containerID{rktpod.Id, app.Name}), - Name: app.Name, - // By default, the version returned by rkt API service will be "latest" if not specified. - Image: fmt.Sprintf("%s:%s", app.Image.Name, app.Image.Version), - ImageID: app.Image.Id, - Hash: containerHash, - State: appStateToContainerState(app.State), - }) - } - - return kubepod, nil -} - -// GetPods runs 'rkt list' to get the list of rkt pods. -// Then it will use the result to construct a list of container runtime pods. -// If all is false, then only running pods will be returned, otherwise all pods will be -// returned. -func (r *Runtime) GetPods(all bool) ([]*kubecontainer.Pod, error) { - glog.V(4).Infof("Rkt getting pods") - - listReq := &rktapi.ListPodsRequest{ - Detail: true, - Filters: []*rktapi.PodFilter{ - { - Annotations: []*rktapi.KeyValue{ - { - Key: k8sRktKubeletAnno, - Value: k8sRktKubeletAnnoValue, - }, - }, - }, - }, - } - if !all { - listReq.Filters[0].States = []rktapi.PodState{rktapi.PodState_POD_STATE_RUNNING} - } - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - listResp, err := r.apisvc.ListPods(ctx, listReq) - if err != nil { - return nil, fmt.Errorf("couldn't list pods: %v", err) - } - - pods := make(map[kubetypes.UID]*kubecontainer.Pod) - var podIDs []kubetypes.UID - for _, pod := range listResp.Pods { - pod, err := r.convertRktPod(pod) - if err != nil { - glog.Warningf("rkt: Cannot construct pod from unit file: %v.", err) - continue - } - - // Group pods together. - oldPod, found := pods[pod.ID] - if !found { - pods[pod.ID] = pod - podIDs = append(podIDs, pod.ID) - continue - } - - oldPod.Containers = append(oldPod.Containers, pod.Containers...) - } - - // Convert map to list, using the consistent order from the podIDs array. - var result []*kubecontainer.Pod - for _, id := range podIDs { - result = append(result, pods[id]) - } - - return result, nil -} - -func getPodTerminationGracePeriodInSecond(pod *v1.Pod) int64 { - var gracePeriod int64 - switch { - case pod.DeletionGracePeriodSeconds != nil: - gracePeriod = *pod.DeletionGracePeriodSeconds - case pod.Spec.TerminationGracePeriodSeconds != nil: - gracePeriod = *pod.Spec.TerminationGracePeriodSeconds - } - if gracePeriod < minimumGracePeriodInSeconds { - gracePeriod = minimumGracePeriodInSeconds - } - return gracePeriod -} - -func (r *Runtime) waitPreStopHooks(pod *v1.Pod, runningPod *kubecontainer.Pod) { - gracePeriod := getPodTerminationGracePeriodInSecond(pod) - - done := make(chan struct{}) - go func() { - if err := r.runLifecycleHooks(pod, runningPod, lifecyclePreStopHook); err != nil { - glog.Errorf("rkt: Some pre-stop hooks failed for pod %q: %v", format.Pod(pod), err) - } - close(done) - }() - - select { - case <-time.After(time.Duration(gracePeriod) * time.Second): - glog.V(2).Infof("rkt: Some pre-stop hooks did not complete in %d seconds for pod %q", gracePeriod, format.Pod(pod)) - case <-done: - } -} - -// KillPod invokes 'systemctl kill' to kill the unit that runs the pod. -// TODO: add support for gracePeriodOverride which is used in eviction scenarios -func (r *Runtime) KillPod(pod *v1.Pod, runningPod kubecontainer.Pod, gracePeriodOverride *int64) error { - glog.V(4).Infof("Rkt is killing pod: name %q.", runningPod.Name) - - if len(runningPod.Containers) == 0 { - glog.V(4).Infof("rkt: Pod %q is already being killed, no action will be taken", runningPod.Name) - return nil - } - - if pod != nil { - r.waitPreStopHooks(pod, &runningPod) - } - - containerID, err := parseContainerID(runningPod.Containers[0].ID) - if err != nil { - glog.Errorf("rkt: Failed to get rkt uuid of the pod %q: %v", runningPod.Name, err) - return err - } - serviceName := makePodServiceFileName(containerID.uuid) - serviceFile := serviceFilePath(serviceName) - - r.generateEvents(&runningPod, "Killing", nil) - for _, c := range runningPod.Containers { - r.containerRefManager.ClearRef(c.ID) - } - - // Since all service file have 'KillMode=mixed', the processes in - // the unit's cgroup will receive a SIGKILL if the normal stop timeouts. - reschan := make(chan string) - if _, err = r.systemd.StopUnit(serviceName, "replace", reschan); err != nil { - glog.Errorf("rkt: Failed to stop unit %q: %v", serviceName, err) - return err - } - - res := <-reschan - if res != "done" { - err := fmt.Errorf("invalid result: %s", res) - glog.Errorf("rkt: Failed to stop unit %q: %v", serviceName, err) - return err - } - - // Clean up networking. Use the service file to get pod details since 'pod' can be nil. - if err := r.cleanupPodNetworkFromServiceFile(serviceFile); err != nil { - glog.Errorf("rkt: failed to tear down network for unit %q: %v", serviceName, err) - return err - } - - return nil -} - -func (r *Runtime) Type() string { - return RktType -} - -func (r *Runtime) Version() (kubecontainer.Version, error) { - r.versions.RLock() - defer r.versions.RUnlock() - return r.versions.binVersion, nil -} - -func (r *Runtime) APIVersion() (kubecontainer.Version, error) { - r.versions.RLock() - defer r.versions.RUnlock() - return r.versions.apiVersion, nil -} - -// Status returns error if rkt is unhealthy, nil otherwise. -func (r *Runtime) Status() (*kubecontainer.RuntimeStatus, error) { - return nil, r.checkVersion(minimumRktBinVersion, minimumRktApiVersion, minimumSystemdVersion) -} - -// SyncPod syncs the running pod to match the specified desired pod. -func (r *Runtime) SyncPod(pod *v1.Pod, _ v1.PodStatus, podStatus *kubecontainer.PodStatus, pullSecrets []v1.Secret, backOff *flowcontrol.Backoff) (result kubecontainer.PodSyncResult) { - var err error - defer func() { - if err != nil { - result.Fail(err) - } - }() - // TODO: (random-liu) Stop using running pod in SyncPod() - runningPod := kubecontainer.ConvertPodStatusToRunningPod(r.Type(), podStatus) - // Add references to all containers. - unidentifiedContainers := make(map[kubecontainer.ContainerID]*kubecontainer.Container) - for _, c := range runningPod.Containers { - unidentifiedContainers[c.ID] = c - } - - restartPod := false - for _, container := range pod.Spec.Containers { - expectedHash := kubecontainer.HashContainerLegacy(&container) - - c := runningPod.FindContainerByName(container.Name) - if c == nil { - if kubecontainer.ShouldContainerBeRestarted(&container, pod, podStatus) { - glog.V(3).Infof("Container %+v is dead, but RestartPolicy says that we should restart it.", container) - // TODO(yifan): Containers in one pod are fate-sharing at this moment, see: - // https://github.com/appc/spec/issues/276. - restartPod = true - break - } - continue - } - - // TODO: check for non-root image directives. See ../docker/manager.go#SyncPod - - // TODO(yifan): Take care of host network change. - containerChanged := c.Hash != 0 && c.Hash != expectedHash - if containerChanged { - glog.Infof("Pod %q container %q hash changed (%d vs %d), it will be killed and re-created.", format.Pod(pod), container.Name, c.Hash, expectedHash) - restartPod = true - break - } - - liveness, found := r.livenessManager.Get(c.ID) - if found && liveness != proberesults.Success && pod.Spec.RestartPolicy != v1.RestartPolicyNever { - glog.Infof("Pod %q container %q is unhealthy, it will be killed and re-created.", format.Pod(pod), container.Name) - restartPod = true - break - } - - delete(unidentifiedContainers, c.ID) - } - - // If there is any unidentified containers, restart the pod. - if len(unidentifiedContainers) > 0 { - restartPod = true - } - - if restartPod { - // Kill the pod only if the pod is actually running. - if len(runningPod.Containers) > 0 { - if err = r.KillPod(pod, runningPod, nil); err != nil { - return - } - } - if err = r.RunPod(pod, pullSecrets); err != nil { - return - } - } - return -} - -// Sort rkt pods by creation time. -type podsByCreatedAt []*rktapi.Pod - -func (s podsByCreatedAt) Len() int { return len(s) } -func (s podsByCreatedAt) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s podsByCreatedAt) Less(i, j int) bool { return s[i].CreatedAt < s[j].CreatedAt } - -// getPodUID returns the pod's API UID, it returns -// empty UID if the UID cannot be determined. -func getPodUID(pod *rktapi.Pod) kubetypes.UID { - for _, anno := range pod.Annotations { - if anno.Key == types.KubernetesPodUIDLabel { - return kubetypes.UID(anno.Value) - } - } - return kubetypes.UID("") -} - -// podIsActive returns true if the pod is embryo, preparing or running. -// If a pod is prepared, it is not guaranteed to be active (e.g. the systemd -// service might fail). -func podIsActive(pod *rktapi.Pod) bool { - return pod.State == rktapi.PodState_POD_STATE_EMBRYO || - pod.State == rktapi.PodState_POD_STATE_PREPARING || - pod.State == rktapi.PodState_POD_STATE_RUNNING -} - -// GetNetNS returns the network namespace path for the given container -func (r *Runtime) GetNetNS(containerID kubecontainer.ContainerID) (string, error) { - // Currently the containerID is a UUID for a network namespace - // This hack is a way to create an unique network namespace for each new starting/restarting Pod - // We can do this because we played the same trick in - // `networkPlugin.SetUpPod` and `networkPlugin.TearDownPod`. - // See https://github.com/kubernetes/kubernetes/issues/45149 - return netnsPathFromName(containerID.ID), nil -} - -func (r *Runtime) GetPodContainerID(pod *kubecontainer.Pod) (kubecontainer.ContainerID, error) { - return kubecontainer.ContainerID{ID: string(pod.ID)}, nil -} - -func (r *Runtime) getKubernetesDirective(serviceFilePath string) (podService podServiceDirective, err error) { - f, err := os.Open(serviceFilePath) - if err != nil { - return podService, err - } - defer f.Close() - - opts, err := unit.Deserialize(f) - if err != nil { - return podService, err - } - - var hostnetwork, networkNamespace string - for _, o := range opts { - if o.Section != unitKubernetesSection { - continue - } - switch o.Name { - case unitPodUID: - podService.id = o.Value - case unitPodName: - podService.name = o.Value - case unitPodNamespace: - podService.namespace = o.Value - case unitPodHostNetwork: - hostnetwork = o.Value - case unitPodNetworkNamespace: - networkNamespace = o.Value - } - - if podService.id != "" && podService.name != "" && podService.namespace != "" && hostnetwork != "" && networkNamespace != "" { - podService.hostNetwork, err = strconv.ParseBool(hostnetwork) - podService.networkNamespace = kubecontainer.ContainerID{ID: networkNamespace} - if err != nil { - return podService, err - } - return podService, nil - } - } - - return podService, fmt.Errorf("failed to parse pod from file %s", serviceFilePath) -} - -func (r *Runtime) DeleteContainer(containerID kubecontainer.ContainerID) error { - return fmt.Errorf("unimplemented") -} - -// Collects all the systemd units for k8s Pods -func (r *Runtime) getPodSystemdServiceFiles() ([]os.FileInfo, error) { - // Get all the current units - files, err := r.os.ReadDir(systemdServiceDir) - if err != nil { - glog.Errorf("rkt: Failed to read the systemd service directory: %v", err) - return files, err - } - - // Keep only k8s unit files - k8sSystemdServiceFiles := files[:0] - for _, f := range files { - if strings.HasPrefix(f.Name(), kubernetesUnitPrefix) { - k8sSystemdServiceFiles = append(k8sSystemdServiceFiles, f) - } - } - return k8sSystemdServiceFiles, err -} - -// GarbageCollect collects the pods/containers. -// After one GC iteration: -// - The deleted pods will be removed. -// - If the number of containers exceeds gcPolicy.MaxContainers, -// then containers whose ages are older than gcPolicy.minAge will -// be removed. -func (r *Runtime) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy, allSourcesReady bool, _ bool) error { - var errlist []error - var totalInactiveContainers int - var inactivePods []*rktapi.Pod - var removeCandidates []*rktapi.Pod - var allPods = map[string]*rktapi.Pod{} - - glog.V(4).Infof("rkt: Garbage collecting triggered with policy %v", gcPolicy) - - // GC all inactive systemd service files and pods. - files, err := r.getPodSystemdServiceFiles() - if err != nil { - return err - } - - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - resp, err := r.apisvc.ListPods(ctx, &rktapi.ListPodsRequest{Filters: kubernetesPodsFilters()}) - if err != nil { - glog.Errorf("rkt: Failed to list pods: %v", err) - return err - } - - // Mark inactive pods. - for _, pod := range resp.Pods { - allPods[pod.Id] = pod - if !podIsActive(pod) { - uid := getPodUID(pod) - if uid == kubetypes.UID("") { - glog.Errorf("rkt: Cannot get the UID of pod %q, pod is broken, will remove it", pod.Id) - removeCandidates = append(removeCandidates, pod) - continue - } - if r.podDeletionProvider.IsPodDeleted(uid) && allSourcesReady { - removeCandidates = append(removeCandidates, pod) - continue - } - - inactivePods = append(inactivePods, pod) - totalInactiveContainers = totalInactiveContainers + len(pod.Apps) - } - } - - // Remove any orphan service files. - for _, f := range files { - serviceName := f.Name() - rktUUID := getRktUUIDFromServiceFileName(serviceName) - if _, ok := allPods[rktUUID]; !ok { - glog.V(4).Infof("rkt: No rkt pod found for service file %q, will remove it", serviceName) - - if err := r.cleanupByPodId(rktUUID); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to clean up rkt pod %q: %v", rktUUID, err)) - } - } - } - - sort.Sort(podsByCreatedAt(inactivePods)) - - // Enforce GCPolicy.MaxContainers. - for _, pod := range inactivePods { - if totalInactiveContainers <= gcPolicy.MaxContainers { - break - } - creationTime := time.Unix(0, pod.CreatedAt) - if creationTime.Add(gcPolicy.MinAge).Before(time.Now()) { - // The pod is old and we are exceeding the MaxContainers limit. - // Delete the pod. - removeCandidates = append(removeCandidates, pod) - totalInactiveContainers = totalInactiveContainers - len(pod.Apps) - } - } - - // Remove pods and their service files. - for _, pod := range removeCandidates { - if err := r.removePod(pod); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to clean up rkt pod %q: %v", pod.Id, err)) - } - } - - return errors.NewAggregate(errlist) -} - -// Read kubernetes pod UUID, namespace, netns and name from systemd service file and -// use that to clean up any pod network that may still exist. -func (r *Runtime) cleanupPodNetworkFromServiceFile(serviceFilePath string) error { - podService, err := r.unitGetter.getKubernetesDirective(serviceFilePath) - if err != nil { - return err - } - return r.cleanupPodNetwork(&v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - UID: kubetypes.UID(podService.id), - Name: podService.name, - Namespace: podService.namespace, - }, - Spec: v1.PodSpec{ - HostNetwork: podService.hostNetwork, - }, - }, podService.networkNamespace) -} - -// Remove the touched file created by ExecStartPost in the systemd service file -func (r *Runtime) removeFinishedMarkerFile(serviceName string) error { - serviceFile := serviceFilePath(serviceName) - podDetail, err := r.unitGetter.getKubernetesDirective(serviceFile) - if err != nil { - return err - } - podDir := r.runtimeHelper.GetPodDir(kubetypes.UID(podDetail.id)) - finishedFile := podFinishedMarkerPath(podDir, getRktUUIDFromServiceFileName(serviceName)) - return r.os.Remove(finishedFile) -} - -// Iter over each container in the pod to delete its termination log file -func (r *Runtime) removeTerminationFiles(pod *rktapi.Pod) (errlist []error) { - // container == app - for _, app := range pod.Apps { - for _, annotation := range app.Annotations { - if annotation.GetKey() == k8sRktTerminationMessagePathAnno { - if err := r.os.Remove(annotation.GetValue()); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to remove for pod %q container file %v", pod.Id, err)) - } - } - } - } - return errlist -} - -func (r *Runtime) cleanupByPodId(podID string) (errlist []error) { - serviceName := makePodServiceFileName(podID) - serviceFile := serviceFilePath(serviceName) - - if err := r.cleanupPodNetworkFromServiceFile(serviceFile); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to clean up pod network from service %q: %v, the network may not be around already", serviceName, err)) - } - - // GC finished marker, termination-log file, systemd service files as well. - if err := r.systemd.ResetFailedUnit(serviceName); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to reset the failed systemd service %q: %v", serviceName, err)) - } - if err := r.removeFinishedMarkerFile(serviceName); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to remove finished file %q for unit %q: %v", serviceName, podID, err)) - } - if err := r.os.Remove(serviceFile); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to remove service file %q for pod %q: %v", serviceFile, podID, err)) - } - return errlist -} - -// removePod calls 'rkt rm $UUID' to delete a rkt pod, -// it also remove the systemd service file, -// the finished-* marker and the termination-log files -// related to the pod. -func (r *Runtime) removePod(pod *rktapi.Pod) error { - var errlist []error - glog.V(4).Infof("rkt: GC is removing pod %q", pod) - - if err := r.cleanupByPodId(pod.Id); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to remove pod %q: %v", pod.Id, err)) - } - if err := r.removeTerminationFiles(pod); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to clean up pod TerminationMessageFile %q: %v", pod.Id, err)) - } - - if _, err := r.cli.RunCommand(nil, "rm", pod.Id); err != nil { - errlist = append(errlist, fmt.Errorf("rkt: Failed to remove pod %q: %v", pod.Id, err)) - } - - return errors.NewAggregate(errlist) -} - -// rktExitError implements /pkg/util/exec.ExitError interface. -type rktExitError struct{ *exec.ExitError } - -var _ utilexec.ExitError = &rktExitError{} - -func (r *rktExitError) ExitStatus() int { - if status, ok := r.Sys().(syscall.WaitStatus); ok { - return status.ExitStatus() - } - return 0 -} - -func newRktExitError(e error) error { - if exitErr, ok := e.(*exec.ExitError); ok { - return &rktExitError{exitErr} - } - return e -} - -func (r *Runtime) AttachContainer(containerID kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error { - return fmt.Errorf("unimplemented") -} - -// Note: In rkt, the container ID is in the form of "UUID:appName", where UUID is -// the rkt UUID, and appName is the container name. -// TODO(yifan): If the rkt is using lkvm as the stage1 image, then this function will fail. -func (r *Runtime) ExecInContainer(containerID kubecontainer.ContainerID, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error { - glog.V(4).Infof("Rkt execing in container.") - - id, err := parseContainerID(containerID) - if err != nil { - return err - } - args := []string{"enter", fmt.Sprintf("--app=%s", id.appName), id.uuid} - args = append(args, cmd...) - command := buildCommand(r.config, args...) - - if tty { - p, err := kubecontainer.StartPty(command) - if err != nil { - return err - } - defer p.Close() - - // make sure to close the stdout stream - defer stdout.Close() - - kubecontainer.HandleResizing(resize, func(size remotecommand.TerminalSize) { - term.SetSize(p.Fd(), size) - }) - - if stdin != nil { - go io.Copy(p, stdin) - } - if stdout != nil { - go io.Copy(stdout, p) - } - return newRktExitError(command.Wait()) - } - if stdin != nil { - // Use an os.Pipe here as it returns true *os.File objects. - // This way, if you run 'kubectl exec -i bash' (no tty) and type 'exit', - // the call below to command.Run() can unblock because its Stdin is the read half - // of the pipe. - r, w, err := r.os.Pipe() - if err != nil { - return newRktExitError(err) - } - go io.Copy(w, stdin) - - command.Stdin = r - } - if stdout != nil { - command.Stdout = stdout - } - if stderr != nil { - command.Stderr = stderr - } - return newRktExitError(command.Run()) -} - -// PortForward executes socat in the pod's network namespace and copies -// data between stream (representing the user's local connection on their -// computer) and the specified port in the container. -// -// TODO: -// - match cgroups of container -// - should we support nsenter + socat on the host? (current impl) -// - should we support nsenter + socat in a container, running with elevated privs and --pid=host? -// -// TODO(yifan): Merge with the same function in dockertools. -func (r *Runtime) PortForward(pod *kubecontainer.Pod, port int32, stream io.ReadWriteCloser) error { - glog.V(4).Infof("Rkt port forwarding in container.") - - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - listResp, err := r.apisvc.ListPods(ctx, &rktapi.ListPodsRequest{ - Detail: true, - Filters: runningKubernetesPodFilters(pod.ID), - }) - if err != nil { - return fmt.Errorf("couldn't list pods: %v", err) - } - - if len(listResp.Pods) != 1 { - var podlist []string - for _, p := range listResp.Pods { - podlist = append(podlist, p.Id) - } - return fmt.Errorf("more than one running rkt pod for the kubernetes pod [%s]", strings.Join(podlist, ", ")) - } - listPod := listResp.Pods[0] - - socatPath, lookupErr := exec.LookPath("socat") - if lookupErr != nil { - return fmt.Errorf("unable to do port forwarding: socat not found.") - } - - // Check in config and in annotations if we're running kvm flavor - isKvm := strings.Contains(r.config.Stage1Image, "kvm") - for _, anno := range listPod.Annotations { - if anno.Key == k8sRktStage1NameAnno { - isKvm = strings.Contains(anno.Value, "kvm") - break - } - } - - var args []string - var fwCaller string - if isKvm { - podNetworks := listPod.GetNetworks() - if podNetworks == nil { - return fmt.Errorf("unable to get networks") - } - args = []string{"-", fmt.Sprintf("TCP4:%s:%d", podNetworks[0].Ipv4, port)} - fwCaller = socatPath - } else { - args = []string{"-t", fmt.Sprintf("%d", listPod.Pid), "-n", socatPath, "-", fmt.Sprintf("TCP4:localhost:%d", port)} - nsenterPath, lookupErr := exec.LookPath("nsenter") - if lookupErr != nil { - return fmt.Errorf("unable to do port forwarding: nsenter not found") - } - fwCaller = nsenterPath - } - - command := exec.Command(fwCaller, args...) - command.Stdout = stream - - // If we use Stdin, command.Run() won't return until the goroutine that's copying - // from stream finishes. Unfortunately, if you have a client like telnet connected - // via port forwarding, as long as the user's telnet client is connected to the user's - // local listener that port forwarding sets up, the telnet session never exits. This - // means that even if socat has finished running, command.Run() won't ever return - // (because the client still has the connection and stream open). - // - // The work around is to use StdinPipe(), as Wait() (called by Run()) closes the pipe - // when the command (socat) exits. - inPipe, err := command.StdinPipe() - if err != nil { - return fmt.Errorf("unable to do port forwarding: error creating stdin pipe: %v", err) - } - go func() { - io.Copy(inPipe, stream) - inPipe.Close() - }() - - return command.Run() -} - -// UpdatePodCIDR updates the runtimeconfig with the podCIDR. -// Currently no-ops, just implemented to satisfy the cri. -func (r *Runtime) UpdatePodCIDR(podCIDR string) error { - return nil -} - -// appStateToContainerState converts rktapi.AppState to kubecontainer.ContainerState. -func appStateToContainerState(state rktapi.AppState) kubecontainer.ContainerState { - switch state { - case rktapi.AppState_APP_STATE_RUNNING: - return kubecontainer.ContainerStateRunning - case rktapi.AppState_APP_STATE_EXITED: - return kubecontainer.ContainerStateExited - } - return kubecontainer.ContainerStateUnknown -} - -// getPodInfo returns the pod manifest, creation time and restart count of the pod. -func getPodInfo(pod *rktapi.Pod) (podManifest *appcschema.PodManifest, restartCount int, err error) { - // TODO(yifan): The manifest is only used for getting the annotations. - // Consider to let the server to unmarshal the annotations. - var manifest appcschema.PodManifest - if err = json.Unmarshal(pod.Manifest, &manifest); err != nil { - return - } - - if countString, ok := manifest.Annotations.Get(k8sRktRestartCountAnno); ok { - restartCount, err = strconv.Atoi(countString) - if err != nil { - return - } - } - - return &manifest, restartCount, nil -} - -// populateContainerStatus fills the container status according to the app's information. -func populateContainerStatus(pod rktapi.Pod, app rktapi.App, runtimeApp appcschema.RuntimeApp, restartCount int, finishedTime time.Time) (*kubecontainer.ContainerStatus, error) { - hashStr, ok := runtimeApp.Annotations.Get(k8sRktContainerHashAnno) - if !ok { - return nil, fmt.Errorf("No container hash in pod manifest") - } - - hashNum, err := strconv.ParseUint(hashStr, 10, 64) - if err != nil { - return nil, err - } - - var reason, message string - if app.State == rktapi.AppState_APP_STATE_EXITED { - if app.ExitCode == 0 { - reason = "Completed" - } else { - reason = "Error" - } - } - - terminationMessagePath, ok := runtimeApp.Annotations.Get(k8sRktTerminationMessagePathAnno) - if ok { - if data, err := ioutil.ReadFile(terminationMessagePath); err != nil { - message = fmt.Sprintf("Error on reading termination-log %s: %v", terminationMessagePath, err) - } else { - message = string(data) - } - } - - createdTime := time.Unix(0, pod.CreatedAt) - startedTime := time.Unix(0, pod.StartedAt) - - return &kubecontainer.ContainerStatus{ - ID: buildContainerID(&containerID{uuid: pod.Id, appName: app.Name}), - Name: app.Name, - State: appStateToContainerState(app.State), - CreatedAt: createdTime, - StartedAt: startedTime, - FinishedAt: finishedTime, - ExitCode: int(app.ExitCode), - // By default, the version returned by rkt API service will be "latest" if not specified. - Image: fmt.Sprintf("%s:%s", app.Image.Name, app.Image.Version), - ImageID: "rkt://" + app.Image.Id, // TODO(yifan): Add the prefix only in v1.PodStatus. - Hash: hashNum, - // TODO(yifan): Note that now all apps share the same restart count, this might - // change once apps don't share the same lifecycle. - // See https://github.com/appc/spec/pull/547. - RestartCount: restartCount, - Reason: reason, - Message: message, - }, nil -} - -// from a running systemd unit, return the network namespace of a Pod -// this field is inside the X-Kubernetes directive -func (r *Runtime) getNetworkNamespace(uid kubetypes.UID, latestPod *rktapi.Pod) (networkNamespace kubecontainer.ContainerID, err error) { - serviceFiles, err := r.getPodSystemdServiceFiles() - if err != nil { - return networkNamespace, err - } - - for _, f := range serviceFiles { - fileName := f.Name() - if latestPod.Id == getRktUUIDFromServiceFileName(fileName) { - podService, err := r.unitGetter.getKubernetesDirective(serviceFilePath(fileName)) - if err != nil { - return networkNamespace, err - } - return podService.networkNamespace, nil - } - } - - return networkNamespace, fmt.Errorf("Pod %q containing rktPod %q haven't find a corresponding NetworkNamespace in %d systemd units", uid, latestPod.Id, len(serviceFiles)) -} - -// GetPodStatus returns the status for a pod specified by a given UID, name, -// and namespace. It will attempt to find pod's information via a request to -// the rkt api server. -// An error will be returned if the api server returns an error. If the api -// server doesn't error, but doesn't provide meaningful information about the -// pod, a status with no information (other than the passed in arguments) is -// returned anyways. -func (r *Runtime) GetPodStatus(uid kubetypes.UID, name, namespace string) (*kubecontainer.PodStatus, error) { - podStatus := &kubecontainer.PodStatus{ - ID: uid, - Name: name, - Namespace: namespace, - } - - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - listResp, err := r.apisvc.ListPods(ctx, &rktapi.ListPodsRequest{ - Detail: true, - Filters: kubernetesPodFilters(uid), - }) - if err != nil { - return nil, fmt.Errorf("couldn't list pods: %v", err) - } - - var latestPod *rktapi.Pod - var latestRestartCount int = -1 - - // In this loop, we group all containers from all pods together, - // also we try to find the latest pod, so we can fill other info of the pod below. - for _, pod := range listResp.Pods { - manifest, restartCount, err := getPodInfo(pod) - if err != nil { - glog.Warningf("rkt: Couldn't get necessary info from the rkt pod, (uuid %q): %v", pod.Id, err) - continue - } - - if restartCount > latestRestartCount { - latestPod = pod - latestRestartCount = restartCount - } - - finishedTime := r.podFinishedAt(uid, pod.Id) - for i, app := range pod.Apps { - // The order of the apps is determined by the rkt pod manifest. - cs, err := populateContainerStatus(*pod, *app, manifest.Apps[i], restartCount, finishedTime) - if err != nil { - glog.Warningf("rkt: Failed to populate container status(uuid %q, app %q): %v", pod.Id, app.Name, err) - continue - } - podStatus.ContainerStatuses = append(podStatus.ContainerStatuses, cs) - } - } - - if latestPod == nil { - glog.Warningf("No latestPod: rkt api-svc returns [%d]rktPods, cannot fill podStatus.IP", len(listResp.Pods)) - return podStatus, nil - } - - // If we are running no-op network plugin, then get the pod IP from the rkt pod status. - if r.network.PluginName() == network.DefaultPluginName { - for _, n := range latestPod.Networks { - if n.Name == defaultNetworkName { - podStatus.IP = n.Ipv4 - break - } - } - return podStatus, nil - } - - networkNamespace, err := r.unitGetter.getNetworkNamespace(uid, latestPod) - if err != nil { - glog.Warningf("networkNamespace: %v", err) - } - status, err := r.network.GetPodNetworkStatus(namespace, name, networkNamespace) - if err != nil { - glog.Warningf("rkt: %v", err) - } else if status != nil { - // status can be nil when the pod is running on the host network, - // in which case the pod IP will be populated by the upper layer. - podStatus.IP = status.IP.String() - } - - return podStatus, nil -} - -// getOSReleaseInfo reads /etc/os-release and returns a map -// that contains the key value pairs in that file. -func getOSReleaseInfo() (map[string]string, error) { - result := make(map[string]string) - - path := "/etc/os-release" - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := scanner.Text() - if len(strings.TrimSpace(line)) == 0 { - // Skips empty lines - continue - } - - info := strings.SplitN(line, "=", 2) - if len(info) != 2 { - glog.Warningf("Unexpected entry in os-release %q", line) - continue - } - result[info[0]] = info[1] - } - if err := scanner.Err(); err != nil { - return nil, err - } - return result, nil -} - -// convertKubeMounts creates appc volumes and mount points according to the given mounts. -// Only one volume will be created for every unique host path. -// Only one mount point will be created for every unique container path. -func convertKubeMounts(mounts []kubecontainer.Mount) ([]appctypes.Volume, []appctypes.MountPoint) { - volumeMap := make(map[string]*appctypes.Volume) - mountPointMap := make(map[string]*appctypes.MountPoint) - - for _, mnt := range mounts { - readOnly := mnt.ReadOnly - - if _, existed := volumeMap[mnt.HostPath]; !existed { - volumeMap[mnt.HostPath] = &appctypes.Volume{ - Name: *appctypes.MustACName(string(uuid.NewUUID())), - Kind: "host", - Source: mnt.HostPath, - ReadOnly: &readOnly, - } - } - - if _, existed := mountPointMap[mnt.ContainerPath]; existed { - glog.Warningf("Multiple mount points with the same container path %v, ignore it", mnt) - continue - } - - mountPointMap[mnt.ContainerPath] = &appctypes.MountPoint{ - Name: volumeMap[mnt.HostPath].Name, - Path: mnt.ContainerPath, - ReadOnly: readOnly, - } - } - - volumes := make([]appctypes.Volume, 0, len(volumeMap)) - mountPoints := make([]appctypes.MountPoint, 0, len(mountPointMap)) - - for _, vol := range volumeMap { - volumes = append(volumes, *vol) - } - for _, mnt := range mountPointMap { - mountPoints = append(mountPoints, *mnt) - } - - return volumes, mountPoints -} - -// convertKubePortMappings creates appc container ports and host ports according to the given port mappings. -// The container ports and host ports are mapped by PortMapping.Name. -func convertKubePortMappings(portMappings []kubecontainer.PortMapping) ([]appctypes.Port, []appctypes.ExposedPort) { - containerPorts := make([]appctypes.Port, 0, len(portMappings)) - hostPorts := make([]appctypes.ExposedPort, 0, len(portMappings)) - - for _, p := range portMappings { - // This matches the docker code's behaviour. - if p.HostPort == 0 { - continue - } - - portName := convertToACName(p.Name) - containerPorts = append(containerPorts, appctypes.Port{ - Name: portName, - Protocol: string(p.Protocol), - Port: uint(p.ContainerPort), - }) - - hostPorts = append(hostPorts, appctypes.ExposedPort{ - Name: portName, - HostPort: uint(p.HostPort), - }) - } - - return containerPorts, hostPorts -} - -func newNoNewPrivilegesIsolator(v bool) (*appctypes.Isolator, error) { - b := fmt.Sprintf(`{"name": "%s", "value": %t}`, appctypes.LinuxNoNewPrivilegesName, v) - - i := &appctypes.Isolator{ - Name: appctypes.LinuxNoNewPrivilegesName, - } - if err := i.UnmarshalJSON([]byte(b)); err != nil { - return nil, err - } - - return i, nil -} diff --git a/pkg/kubelet/rkt/rkt_test.go b/pkg/kubelet/rkt/rkt_test.go deleted file mode 100644 index 8e5f6cdd812..00000000000 --- a/pkg/kubelet/rkt/rkt_test.go +++ /dev/null @@ -1,2130 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 rkt - -import ( - "encoding/json" - "fmt" - "net" - "os" - "path/filepath" - "sort" - "strings" - "testing" - "time" - - appcschema "github.com/appc/spec/schema" - appctypes "github.com/appc/spec/schema/types" - "github.com/coreos/go-systemd/unit" - rktapi "github.com/coreos/rkt/api/v1alpha" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kubetypes "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/errors" - utiltesting "k8s.io/client-go/util/testing" - kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" - containertesting "k8s.io/kubernetes/pkg/kubelet/container/testing" - "k8s.io/kubernetes/pkg/kubelet/lifecycle" - "k8s.io/kubernetes/pkg/kubelet/network" - "k8s.io/kubernetes/pkg/kubelet/network/kubenet" - nettest "k8s.io/kubernetes/pkg/kubelet/network/testing" - "k8s.io/kubernetes/pkg/kubelet/types" - "k8s.io/utils/exec" - fakeexec "k8s.io/utils/exec/testing" -) - -func mustMarshalPodManifest(man *appcschema.PodManifest) []byte { - manblob, err := json.Marshal(man) - if err != nil { - panic(err) - } - return manblob -} - -func mustMarshalImageManifest(man *appcschema.ImageManifest) []byte { - manblob, err := json.Marshal(man) - if err != nil { - panic(err) - } - return manblob -} - -func mustRktHash(hash string) *appctypes.Hash { - h, err := appctypes.NewHash(hash) - if err != nil { - panic(err) - } - return h -} - -func makeRktPod(rktPodState rktapi.PodState, - rktPodID, podUID, podName, podNamespace string, podCreatedAt, podStartedAt int64, - podRestartCount string, appNames, imgIDs, imgNames, - containerHashes []string, appStates []rktapi.AppState, - exitcodes []int32, ips map[string]string) *rktapi.Pod { - - podManifest := &appcschema.PodManifest{ - ACKind: appcschema.PodManifestKind, - ACVersion: appcschema.AppContainerVersion, - Annotations: appctypes.Annotations{ - appctypes.Annotation{ - Name: *appctypes.MustACIdentifier(k8sRktKubeletAnno), - Value: k8sRktKubeletAnnoValue, - }, - appctypes.Annotation{ - Name: *appctypes.MustACIdentifier(types.KubernetesPodUIDLabel), - Value: podUID, - }, - appctypes.Annotation{ - Name: *appctypes.MustACIdentifier(types.KubernetesPodNameLabel), - Value: podName, - }, - appctypes.Annotation{ - Name: *appctypes.MustACIdentifier(types.KubernetesPodNamespaceLabel), - Value: podNamespace, - }, - appctypes.Annotation{ - Name: *appctypes.MustACIdentifier(k8sRktRestartCountAnno), - Value: podRestartCount, - }, - }, - } - - appNum := len(appNames) - if appNum != len(imgNames) || - appNum != len(imgIDs) || - appNum != len(containerHashes) || - appNum != len(appStates) { - panic("inconsistent app number") - } - - apps := make([]*rktapi.App, appNum) - for i := range appNames { - apps[i] = &rktapi.App{ - Name: appNames[i], - State: appStates[i], - Image: &rktapi.Image{ - Id: imgIDs[i], - Name: imgNames[i], - Version: "latest", - Manifest: mustMarshalImageManifest( - &appcschema.ImageManifest{ - ACKind: appcschema.ImageManifestKind, - ACVersion: appcschema.AppContainerVersion, - Name: *appctypes.MustACIdentifier(imgNames[i]), - Annotations: appctypes.Annotations{ - appctypes.Annotation{ - Name: *appctypes.MustACIdentifier(k8sRktContainerHashAnno), - Value: containerHashes[i], - }, - }, - }, - ), - }, - ExitCode: exitcodes[i], - } - podManifest.Apps = append(podManifest.Apps, appcschema.RuntimeApp{ - Name: *appctypes.MustACName(appNames[i]), - Image: appcschema.RuntimeImage{ID: *mustRktHash("sha512-foo")}, - Annotations: appctypes.Annotations{ - appctypes.Annotation{ - Name: *appctypes.MustACIdentifier(k8sRktContainerHashAnno), - Value: containerHashes[i], - }, - }, - }) - } - - var networks []*rktapi.Network - for name, ip := range ips { - networks = append(networks, &rktapi.Network{Name: name, Ipv4: ip}) - } - - return &rktapi.Pod{ - Id: rktPodID, - State: rktPodState, - Apps: apps, - Manifest: mustMarshalPodManifest(podManifest), - StartedAt: podStartedAt, - CreatedAt: podCreatedAt, - Networks: networks, - } -} - -func TestCheckVersion(t *testing.T) { - fr := newFakeRktInterface() - fs := newFakeSystemd() - r := &Runtime{apisvc: fr, systemd: fs} - - fr.info = rktapi.Info{ - RktVersion: "1.2.3+git", - AppcVersion: "1.2.4+git", - ApiVersion: "1.2.6-alpha", - } - fs.version = "100" - tests := []struct { - minimumRktBinVersion string - minimumRktApiVersion string - minimumSystemdVersion string - err error - calledGetInfo bool - calledSystemVersion bool - }{ - // Good versions. - { - "1.2.3", - "1.2.5", - "99", - nil, - true, - true, - }, - // Good versions. - { - "1.2.3+git", - "1.2.6-alpha", - "100", - nil, - true, - true, - }, - // Requires greater binary version. - { - "1.2.4", - "1.2.6-alpha", - "100", - fmt.Errorf("rkt: binary version is too old(%v), requires at least %v", fr.info.RktVersion, "1.2.4"), - true, - true, - }, - // Requires greater API version. - { - "1.2.3", - "1.2.6", - "100", - fmt.Errorf("rkt: API version is too old(%v), requires at least %v", fr.info.ApiVersion, "1.2.6"), - true, - true, - }, - // Requires greater API version. - { - "1.2.3", - "1.2.7", - "100", - fmt.Errorf("rkt: API version is too old(%v), requires at least %v", fr.info.ApiVersion, "1.2.7"), - true, - true, - }, - // Requires greater systemd version. - { - "1.2.3", - "1.2.7", - "101", - fmt.Errorf("rkt: systemd version(%v) is too old, requires at least %v", fs.version, "101"), - false, - true, - }, - } - - for i, tt := range tests { - testCaseHint := fmt.Sprintf("test case #%d", i) - err := r.checkVersion(tt.minimumRktBinVersion, tt.minimumRktApiVersion, tt.minimumSystemdVersion) - assert.Equal(t, tt.err, err, testCaseHint) - - if tt.calledGetInfo { - assert.Equal(t, fr.called, []string{"GetInfo"}, testCaseHint) - } - if tt.calledSystemVersion { - assert.Equal(t, fs.called, []string{"Version"}, testCaseHint) - } - if err == nil { - assert.Equal(t, fr.info.RktVersion, r.versions.binVersion.String(), testCaseHint) - assert.Equal(t, fr.info.ApiVersion, r.versions.apiVersion.String(), testCaseHint) - } - fr.CleanCalls() - fs.CleanCalls() - } -} - -func TestListImages(t *testing.T) { - fr := newFakeRktInterface() - fs := newFakeSystemd() - r := &Runtime{apisvc: fr, systemd: fs} - - tests := []struct { - images []*rktapi.Image - expected []kubecontainer.Image - }{ - {nil, []kubecontainer.Image{}}, - { - []*rktapi.Image{ - { - Id: "sha512-a2fb8f390702", - Name: "quay.io/coreos/alpine-sh", - Version: "latest", - }, - }, - []kubecontainer.Image{ - { - ID: "sha512-a2fb8f390702", - RepoTags: []string{"quay.io/coreos/alpine-sh:latest"}, - }, - }, - }, - { - []*rktapi.Image{ - { - Id: "sha512-a2fb8f390702", - Name: "quay.io/coreos/alpine-sh", - Version: "latest", - Size: 400, - }, - { - Id: "sha512-c6b597f42816", - Name: "coreos.com/rkt/stage1-coreos", - Version: "0.10.0", - Size: 400, - }, - }, - []kubecontainer.Image{ - { - ID: "sha512-a2fb8f390702", - RepoTags: []string{"quay.io/coreos/alpine-sh:latest"}, - Size: 400, - }, - { - ID: "sha512-c6b597f42816", - RepoTags: []string{"coreos.com/rkt/stage1-coreos:0.10.0"}, - Size: 400, - }, - }, - }, - { - []*rktapi.Image{ - { - Id: "sha512-a2fb8f390702", - Name: "quay.io_443/coreos/alpine-sh", - Version: "latest", - Annotations: []*rktapi.KeyValue{ - { - Key: appcDockerRegistryURL, - Value: "quay.io:443", - }, - { - Key: appcDockerRepository, - Value: "coreos/alpine-sh", - }, - }, - Size: 400, - }, - }, - []kubecontainer.Image{ - { - ID: "sha512-a2fb8f390702", - RepoTags: []string{"quay.io:443/coreos/alpine-sh:latest"}, - Size: 400, - }, - }, - }, - } - - for i, tt := range tests { - fr.images = tt.images - - images, err := r.ListImages() - if err != nil { - t.Errorf("%v", err) - } - assert.Equal(t, tt.expected, images) - assert.Equal(t, fr.called, []string{"ListImages"}, fmt.Sprintf("test case %d: unexpected called list", i)) - - fr.CleanCalls() - } -} - -func TestGetPods(t *testing.T) { - fr := newFakeRktInterface() - fs := newFakeSystemd() - r := &Runtime{apisvc: fr, systemd: fs} - - ns := func(seconds int64) int64 { - return seconds * 1e9 - } - - tests := []struct { - pods []*rktapi.Pod - result []*kubecontainer.Pod - }{ - // No pods. - {}, - // One pod. - { - []*rktapi.Pod{ - makeRktPod(rktapi.PodState_POD_STATE_RUNNING, - "uuid-4002", "42", "guestbook", "default", - ns(10), ns(10), "7", - []string{"app-1", "app-2"}, - []string{"img-id-1", "img-id-2"}, - []string{"img-name-1", "img-name-2"}, - []string{"1001", "1002"}, - []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, - []int32{0, 0}, - nil, - ), - }, - []*kubecontainer.Pod{ - { - ID: "42", - Name: "guestbook", - Namespace: "default", - Containers: []*kubecontainer.Container{ - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), - Name: "app-1", - Image: "img-name-1:latest", - ImageID: "img-id-1", - Hash: 1001, - State: "running", - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), - Name: "app-2", - Image: "img-name-2:latest", - ImageID: "img-id-2", - Hash: 1002, - State: "exited", - }, - }, - }, - }, - }, - // Multiple pods. - { - []*rktapi.Pod{ - makeRktPod(rktapi.PodState_POD_STATE_RUNNING, - "uuid-4002", "42", "guestbook", "default", - ns(10), ns(20), "7", - []string{"app-1", "app-2"}, - []string{"img-id-1", "img-id-2"}, - []string{"img-name-1", "img-name-2"}, - []string{"1001", "1002"}, - []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, - []int32{0, 0}, - nil, - ), - makeRktPod(rktapi.PodState_POD_STATE_EXITED, - "uuid-4003", "43", "guestbook", "default", - ns(30), ns(40), "7", - []string{"app-11", "app-22"}, - []string{"img-id-11", "img-id-22"}, - []string{"img-name-11", "img-name-22"}, - []string{"10011", "10022"}, - []rktapi.AppState{rktapi.AppState_APP_STATE_EXITED, rktapi.AppState_APP_STATE_EXITED}, - []int32{0, 0}, - nil, - ), - makeRktPod(rktapi.PodState_POD_STATE_EXITED, - "uuid-4004", "43", "guestbook", "default", - ns(50), ns(60), "8", - []string{"app-11", "app-22"}, - []string{"img-id-11", "img-id-22"}, - []string{"img-name-11", "img-name-22"}, - []string{"10011", "10022"}, - []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_RUNNING}, - []int32{0, 0}, - nil, - ), - }, - []*kubecontainer.Pod{ - { - ID: "42", - Name: "guestbook", - Namespace: "default", - Containers: []*kubecontainer.Container{ - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), - Name: "app-1", - Image: "img-name-1:latest", - ImageID: "img-id-1", - Hash: 1001, - State: "running", - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), - Name: "app-2", - Image: "img-name-2:latest", - ImageID: "img-id-2", - Hash: 1002, - State: "exited", - }, - }, - }, - { - ID: "43", - Name: "guestbook", - Namespace: "default", - Containers: []*kubecontainer.Container{ - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-11"), - Name: "app-11", - Image: "img-name-11:latest", - ImageID: "img-id-11", - Hash: 10011, - State: "exited", - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-22"), - Name: "app-22", - Image: "img-name-22:latest", - ImageID: "img-id-22", - Hash: 10022, - State: "exited", - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4004:app-11"), - Name: "app-11", - Image: "img-name-11:latest", - ImageID: "img-id-11", - Hash: 10011, - State: "running", - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4004:app-22"), - Name: "app-22", - Image: "img-name-22:latest", - ImageID: "img-id-22", - Hash: 10022, - State: "running", - }, - }, - }, - }, - }, - } - - for i, tt := range tests { - testCaseHint := fmt.Sprintf("test case #%d", i) - fr.pods = tt.pods - - pods, err := r.GetPods(true) - if err != nil { - t.Errorf("test case #%d: unexpected error: %v", i, err) - } - - assert.Equal(t, tt.result, pods, testCaseHint) - assert.Equal(t, []string{"ListPods"}, fr.called, fmt.Sprintf("test case %d: unexpected called list", i)) - - fr.CleanCalls() - } -} - -func TestGetPodsFilters(t *testing.T) { - fr := newFakeRktInterface() - fs := newFakeSystemd() - r := &Runtime{apisvc: fr, systemd: fs} - - for _, test := range []struct { - All bool - ExpectedFilters []*rktapi.PodFilter - }{ - { - true, - []*rktapi.PodFilter{ - { - Annotations: []*rktapi.KeyValue{ - { - Key: k8sRktKubeletAnno, - Value: k8sRktKubeletAnnoValue, - }, - }, - }, - }, - }, - { - false, - []*rktapi.PodFilter{ - { - States: []rktapi.PodState{rktapi.PodState_POD_STATE_RUNNING}, - Annotations: []*rktapi.KeyValue{ - { - Key: k8sRktKubeletAnno, - Value: k8sRktKubeletAnnoValue, - }, - }, - }, - }, - }, - } { - _, err := r.GetPods(test.All) - if err != nil { - t.Errorf("%v", err) - } - assert.Equal(t, test.ExpectedFilters, fr.podFilters, "filters didn't match when all=%b", test.All) - } -} - -func TestGetPodStatus(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - fr := newFakeRktInterface() - fs := newFakeSystemd() - fug := newfakeUnitGetter() - fnp := nettest.NewMockNetworkPlugin(ctrl) - fos := &containertesting.FakeOS{} - frh := &containertesting.FakeRuntimeHelper{} - r := &Runtime{ - apisvc: fr, - systemd: fs, - runtimeHelper: frh, - os: fos, - network: network.NewPluginManager(fnp), - unitGetter: fug, - } - - ns := func(seconds int64) int64 { - return seconds * 1e9 - } - - tests := []struct { - networkPluginName string - pods []*rktapi.Pod - result *kubecontainer.PodStatus - }{ - // # case 0, No pods. - { - kubenet.KubenetPluginName, - nil, - &kubecontainer.PodStatus{ID: "42", Name: "guestbook", Namespace: "default"}, - }, - // # case 1, One pod. - { - kubenet.KubenetPluginName, - []*rktapi.Pod{ - makeRktPod(rktapi.PodState_POD_STATE_RUNNING, - "uuid-4002", "42", "guestbook", "default", - ns(10), ns(20), "7", - []string{"app-1", "app-2"}, - []string{"img-id-1", "img-id-2"}, - []string{"img-name-1", "img-name-2"}, - []string{"1001", "1002"}, - []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, - []int32{0, 0}, - nil, - ), - }, - &kubecontainer.PodStatus{ - ID: "42", - Name: "guestbook", - Namespace: "default", - IP: "10.10.10.42", - ContainerStatuses: []*kubecontainer.ContainerStatus{ - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), - Name: "app-1", - State: kubecontainer.ContainerStateRunning, - CreatedAt: time.Unix(10, 0), - StartedAt: time.Unix(20, 0), - FinishedAt: time.Unix(0, 30), - Image: "img-name-1:latest", - ImageID: "rkt://img-id-1", - Hash: 1001, - RestartCount: 7, - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), - Name: "app-2", - State: kubecontainer.ContainerStateExited, - CreatedAt: time.Unix(10, 0), - StartedAt: time.Unix(20, 0), - FinishedAt: time.Unix(0, 30), - Image: "img-name-2:latest", - ImageID: "rkt://img-id-2", - Hash: 1002, - RestartCount: 7, - Reason: "Completed", - }, - }, - }, - }, - // # case 2, One pod with no-op network plugin name. - { - network.DefaultPluginName, - []*rktapi.Pod{ - makeRktPod(rktapi.PodState_POD_STATE_RUNNING, - "uuid-4002", "42", "guestbook", "default", - ns(10), ns(20), "7", - []string{"app-1", "app-2"}, - []string{"img-id-1", "img-id-2"}, - []string{"img-name-1", "img-name-2"}, - []string{"1001", "1002"}, - []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, - []int32{0, 0}, - map[string]string{defaultNetworkName: "10.10.10.22"}, - ), - }, - &kubecontainer.PodStatus{ - ID: "42", - Name: "guestbook", - Namespace: "default", - IP: "10.10.10.22", - ContainerStatuses: []*kubecontainer.ContainerStatus{ - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), - Name: "app-1", - State: kubecontainer.ContainerStateRunning, - CreatedAt: time.Unix(10, 0), - StartedAt: time.Unix(20, 0), - FinishedAt: time.Unix(0, 30), - Image: "img-name-1:latest", - ImageID: "rkt://img-id-1", - Hash: 1001, - RestartCount: 7, - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), - Name: "app-2", - State: kubecontainer.ContainerStateExited, - CreatedAt: time.Unix(10, 0), - StartedAt: time.Unix(20, 0), - FinishedAt: time.Unix(0, 30), - Image: "img-name-2:latest", - ImageID: "rkt://img-id-2", - Hash: 1002, - RestartCount: 7, - Reason: "Completed", - }, - }, - }, - }, - // # case 3, Multiple pods. - { - kubenet.KubenetPluginName, - []*rktapi.Pod{ - makeRktPod(rktapi.PodState_POD_STATE_EXITED, - "uuid-4002", "42", "guestbook", "default", - ns(10), ns(20), "7", - []string{"app-1", "app-2"}, - []string{"img-id-1", "img-id-2"}, - []string{"img-name-1", "img-name-2"}, - []string{"1001", "1002"}, - []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, - []int32{0, 0}, - nil, - ), - makeRktPod(rktapi.PodState_POD_STATE_RUNNING, // The latest pod is running. - "uuid-4003", "42", "guestbook", "default", - ns(10), ns(20), "10", - []string{"app-1", "app-2"}, - []string{"img-id-1", "img-id-2"}, - []string{"img-name-1", "img-name-2"}, - []string{"1001", "1002"}, - []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, - []int32{0, 1}, - nil, - ), - }, - &kubecontainer.PodStatus{ - ID: "42", - Name: "guestbook", - Namespace: "default", - IP: "10.10.10.42", - // Result should contain all containers. - ContainerStatuses: []*kubecontainer.ContainerStatus{ - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), - Name: "app-1", - State: kubecontainer.ContainerStateRunning, - CreatedAt: time.Unix(10, 0), - StartedAt: time.Unix(20, 0), - FinishedAt: time.Unix(0, 30), - Image: "img-name-1:latest", - ImageID: "rkt://img-id-1", - Hash: 1001, - RestartCount: 7, - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), - Name: "app-2", - State: kubecontainer.ContainerStateExited, - CreatedAt: time.Unix(10, 0), - StartedAt: time.Unix(20, 0), - FinishedAt: time.Unix(0, 30), - Image: "img-name-2:latest", - ImageID: "rkt://img-id-2", - Hash: 1002, - RestartCount: 7, - Reason: "Completed", - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-1"), - Name: "app-1", - State: kubecontainer.ContainerStateRunning, - CreatedAt: time.Unix(10, 0), - StartedAt: time.Unix(20, 0), - FinishedAt: time.Unix(0, 30), - Image: "img-name-1:latest", - ImageID: "rkt://img-id-1", - Hash: 1001, - RestartCount: 10, - }, - { - ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-2"), - Name: "app-2", - State: kubecontainer.ContainerStateExited, - CreatedAt: time.Unix(10, 0), - StartedAt: time.Unix(20, 0), - FinishedAt: time.Unix(0, 30), - Image: "img-name-2:latest", - ImageID: "rkt://img-id-2", - Hash: 1002, - RestartCount: 10, - ExitCode: 1, - Reason: "Error", - }, - }, - }, - }, - } - - for i, tt := range tests { - testCaseHint := fmt.Sprintf("test case #%d", i) - fr.pods = tt.pods - - podTimes := map[string]time.Time{} - for _, pod := range tt.pods { - podTimes[podFinishedMarkerPath(r.runtimeHelper.GetPodDir(tt.result.ID), pod.Id)] = tt.result.ContainerStatuses[0].FinishedAt - } - - ctrl := gomock.NewController(t) - - r.os.(*containertesting.FakeOS).StatFn = func(name string) (os.FileInfo, error) { - podTime, ok := podTimes[name] - if !ok { - t.Errorf("osStat called with %v, but only knew about %#v", name, podTimes) - } - mockFI := containertesting.NewMockFileInfo(ctrl) - mockFI.EXPECT().ModTime().Return(podTime) - return mockFI, nil - } - - if tt.networkPluginName == network.DefaultPluginName { - fnp.EXPECT().Name().Return(tt.networkPluginName) - } - - if tt.pods != nil && tt.networkPluginName == kubenet.KubenetPluginName { - fnp.EXPECT().Name().Return(tt.networkPluginName) - if tt.result.IP != "" { - fnp.EXPECT().GetPodNetworkStatus("default", "guestbook", kubecontainer.ContainerID{ID: "42"}). - Return(&network.PodNetworkStatus{IP: net.ParseIP(tt.result.IP)}, nil) - } else { - fnp.EXPECT().GetPodNetworkStatus("default", "guestbook", kubecontainer.ContainerID{ID: "42"}). - Return(nil, fmt.Errorf("no such network")) - // Plugin name only requested again in error case - fnp.EXPECT().Name().Return(tt.networkPluginName) - } - } - - status, err := r.GetPodStatus("42", "guestbook", "default") - if err != nil { - t.Errorf("test case #%d: unexpected error: %v", i, err) - } - - assert.Equal(t, tt.result, status, testCaseHint) - assert.Equal(t, []string{"ListPods"}, fr.called, testCaseHint) - fug.networkNamespace = kubecontainer.ContainerID{} - fr.CleanCalls() - ctrl.Finish() - } -} - -func generateCapRetainIsolator(t *testing.T, caps ...string) appctypes.Isolator { - retain, err := appctypes.NewLinuxCapabilitiesRetainSet(caps...) - if err != nil { - t.Fatalf("Error generating cap retain isolator: %v", err) - } - isolator, err := retain.AsIsolator() - if err != nil { - t.Fatalf("Error generating cap retain isolator: %v", err) - } - return *isolator -} - -func generateCapRevokeIsolator(t *testing.T, caps ...string) appctypes.Isolator { - revoke, err := appctypes.NewLinuxCapabilitiesRevokeSet(caps...) - if err != nil { - t.Fatalf("Error generating cap revoke isolator: %v", err) - } - isolator, err := revoke.AsIsolator() - if err != nil { - t.Fatalf("Error generating cap revoke isolator: %v", err) - } - return *isolator -} - -func generateCPUIsolator(t *testing.T, request, limit string) appctypes.Isolator { - cpu, err := appctypes.NewResourceCPUIsolator(request, limit) - if err != nil { - t.Fatalf("Error generating cpu resource isolator: %v", err) - } - return cpu.AsIsolator() -} - -func generateMemoryIsolator(t *testing.T, request, limit string) appctypes.Isolator { - memory, err := appctypes.NewResourceMemoryIsolator(request, limit) - if err != nil { - t.Fatalf("Error generating memory resource isolator: %v", err) - } - return memory.AsIsolator() -} - -func baseApp(t *testing.T) *appctypes.App { - return &appctypes.App{ - User: "0", - Group: "0", - Exec: appctypes.Exec{"/bin/foo", "bar"}, - SupplementaryGIDs: []int{4, 5, 6}, - WorkingDirectory: "/foo", - Environment: []appctypes.EnvironmentVariable{ - {Name: "env-foo", Value: "bar"}, - }, - MountPoints: []appctypes.MountPoint{ - {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: false}, - }, - Ports: []appctypes.Port{ - {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 4242}, - }, - Isolators: []appctypes.Isolator{ - generateCapRetainIsolator(t, "CAP_SYS_ADMIN"), - generateCapRevokeIsolator(t, "CAP_NET_ADMIN"), - generateCPUIsolator(t, "100m", "200m"), - generateMemoryIsolator(t, "10M", "20M"), - }, - } -} - -func baseImageManifest(t *testing.T) *appcschema.ImageManifest { - img := &appcschema.ImageManifest{App: baseApp(t)} - entrypoint, err := json.Marshal([]string{"/bin/foo"}) - if err != nil { - t.Fatal(err) - } - cmd, err := json.Marshal([]string{"bar"}) - if err != nil { - t.Fatal(err) - } - img.Annotations.Set(*appctypes.MustACIdentifier(appcDockerEntrypoint), string(entrypoint)) - img.Annotations.Set(*appctypes.MustACIdentifier(appcDockerCmd), string(cmd)) - return img -} - -func baseAppWithRootUserGroup(t *testing.T) *appctypes.App { - app := baseApp(t) - app.User, app.Group = "0", "0" - app.Isolators = append(app.Isolators) - return app -} - -type envByName []appctypes.EnvironmentVariable - -func (s envByName) Len() int { return len(s) } -func (s envByName) Less(i, j int) bool { return s[i].Name < s[j].Name } -func (s envByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -type mountsByName []appctypes.MountPoint - -func (s mountsByName) Len() int { return len(s) } -func (s mountsByName) Less(i, j int) bool { return s[i].Name < s[j].Name } -func (s mountsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -type portsByName []appctypes.Port - -func (s portsByName) Len() int { return len(s) } -func (s portsByName) Less(i, j int) bool { return s[i].Name < s[j].Name } -func (s portsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -type isolatorsByName []appctypes.Isolator - -func (s isolatorsByName) Len() int { return len(s) } -func (s isolatorsByName) Less(i, j int) bool { return s[i].Name < s[j].Name } -func (s isolatorsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func sortAppFields(app *appctypes.App) { - sort.Sort(envByName(app.Environment)) - sort.Sort(mountsByName(app.MountPoints)) - sort.Sort(portsByName(app.Ports)) - sort.Sort(isolatorsByName(app.Isolators)) -} - -type sortedStringList []string - -func (s sortedStringList) Len() int { return len(s) } -func (s sortedStringList) Less(i, j int) bool { return s[i] < s[j] } -func (s sortedStringList) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func TestSetApp(t *testing.T) { - tmpDir, err := utiltesting.MkTmpdir("rkt_test") - if err != nil { - t.Fatalf("error creating temp dir: %v", err) - } - defer os.RemoveAll(tmpDir) - - rootUser := int64(0) - nonRootUser := int64(42) - runAsNonRootTrue := true - fsgid := int64(3) - - tests := []struct { - container *v1.Container - mountPoints []appctypes.MountPoint - containerPorts []appctypes.Port - envs []kubecontainer.EnvVar - ctx *v1.SecurityContext - podCtx *v1.PodSecurityContext - supplementalGids []int64 - expect *appctypes.App - err error - }{ - // Nothing should change, but the "User" and "Group" should be filled. - { - container: &v1.Container{}, - mountPoints: []appctypes.MountPoint{}, - containerPorts: []appctypes.Port{}, - envs: []kubecontainer.EnvVar{}, - ctx: nil, - podCtx: nil, - supplementalGids: nil, - expect: baseAppWithRootUserGroup(t), - err: nil, - }, - - // error verifying non-root. - { - container: &v1.Container{}, - mountPoints: []appctypes.MountPoint{}, - containerPorts: []appctypes.Port{}, - envs: []kubecontainer.EnvVar{}, - ctx: &v1.SecurityContext{ - RunAsNonRoot: &runAsNonRootTrue, - RunAsUser: &rootUser, - }, - podCtx: nil, - supplementalGids: nil, - expect: nil, - err: fmt.Errorf("container has no runAsUser and image will run as root"), - }, - - // app's args should be changed. - { - container: &v1.Container{ - Args: []string{"foo"}, - }, - mountPoints: []appctypes.MountPoint{}, - containerPorts: []appctypes.Port{}, - envs: []kubecontainer.EnvVar{}, - ctx: nil, - podCtx: nil, - supplementalGids: nil, - expect: &appctypes.App{ - Exec: appctypes.Exec{"/bin/foo", "foo"}, - User: "0", - Group: "0", - SupplementaryGIDs: []int{4, 5, 6}, - WorkingDirectory: "/foo", - Environment: []appctypes.EnvironmentVariable{ - {Name: "env-foo", Value: "bar"}, - }, - MountPoints: []appctypes.MountPoint{ - {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: false}, - }, - Ports: []appctypes.Port{ - {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 4242}, - }, - Isolators: []appctypes.Isolator{ - generateCapRetainIsolator(t, "CAP_SYS_ADMIN"), - generateCapRevokeIsolator(t, "CAP_NET_ADMIN"), - generateCPUIsolator(t, "100m", "200m"), - generateMemoryIsolator(t, "10M", "20M"), - }, - }, - err: nil, - }, - - // app should be changed. - { - container: &v1.Container{ - Command: []string{"/bin/bar", "$(env-bar)"}, - WorkingDir: tmpDir, - Resources: v1.ResourceRequirements{ - Limits: v1.ResourceList{v1.ResourceCPU: resource.MustParse("50m"), v1.ResourceMemory: resource.MustParse("50M")}, - Requests: v1.ResourceList{v1.ResourceCPU: resource.MustParse("5m"), v1.ResourceMemory: resource.MustParse("5M")}, - }, - }, - mountPoints: []appctypes.MountPoint{ - {Name: *appctypes.MustACName("mnt-bar"), Path: "/mnt-bar", ReadOnly: true}, - }, - containerPorts: []appctypes.Port{ - {Name: *appctypes.MustACName("port-bar"), Protocol: "TCP", Port: 1234}, - }, - envs: []kubecontainer.EnvVar{ - {Name: "env-bar", Value: "foo"}, - }, - ctx: &v1.SecurityContext{ - Capabilities: &v1.Capabilities{ - Add: []v1.Capability{"CAP_SYS_CHROOT", "CAP_SYS_BOOT"}, - Drop: []v1.Capability{"CAP_SETUID", "CAP_SETGID"}, - }, - RunAsUser: &nonRootUser, - RunAsNonRoot: &runAsNonRootTrue, - }, - podCtx: &v1.PodSecurityContext{ - SupplementalGroups: []int64{ - int64(1), - int64(2), - }, - FSGroup: &fsgid, - }, - supplementalGids: []int64{4}, - expect: &appctypes.App{ - Exec: appctypes.Exec{"/bin/bar", "foo"}, - User: "42", - Group: "0", - SupplementaryGIDs: []int{1, 2, 3, 4}, - WorkingDirectory: tmpDir, - Environment: []appctypes.EnvironmentVariable{ - {Name: "env-foo", Value: "bar"}, - {Name: "env-bar", Value: "foo"}, - }, - MountPoints: []appctypes.MountPoint{ - {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: false}, - {Name: *appctypes.MustACName("mnt-bar"), Path: "/mnt-bar", ReadOnly: true}, - }, - Ports: []appctypes.Port{ - {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 4242}, - {Name: *appctypes.MustACName("port-bar"), Protocol: "TCP", Port: 1234}, - }, - Isolators: []appctypes.Isolator{ - generateCapRetainIsolator(t, "CAP_SYS_CHROOT", "CAP_SYS_BOOT"), - generateCapRevokeIsolator(t, "CAP_SETUID", "CAP_SETGID"), - generateCPUIsolator(t, "5m", "50m"), - generateMemoryIsolator(t, "5M", "50M"), - }, - }, - }, - - // app should be changed. (env, mounts, ports, are overrided). - { - container: &v1.Container{ - Name: "hello-world", - Command: []string{"/bin/hello", "$(env-foo)"}, - Args: []string{"hello", "world", "$(env-bar)"}, - WorkingDir: tmpDir, - Resources: v1.ResourceRequirements{ - Limits: v1.ResourceList{v1.ResourceCPU: resource.MustParse("50m")}, - Requests: v1.ResourceList{v1.ResourceMemory: resource.MustParse("5M")}, - }, - }, - mountPoints: []appctypes.MountPoint{ - {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: true}, - }, - containerPorts: []appctypes.Port{ - {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 1234}, - }, - envs: []kubecontainer.EnvVar{ - {Name: "env-foo", Value: "foo"}, - {Name: "env-bar", Value: "bar"}, - }, - ctx: &v1.SecurityContext{ - Capabilities: &v1.Capabilities{ - Add: []v1.Capability{"CAP_SYS_CHROOT", "CAP_SYS_BOOT"}, - Drop: []v1.Capability{"CAP_SETUID", "CAP_SETGID"}, - }, - RunAsUser: &nonRootUser, - RunAsNonRoot: &runAsNonRootTrue, - }, - podCtx: &v1.PodSecurityContext{ - SupplementalGroups: []int64{ - int64(1), - int64(2), - }, - FSGroup: &fsgid, - }, - supplementalGids: []int64{4}, - expect: &appctypes.App{ - Exec: appctypes.Exec{"/bin/hello", "foo", "hello", "world", "bar"}, - User: "42", - Group: "0", - SupplementaryGIDs: []int{1, 2, 3, 4}, - WorkingDirectory: tmpDir, - Environment: []appctypes.EnvironmentVariable{ - {Name: "env-foo", Value: "foo"}, - {Name: "env-bar", Value: "bar"}, - }, - MountPoints: []appctypes.MountPoint{ - {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: true}, - }, - Ports: []appctypes.Port{ - {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 1234}, - }, - Isolators: []appctypes.Isolator{ - generateCapRetainIsolator(t, "CAP_SYS_CHROOT", "CAP_SYS_BOOT"), - generateCapRevokeIsolator(t, "CAP_SETUID", "CAP_SETGID"), - generateCPUIsolator(t, "50m", "50m"), - generateMemoryIsolator(t, "5M", "5M"), - }, - }, - }, - } - - for i, tt := range tests { - testCaseHint := fmt.Sprintf("test case #%d", i) - img := baseImageManifest(t) - - err := setApp(img, tt.container, - tt.mountPoints, tt.containerPorts, tt.envs, - tt.ctx, tt.podCtx, tt.supplementalGids) - - if err == nil && tt.err != nil || err != nil && tt.err == nil { - t.Errorf("%s: expect %v, saw %v", testCaseHint, tt.err, err) - } - if err == nil { - sortAppFields(tt.expect) - sortAppFields(img.App) - assert.Equal(t, tt.expect, img.App, testCaseHint) - } - } -} - -func TestGenerateRunCommand(t *testing.T) { - hostName := "test-hostname" - boolTrue := true - boolFalse := false - pluginDirs := []string{"/tmp"} - - tests := []struct { - networkPlugin network.NetworkPlugin - pod *v1.Pod - uuid string - netnsName string - - dnsServers []string - dnsSearches []string - hostName string - err error - - expect string - }{ - // Case #0, returns error. - { - kubenet.NewPlugin(pluginDirs), - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-name-foo", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{{Name: "container-foo"}}, - }, - }, - "rkt-uuid-foo", - "default", - []string{}, - []string{}, - "", - fmt.Errorf("failed to get cluster dns"), - "", - }, - // Case #1, returns no dns, with private-net. - { - kubenet.NewPlugin(pluginDirs), - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-name-foo", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{{Name: "container-foo"}}, - }, - }, - "rkt-uuid-foo", - "default", - []string{}, - []string{}, - "pod-hostname-foo", - nil, - "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=pod-hostname-foo rkt-uuid-foo", - }, - // Case #2, returns no dns, with host-net. - { - kubenet.NewPlugin(pluginDirs), - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-name-foo", - }, - Spec: v1.PodSpec{ - HostNetwork: true, - - Containers: []v1.Container{{Name: "container-foo"}}, - }, - }, - "rkt-uuid-foo", - "", - []string{}, - []string{}, - "", - nil, - fmt.Sprintf("/bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=%s rkt-uuid-foo", hostName), - }, - // Case #3, returns dns, dns searches, with private-net. - { - kubenet.NewPlugin(pluginDirs), - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-name-foo", - }, - Spec: v1.PodSpec{ - HostNetwork: false, - - Containers: []v1.Container{{Name: "container-foo"}}, - }, - }, - "rkt-uuid-foo", - "default", - []string{"127.0.0.1"}, - []string{"."}, - "pod-hostname-foo", - nil, - "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --dns=127.0.0.1 --dns-search=. --dns-opt=ndots:5 --hostname=pod-hostname-foo rkt-uuid-foo", - }, - // Case #4, returns no dns, dns searches, with host-network. - { - kubenet.NewPlugin(pluginDirs), - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-name-foo", - }, - Spec: v1.PodSpec{ - HostNetwork: true, - - Containers: []v1.Container{{Name: "container-foo"}}, - }, - }, - "rkt-uuid-foo", - "", - []string{"127.0.0.1"}, - []string{"."}, - "pod-hostname-foo", - nil, - fmt.Sprintf("/bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=%s rkt-uuid-foo", hostName), - }, - // Case #5, with no-op plugin, returns --net=rkt.kubernetes.io, with dns and dns search. - { - &network.NoopNetworkPlugin{}, - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-name-foo", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{{Name: "container-foo"}}, - }, - }, - "rkt-uuid-foo", - "default", - []string{"127.0.0.1"}, - []string{"."}, - "pod-hostname-foo", - nil, - "/bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=rkt.kubernetes.io --dns=127.0.0.1 --dns-search=. --dns-opt=ndots:5 --hostname=pod-hostname-foo rkt-uuid-foo", - }, - // Case #6, if all containers are privileged, the result should have 'insecure-options=all-run' - { - kubenet.NewPlugin(pluginDirs), - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-name-foo", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - {Name: "container-foo", SecurityContext: &v1.SecurityContext{Privileged: &boolTrue}}, - {Name: "container-bar", SecurityContext: &v1.SecurityContext{Privileged: &boolTrue}}, - }, - }, - }, - "rkt-uuid-foo", - "default", - []string{}, - []string{}, - "pod-hostname-foo", - nil, - "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk,all-run --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=pod-hostname-foo rkt-uuid-foo", - }, - // Case #7, if not all containers are privileged, the result should not have 'insecure-options=all-run' - { - kubenet.NewPlugin(pluginDirs), - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-name-foo", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - {Name: "container-foo", SecurityContext: &v1.SecurityContext{Privileged: &boolTrue}}, - {Name: "container-bar", SecurityContext: &v1.SecurityContext{Privileged: &boolFalse}}, - }, - }, - }, - "rkt-uuid-foo", - "default", - []string{}, - []string{}, - "pod-hostname-foo", - nil, - "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=pod-hostname-foo rkt-uuid-foo", - }, - } - - rkt := &Runtime{ - nsenterPath: "/usr/bin/nsenter", - os: &containertesting.FakeOS{HostName: hostName}, - config: &Config{ - Path: "/bin/rkt/rkt", - Stage1Image: "/bin/rkt/stage1-coreos.aci", - Dir: "/var/data", - InsecureOptions: "image,ondisk", - LocalConfigDir: "/var/rkt/local/data", - }, - } - - for i, tt := range tests { - testCaseHint := fmt.Sprintf("test case #%d", i) - rkt.network = network.NewPluginManager(tt.networkPlugin) - rkt.runtimeHelper = &containertesting.FakeRuntimeHelper{ - DNSServers: tt.dnsServers, - DNSSearches: tt.dnsSearches, - HostName: tt.hostName, - Err: tt.err, - } - rkt.execer = &fakeexec.FakeExec{CommandScript: []fakeexec.FakeCommandAction{func(cmd string, args ...string) exec.Cmd { - return fakeexec.InitFakeCmd(&fakeexec.FakeCmd{}, cmd, args...) - }}} - - // a command should be created of this form, but the returned command shouldn't be called (asserted by having no expectations on it) - - result, err := rkt.generateRunCommand(tt.pod, tt.uuid, tt.netnsName) - assert.Equal(t, tt.err, err, testCaseHint) - assert.Equal(t, tt.expect, result, testCaseHint) - } -} - -func TestLifeCycleHooks(t *testing.T) { - runner := lifecycle.NewFakeHandlerRunner() - fr := newFakeRktInterface() - fs := newFakeSystemd() - - rkt := &Runtime{ - runner: runner, - apisvc: fr, - systemd: fs, - containerRefManager: kubecontainer.NewRefManager(), - } - - tests := []struct { - pod *v1.Pod - runtimePod *kubecontainer.Pod - postStartRuns []string - preStopRuns []string - err error - }{ - { - // Case 0, container without any hooks. - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-1", - Namespace: "ns-1", - UID: "uid-1", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - {Name: "container-name-1"}, - }, - }, - }, - &kubecontainer.Pod{ - Containers: []*kubecontainer.Container{ - {ID: kubecontainer.BuildContainerID("rkt", "id-1")}, - }, - }, - []string{}, - []string{}, - nil, - }, - { - // Case 1, containers with post-start and pre-stop hooks. - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-1", - Namespace: "ns-1", - UID: "uid-1", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "container-name-1", - Lifecycle: &v1.Lifecycle{ - PostStart: &v1.Handler{ - Exec: &v1.ExecAction{}, - }, - }, - }, - { - Name: "container-name-2", - Lifecycle: &v1.Lifecycle{ - PostStart: &v1.Handler{ - HTTPGet: &v1.HTTPGetAction{}, - }, - }, - }, - { - Name: "container-name-3", - Lifecycle: &v1.Lifecycle{ - PreStop: &v1.Handler{ - Exec: &v1.ExecAction{}, - }, - }, - }, - { - Name: "container-name-4", - Lifecycle: &v1.Lifecycle{ - PreStop: &v1.Handler{ - HTTPGet: &v1.HTTPGetAction{}, - }, - }, - }, - }, - }, - }, - &kubecontainer.Pod{ - Containers: []*kubecontainer.Container{ - { - ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-4"), - Name: "container-name-4", - }, - { - ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-3"), - Name: "container-name-3", - }, - { - ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-2"), - Name: "container-name-2", - }, - { - ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-1"), - Name: "container-name-1", - }, - }, - }, - []string{ - "exec on pod: pod-1_ns-1(uid-1), container: container-name-1: rkt://uuid:container-name-1", - "http-get on pod: pod-1_ns-1(uid-1), container: container-name-2: rkt://uuid:container-name-2", - }, - []string{ - "exec on pod: pod-1_ns-1(uid-1), container: container-name-3: rkt://uuid:container-name-3", - "http-get on pod: pod-1_ns-1(uid-1), container: container-name-4: rkt://uuid:container-name-4", - }, - nil, - }, - { - // Case 2, one container with invalid hooks. - &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-1", - Namespace: "ns-1", - UID: "uid-1", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "container-name-1", - Lifecycle: &v1.Lifecycle{ - PostStart: &v1.Handler{}, - PreStop: &v1.Handler{}, - }, - }, - }, - }, - }, - &kubecontainer.Pod{ - Containers: []*kubecontainer.Container{ - { - ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-1"), - Name: "container-name-1", - }, - }, - }, - []string{}, - []string{}, - errors.NewAggregate([]error{fmt.Errorf("Invalid handler: %v", &v1.Handler{})}), - }, - } - - for i, tt := range tests { - testCaseHint := fmt.Sprintf("test case #%d", i) - - pod := &rktapi.Pod{Id: "uuid"} - for _, c := range tt.runtimePod.Containers { - pod.Apps = append(pod.Apps, &rktapi.App{ - Name: c.Name, - State: rktapi.AppState_APP_STATE_RUNNING, - }) - } - fr.pods = []*rktapi.Pod{pod} - - // Run post-start hooks - err := rkt.runLifecycleHooks(tt.pod, tt.runtimePod, lifecyclePostStartHook) - assert.Equal(t, tt.err, err, testCaseHint) - - sort.Sort(sortedStringList(tt.postStartRuns)) - sort.Sort(sortedStringList(runner.HandlerRuns)) - - assert.Equal(t, tt.postStartRuns, runner.HandlerRuns, testCaseHint) - - runner.Reset() - - // Run pre-stop hooks. - err = rkt.runLifecycleHooks(tt.pod, tt.runtimePod, lifecyclePreStopHook) - assert.Equal(t, tt.err, err, testCaseHint) - - sort.Sort(sortedStringList(tt.preStopRuns)) - sort.Sort(sortedStringList(runner.HandlerRuns)) - - assert.Equal(t, tt.preStopRuns, runner.HandlerRuns, testCaseHint) - - runner.Reset() - } -} - -func TestImageStats(t *testing.T) { - fr := newFakeRktInterface() - rkt := &Runtime{apisvc: fr} - - fr.images = []*rktapi.Image{ - {Size: 100}, - {Size: 200}, - {Size: 300}, - } - - result, err := rkt.ImageStats() - assert.NoError(t, err) - assert.Equal(t, result, &kubecontainer.ImageStats{TotalStorageBytes: 600}) -} - -func TestGarbageCollect(t *testing.T) { - fr := newFakeRktInterface() - fs := newFakeSystemd() - cli := newFakeRktCli() - fakeOS := containertesting.NewFakeOS() - deletionProvider := newFakePodDeletionProvider() - fug := newfakeUnitGetter() - frh := &containertesting.FakeRuntimeHelper{} - - rkt := &Runtime{ - os: fakeOS, - cli: cli, - apisvc: fr, - podDeletionProvider: deletionProvider, - systemd: fs, - containerRefManager: kubecontainer.NewRefManager(), - unitGetter: fug, - runtimeHelper: frh, - } - - fakeApp := &rktapi.App{Name: "app-foo"} - - tests := []struct { - gcPolicy kubecontainer.ContainerGCPolicy - apiPods []*v1.Pod - pods []*rktapi.Pod - serviceFilesOnDisk []string - expectedCommands []string - expectedDeletedFiles []string - }{ - // All running pods, should not be gc'd. - // Dead, new pods should not be gc'd. - // Dead, old pods should be gc'd. - // Deleted pods should be gc'd. - // Service files without corresponded pods should be removed. - { - kubecontainer.ContainerGCPolicy{ - MinAge: 0, - MaxContainers: 0, - }, - []*v1.Pod{ - {ObjectMeta: metav1.ObjectMeta{UID: "pod-uid-1"}}, - {ObjectMeta: metav1.ObjectMeta{UID: "pod-uid-2"}}, - {ObjectMeta: metav1.ObjectMeta{UID: "pod-uid-3"}}, - {ObjectMeta: metav1.ObjectMeta{UID: "pod-uid-4"}}, - }, - []*rktapi.Pod{ - { - Id: "deleted-foo", - State: rktapi.PodState_POD_STATE_EXITED, - CreatedAt: time.Now().Add(time.Hour).UnixNano(), - StartedAt: time.Now().Add(time.Hour).UnixNano(), - Apps: []*rktapi.App{fakeApp}, - Annotations: []*rktapi.KeyValue{ - { - Key: types.KubernetesPodUIDLabel, - Value: "pod-uid-0", - }, - }, - }, - { - Id: "running-foo", - State: rktapi.PodState_POD_STATE_RUNNING, - CreatedAt: 0, - StartedAt: 0, - Apps: []*rktapi.App{fakeApp}, - Annotations: []*rktapi.KeyValue{ - { - Key: types.KubernetesPodUIDLabel, - Value: "pod-uid-1", - }, - }, - }, - { - Id: "running-bar", - State: rktapi.PodState_POD_STATE_RUNNING, - CreatedAt: 0, - StartedAt: 0, - Apps: []*rktapi.App{fakeApp}, - Annotations: []*rktapi.KeyValue{ - { - Key: types.KubernetesPodUIDLabel, - Value: "pod-uid-2", - }, - }, - }, - { - Id: "dead-old", - State: rktapi.PodState_POD_STATE_EXITED, - CreatedAt: 0, - StartedAt: 0, - Apps: []*rktapi.App{fakeApp}, - Annotations: []*rktapi.KeyValue{ - { - Key: types.KubernetesPodUIDLabel, - Value: "pod-uid-3", - }, - }, - }, - { - Id: "dead-new", - State: rktapi.PodState_POD_STATE_EXITED, - CreatedAt: time.Now().Add(time.Hour).UnixNano(), - StartedAt: time.Now().Add(time.Hour).UnixNano(), - Apps: []*rktapi.App{fakeApp}, - Annotations: []*rktapi.KeyValue{ - { - Key: types.KubernetesPodUIDLabel, - Value: "pod-uid-4", - }, - }, - }, - }, - []string{"k8s_dead-old.service", "k8s_deleted-foo.service", "k8s_non-existing-bar.service"}, - []string{"rkt rm dead-old", "rkt rm deleted-foo"}, - []string{"/poddir/fake/finished-dead-old", "/poddir/fake/finished-deleted-foo", "/poddir/fake/finished-non-existing-bar", "/run/systemd/system/k8s_dead-old.service", "/run/systemd/system/k8s_deleted-foo.service", "/run/systemd/system/k8s_non-existing-bar.service"}, - }, - // gcPolicy.MaxContainers should be enforced. - // Oldest ones are removed first. - { - kubecontainer.ContainerGCPolicy{ - MinAge: 0, - MaxContainers: 1, - }, - []*v1.Pod{ - {ObjectMeta: metav1.ObjectMeta{UID: "pod-uid-0"}}, - {ObjectMeta: metav1.ObjectMeta{UID: "pod-uid-1"}}, - {ObjectMeta: metav1.ObjectMeta{UID: "pod-uid-2"}}, - }, - []*rktapi.Pod{ - { - Id: "dead-2", - State: rktapi.PodState_POD_STATE_EXITED, - CreatedAt: 2, - StartedAt: 2, - Apps: []*rktapi.App{fakeApp}, - Annotations: []*rktapi.KeyValue{ - { - Key: types.KubernetesPodUIDLabel, - Value: "pod-uid-2", - }, - }, - }, - { - Id: "dead-1", - State: rktapi.PodState_POD_STATE_EXITED, - CreatedAt: 1, - StartedAt: 1, - Apps: []*rktapi.App{fakeApp}, - Annotations: []*rktapi.KeyValue{ - { - Key: types.KubernetesPodUIDLabel, - Value: "pod-uid-1", - }, - }, - }, - { - Id: "dead-0", - State: rktapi.PodState_POD_STATE_EXITED, - CreatedAt: 0, - StartedAt: 0, - Apps: []*rktapi.App{fakeApp}, - Annotations: []*rktapi.KeyValue{ - { - Key: types.KubernetesPodUIDLabel, - Value: "pod-uid-0", - }, - }, - }, - }, - []string{"k8s_dead-0.service", "k8s_dead-1.service", "k8s_dead-2.service"}, - []string{"rkt rm dead-0", "rkt rm dead-1"}, - []string{"/poddir/fake/finished-dead-0", "/poddir/fake/finished-dead-1", "/run/systemd/system/k8s_dead-0.service", "/run/systemd/system/k8s_dead-1.service"}, - }, - } - - for i, tt := range tests { - testCaseHint := fmt.Sprintf("test case #%d", i) - - ctrl := gomock.NewController(t) - - fakeOS.ReadDirFn = func(dirname string) ([]os.FileInfo, error) { - serviceFileNames := tt.serviceFilesOnDisk - var fileInfos []os.FileInfo - - for _, name := range serviceFileNames { - mockFI := containertesting.NewMockFileInfo(ctrl) - // we need to specify two calls - // first: get all systemd units - // second: filter only the files with a k8s_ prefix - mockFI.EXPECT().Name().Return(name) - mockFI.EXPECT().Name().Return(name) - fileInfos = append(fileInfos, mockFI) - } - return fileInfos, nil - } - - fr.pods = tt.pods - for _, p := range tt.apiPods { - deletionProvider.pods[p.UID] = struct{}{} - } - - allSourcesReady := true - evictNonDeletedPods := false - err := rkt.GarbageCollect(tt.gcPolicy, allSourcesReady, evictNonDeletedPods) - assert.NoError(t, err, testCaseHint) - - sort.Sort(sortedStringList(tt.expectedCommands)) - sort.Sort(sortedStringList(cli.cmds)) - - assert.Equal(t, tt.expectedCommands, cli.cmds, testCaseHint) - - sort.Sort(sortedStringList(tt.expectedDeletedFiles)) - sort.Sort(sortedStringList(fakeOS.Removes)) - sort.Sort(sortedStringList(fs.resetFailedUnits)) - - assert.Equal(t, tt.expectedDeletedFiles, fakeOS.Removes, testCaseHint) - var expectedService []string - for _, f := range tt.expectedDeletedFiles { - unit := filepath.Base(f) - if strings.HasSuffix(unit, ".service") && strings.HasPrefix(unit, kubernetesUnitPrefix) { - expectedService = append(expectedService, unit) - } - } - assert.Equal(t, expectedService, fs.resetFailedUnits, testCaseHint) - - // Cleanup after each test. - cli.Reset() - ctrl.Finish() - fakeOS.Removes = []string{} - fs.resetFailedUnits = []string{} - deletionProvider.pods = make(map[kubetypes.UID]struct{}) - } -} - -type annotationsByName []appctypes.Annotation - -func (a annotationsByName) Len() int { return len(a) } -func (a annotationsByName) Less(x, y int) bool { return a[x].Name < a[y].Name } -func (a annotationsByName) Swap(x, y int) { a[x], a[y] = a[y], a[x] } - -func TestMakePodManifestAnnotations(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - fr := newFakeRktInterface() - fs := newFakeSystemd() - r := &Runtime{apisvc: fr, systemd: fs} - - testCases := []struct { - in *v1.Pod - out *appcschema.PodManifest - outerr error - }{ - { - in: &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - UID: "uid-1", - Name: "name-1", - Namespace: "namespace-1", - Annotations: map[string]string{ - k8sRktStage1NameAnno: "stage1-override-img", - }, - }, - }, - out: &appcschema.PodManifest{ - Annotations: []appctypes.Annotation{ - { - Name: "io.kubernetes.container.name", - Value: "POD", - }, - { - Name: appctypes.ACIdentifier(k8sRktStage1NameAnno), - Value: "stage1-override-img", - }, - { - Name: appctypes.ACIdentifier(types.KubernetesPodUIDLabel), - Value: "uid-1", - }, - { - Name: appctypes.ACIdentifier(types.KubernetesPodNameLabel), - Value: "name-1", - }, - { - Name: appctypes.ACIdentifier(k8sRktKubeletAnno), - Value: "true", - }, - { - Name: appctypes.ACIdentifier(types.KubernetesPodNamespaceLabel), - Value: "namespace-1", - }, - { - Name: appctypes.ACIdentifier(k8sRktRestartCountAnno), - Value: "0", - }, - }, - }, - }, - } - - for i, testCase := range testCases { - hint := fmt.Sprintf("case #%d", i) - - result, err := r.makePodManifest(testCase.in, "", []v1.Secret{}) - assert.Equal(t, testCase.outerr, err, hint) - if err == nil { - sort.Sort(annotationsByName(result.Annotations)) - sort.Sort(annotationsByName(testCase.out.Annotations)) - assert.Equal(t, testCase.out.Annotations, result.Annotations, hint) - } - } -} - -func TestPreparePodArgs(t *testing.T) { - r := &Runtime{ - config: &Config{}, - } - - testCases := []struct { - manifest appcschema.PodManifest - stage1Config string - cmd []string - }{ - { - appcschema.PodManifest{ - Annotations: appctypes.Annotations{ - { - Name: k8sRktStage1NameAnno, - Value: "stage1-image", - }, - }, - }, - "", - []string{"prepare", "--quiet", "--pod-manifest", "file", "--stage1-name=stage1-image"}, - }, - { - appcschema.PodManifest{ - Annotations: appctypes.Annotations{ - { - Name: k8sRktStage1NameAnno, - Value: "stage1-image", - }, - }, - }, - "stage1-image0", - []string{"prepare", "--quiet", "--pod-manifest", "file", "--stage1-name=stage1-image"}, - }, - { - appcschema.PodManifest{ - Annotations: appctypes.Annotations{}, - }, - "stage1-image0", - []string{"prepare", "--quiet", "--pod-manifest", "file", "--stage1-name=stage1-image0"}, - }, - { - appcschema.PodManifest{ - Annotations: appctypes.Annotations{}, - }, - "", - []string{"prepare", "--quiet", "--pod-manifest", "file"}, - }, - } - - for i, testCase := range testCases { - r.config.Stage1Image = testCase.stage1Config - cmd := r.preparePodArgs(&testCase.manifest, "file") - assert.Equal(t, testCase.cmd, cmd, fmt.Sprintf("Test case #%d", i)) - } -} - -func TestConstructSyslogIdentifier(t *testing.T) { - testCases := []struct { - podName string - podGenerateName string - identifier string - }{ - { - "prometheus-node-exporter-rv90m", - "prometheus-node-exporter-", - "prometheus-node-exporter", - }, - { - "simplepod", - "", - "simplepod", - }, - { - "p", - "", - "p", - }, - } - for i, testCase := range testCases { - identifier := constructSyslogIdentifier(testCase.podGenerateName, testCase.podName) - assert.Equal(t, testCase.identifier, identifier, fmt.Sprintf("Test case #%d", i)) - } -} - -func TestGetPodSystemdServiceFiles(t *testing.T) { - fs := containertesting.NewFakeOS() - r := &Runtime{os: fs} - - testCases := []struct { - serviceFilesOnDisk []string - expected []string - }{ - { - []string{"one.service", "two.service", "k8s_513ce947-8f6e-4d27-8c03-99f97b78d680.service", "k8s_184482df-8630-4d41-b84f-302684871758.service", "k8s_f4a244d8-5ec2-4f59-b7dd-c9e130d6e7a3.service", "k8s_f5aad446-5598-488f-93a4-5a27e03e7fcb.service"}, - []string{"k8s_513ce947-8f6e-4d27-8c03-99f97b78d680.service", "k8s_184482df-8630-4d41-b84f-302684871758.service", "k8s_f4a244d8-5ec2-4f59-b7dd-c9e130d6e7a3.service", "k8s_f5aad446-5598-488f-93a4-5a27e03e7fcb.service"}, - }, - { - []string{"one.service", "two.service"}, - []string{}, - }, - { - []string{"one.service", "k8s_513ce947-8f6e-4d27-8c03-99f97b78d680.service"}, - []string{"k8s_513ce947-8f6e-4d27-8c03-99f97b78d680.service"}, - }, - } - for i, tt := range testCases { - ctrl := gomock.NewController(t) - - fs.ReadDirFn = func(dirname string) ([]os.FileInfo, error) { - serviceFileNames := tt.serviceFilesOnDisk - var fileInfos []os.FileInfo - - for _, name := range serviceFileNames { - mockFI := containertesting.NewMockFileInfo(ctrl) - // we need to specify two calls - // first: get all systemd units - // second: filter only the files with a k8s_ prefix - mockFI.EXPECT().Name().Return(name) - mockFI.EXPECT().Name().Return(name) - fileInfos = append(fileInfos, mockFI) - } - return fileInfos, nil - } - serviceFiles, err := r.getPodSystemdServiceFiles() - if err != nil { - t.Errorf("%v", err) - } - for _, f := range serviceFiles { - assert.Contains(t, tt.expected, f.Name(), fmt.Sprintf("Test case #%d", i)) - - } - } -} - -func TestSetupSystemdCustomFields(t *testing.T) { - testCases := []struct { - unitOpts []*unit.UnitOption - podAnnotations map[string]string - expectedValues []string - raiseErr bool - }{ - // without annotation - { - []*unit.UnitOption{ - {Section: "Service", Name: "ExecStart", Value: "/bin/true"}, - }, - map[string]string{}, - []string{"/bin/true"}, - false, - }, - // with valid annotation for LimitNOFile - { - []*unit.UnitOption{ - {Section: "Service", Name: "ExecStart", Value: "/bin/true"}, - }, - map[string]string{k8sRktLimitNoFileAnno: "1024"}, - []string{"/bin/true", "1024"}, - false, - }, - // with invalid annotation for LimitNOFile - { - []*unit.UnitOption{ - {Section: "Service", Name: "ExecStart", Value: "/bin/true"}, - }, - map[string]string{k8sRktLimitNoFileAnno: "-1"}, - []string{"/bin/true"}, - true, - }, - } - - for i, tt := range testCases { - raiseErr := false - newUnitsOpts, err := setupSystemdCustomFields(tt.podAnnotations, tt.unitOpts) - if err != nil { - raiseErr = true - } - assert.Equal(t, tt.raiseErr, raiseErr, fmt.Sprintf("Test case #%d", i)) - for _, opt := range newUnitsOpts { - assert.Equal(t, "Service", opt.Section, fmt.Sprintf("Test case #%d", i)) - assert.Contains(t, tt.expectedValues, opt.Value, fmt.Sprintf("Test case #%d", i)) - } - } -} diff --git a/pkg/kubelet/rkt/systemd.go b/pkg/kubelet/rkt/systemd.go deleted file mode 100644 index 73768e5ea8c..00000000000 --- a/pkg/kubelet/rkt/systemd.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 rkt - -import ( - "fmt" - "strconv" - "strings" - - "github.com/coreos/go-systemd/dbus" -) - -// systemdVersion is a type wraps the int to implement kubecontainer.Version interface. -type systemdVersion int - -func (s systemdVersion) String() string { - return fmt.Sprintf("%d", s) -} - -func (s systemdVersion) Compare(other string) (int, error) { - v, err := strconv.Atoi(other) - if err != nil { - return -1, err - } - if int(s) < v { - return -1, nil - } else if int(s) > v { - return 1, nil - } - return 0, nil -} - -// systemdInterface is an abstraction of the go-systemd/dbus to make -// it mockable for testing. -// TODO(yifan): Eventually we should move these functionalities to: -// 1. a package for launching/stopping rkt pods. -// 2. rkt api-service interface for listing pods. -// See https://github.com/coreos/rkt/issues/1769. -type systemdInterface interface { - // Version returns the version of the systemd. - Version() (systemdVersion, error) - // ListUnits lists all the loaded units. - ListUnits() ([]dbus.UnitStatus, error) - // StopUnits stops the unit with the given name. - StopUnit(name string, mode string, ch chan<- string) (int, error) - // RestartUnit restarts the unit with the given name. - RestartUnit(name string, mode string, ch chan<- string) (int, error) - // ResetFailedUnit resets the "failed" state of a specific unit. - ResetFailedUnit(name string) error -} - -// systemd implements the systemdInterface using dbus and systemctl. -// All the functions other then Version() are already implemented by go-systemd/dbus. -type systemd struct { - *dbus.Conn -} - -// newSystemd creates a systemd object that implements systemdInterface. -func newSystemd() (*systemd, error) { - dbusConn, err := dbus.New() - if err != nil { - return nil, err - } - return &systemd{dbusConn}, nil -} - -// Version returns the version of the systemd. -func (s *systemd) Version() (systemdVersion, error) { - versionStr, err := s.Conn.GetManagerProperty("Version") - if err != nil { - return -1, err - } - result, err := strconv.Atoi(strings.Trim(versionStr, "\"")) - if err != nil { - return -1, err - } - return systemdVersion(result), nil -} diff --git a/pkg/kubelet/rkt/version.go b/pkg/kubelet/rkt/version.go deleted file mode 100644 index d94e7ea943c..00000000000 --- a/pkg/kubelet/rkt/version.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 rkt - -import ( - "context" - "fmt" - "sync" - - rktapi "github.com/coreos/rkt/api/v1alpha" - - utilversion "k8s.io/kubernetes/pkg/util/version" -) - -type versions struct { - sync.RWMutex - binVersion *utilversion.Version - apiVersion *utilversion.Version - systemdVersion systemdVersion -} - -func newRktVersion(version string) (*utilversion.Version, error) { - return utilversion.ParseSemantic(version) -} - -func (r *Runtime) getVersions() error { - r.versions.Lock() - defer r.versions.Unlock() - - // Get systemd version. - var err error - r.versions.systemdVersion, err = r.systemd.Version() - if err != nil { - return err - } - - ctx, cancel := context.WithTimeout(context.Background(), r.requestTimeout) - defer cancel() - // Example for the version strings returned by GetInfo(): - // RktVersion:"0.10.0+gitb7349b1" AppcVersion:"0.7.1" ApiVersion:"1.0.0-alpha" - resp, err := r.apisvc.GetInfo(ctx, &rktapi.GetInfoRequest{}) - if err != nil { - return err - } - - // Get rkt binary version. - r.versions.binVersion, err = newRktVersion(resp.Info.RktVersion) - if err != nil { - return err - } - - // Get rkt API version. - r.versions.apiVersion, err = newRktVersion(resp.Info.ApiVersion) - if err != nil { - return err - } - return nil -} - -// checkVersion tests whether the rkt/systemd/rkt-api-service that meet the version requirement. -// If all version requirements are met, it returns nil. -func (r *Runtime) checkVersion(minimumRktBinVersion, minimumRktApiVersion, minimumSystemdVersion string) error { - if err := r.getVersions(); err != nil { - return err - } - - r.versions.RLock() - defer r.versions.RUnlock() - - // Check systemd version. - result, err := r.versions.systemdVersion.Compare(minimumSystemdVersion) - if err != nil { - return err - } - if result < 0 { - return fmt.Errorf("rkt: systemd version(%v) is too old, requires at least %v", r.versions.systemdVersion, minimumSystemdVersion) - } - - // Check rkt binary version. - result, err = r.versions.binVersion.Compare(minimumRktBinVersion) - if err != nil { - return err - } - if result < 0 { - return fmt.Errorf("rkt: binary version is too old(%v), requires at least %v", r.versions.binVersion, minimumRktBinVersion) - } - - // Check rkt API version. - result, err = r.versions.apiVersion.Compare(minimumRktApiVersion) - if err != nil { - return err - } - if result < 0 { - return fmt.Errorf("rkt: API version is too old(%v), requires at least %v", r.versions.apiVersion, minimumRktApiVersion) - } - return nil -} diff --git a/pkg/kubelet/sysctl/runtime.go b/pkg/kubelet/sysctl/runtime.go index 7ccbbdf5328..a7aa49e9ba5 100644 --- a/pkg/kubelet/sysctl/runtime.go +++ b/pkg/kubelet/sysctl/runtime.go @@ -31,7 +31,6 @@ const ( dockerMinimumAPIVersion = "1.24.0" dockerTypeName = "docker" - rktTypeName = "rkt" ) // TODO: The admission logic in this file is runtime-dependent. It should be @@ -72,14 +71,6 @@ func NewRuntimeAdmitHandler(runtime container.Runtime) (*runtimeAdmitHandler, er Message: "Docker API version before 1.24 does not support sysctls", }, }, nil - case rktTypeName: - return &runtimeAdmitHandler{ - result: lifecycle.PodAdmitResult{ - Admit: false, - Reason: UnsupportedReason, - Message: "Rkt does not support sysctls", - }, - }, nil default: // Return admit for other runtimes. return &runtimeAdmitHandler{ diff --git a/pkg/kubelet/types/constants.go b/pkg/kubelet/types/constants.go index 2c83908a7c4..f2f703a8d2b 100644 --- a/pkg/kubelet/types/constants.go +++ b/pkg/kubelet/types/constants.go @@ -22,7 +22,6 @@ const ( // different container runtimes DockerContainerRuntime = "docker" - RktContainerRuntime = "rkt" RemoteContainerRuntime = "remote" // User visible keys for managing node allocatable enforcement on the node. From 1f1595a2436a92481eaed6108be79cfb1d0fb433 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Thu, 22 Mar 2018 09:44:43 -0700 Subject: [PATCH 2/3] Update Godeps after removing rkt. This was done by executing the following two commands: $ hack/run-in-gopath.sh hack/godep-save.sh $ hack/run-in-gopath.sh hack/godep-restore.sh Go packages github.com/appc/spec and github.com/coreos/go-systemd were used by the rkt/ package that is now gone. --- Godeps/Godeps.json | 31 - Godeps/LICENSES | 1249 ----------------- vendor/BUILD | 3 - vendor/github.com/appc/spec/LICENSE | 202 --- vendor/github.com/appc/spec/schema/BUILD | 36 - .../github.com/appc/spec/schema/common/BUILD | 22 - .../appc/spec/schema/common/common.go | 40 - vendor/github.com/appc/spec/schema/doc.go | 25 - vendor/github.com/appc/spec/schema/image.go | 103 -- vendor/github.com/appc/spec/schema/kind.go | 42 - vendor/github.com/appc/spec/schema/pod.go | 173 --- .../github.com/appc/spec/schema/types/BUILD | 57 - .../appc/spec/schema/types/acidentifier.go | 145 -- .../appc/spec/schema/types/ackind.go | 67 - .../appc/spec/schema/types/acname.go | 145 -- .../appc/spec/schema/types/annotations.go | 106 -- .../github.com/appc/spec/schema/types/app.go | 95 -- .../github.com/appc/spec/schema/types/date.go | 60 - .../appc/spec/schema/types/dependencies.go | 58 - .../github.com/appc/spec/schema/types/doc.go | 18 - .../appc/spec/schema/types/environment.go | 110 -- .../appc/spec/schema/types/errors.go | 49 - .../appc/spec/schema/types/event_handler.go | 61 - .../github.com/appc/spec/schema/types/exec.go | 46 - .../github.com/appc/spec/schema/types/hash.go | 118 -- .../appc/spec/schema/types/isolator.go | 190 --- .../schema/types/isolator_linux_specific.go | 529 ------- .../spec/schema/types/isolator_resources.go | 245 ---- .../appc/spec/schema/types/isolator_unix.go | 83 -- .../appc/spec/schema/types/labels.go | 206 --- .../appc/spec/schema/types/mountpoint.go | 92 -- .../github.com/appc/spec/schema/types/port.go | 147 -- .../appc/spec/schema/types/resource/BUILD | 32 - .../appc/spec/schema/types/resource/README.md | 4 - .../appc/spec/schema/types/resource/amount.go | 298 ---- .../appc/spec/schema/types/resource/math.go | 327 ----- .../spec/schema/types/resource/quantity.go | 768 ---------- .../spec/schema/types/resource/scale_int.go | 95 -- .../appc/spec/schema/types/resource/suffix.go | 198 --- .../appc/spec/schema/types/semver.go | 91 -- .../github.com/appc/spec/schema/types/url.go | 71 - .../spec/schema/types/user_annotations.go | 18 - .../appc/spec/schema/types/user_labels.go | 18 - .../github.com/appc/spec/schema/types/uuid.go | 92 -- .../appc/spec/schema/types/volume.go | 249 ---- vendor/github.com/appc/spec/schema/version.go | 39 - .../github.com/coreos/go-systemd/unit/BUILD | 27 - .../coreos/go-systemd/unit/deserialize.go | 276 ---- .../coreos/go-systemd/unit/escape.go | 116 -- .../coreos/go-systemd/unit/option.go | 54 - .../coreos/go-systemd/unit/serialize.go | 75 - vendor/go4.org/AUTHORS | 8 - vendor/go4.org/LICENSE | 202 --- vendor/go4.org/errorutil/BUILD | 22 - vendor/go4.org/errorutil/highlight.go | 58 - 55 files changed, 7691 deletions(-) delete mode 100644 vendor/github.com/appc/spec/LICENSE delete mode 100644 vendor/github.com/appc/spec/schema/BUILD delete mode 100644 vendor/github.com/appc/spec/schema/common/BUILD delete mode 100644 vendor/github.com/appc/spec/schema/common/common.go delete mode 100644 vendor/github.com/appc/spec/schema/doc.go delete mode 100644 vendor/github.com/appc/spec/schema/image.go delete mode 100644 vendor/github.com/appc/spec/schema/kind.go delete mode 100644 vendor/github.com/appc/spec/schema/pod.go delete mode 100644 vendor/github.com/appc/spec/schema/types/BUILD delete mode 100644 vendor/github.com/appc/spec/schema/types/acidentifier.go delete mode 100644 vendor/github.com/appc/spec/schema/types/ackind.go delete mode 100644 vendor/github.com/appc/spec/schema/types/acname.go delete mode 100644 vendor/github.com/appc/spec/schema/types/annotations.go delete mode 100644 vendor/github.com/appc/spec/schema/types/app.go delete mode 100644 vendor/github.com/appc/spec/schema/types/date.go delete mode 100644 vendor/github.com/appc/spec/schema/types/dependencies.go delete mode 100644 vendor/github.com/appc/spec/schema/types/doc.go delete mode 100644 vendor/github.com/appc/spec/schema/types/environment.go delete mode 100644 vendor/github.com/appc/spec/schema/types/errors.go delete mode 100644 vendor/github.com/appc/spec/schema/types/event_handler.go delete mode 100644 vendor/github.com/appc/spec/schema/types/exec.go delete mode 100644 vendor/github.com/appc/spec/schema/types/hash.go delete mode 100644 vendor/github.com/appc/spec/schema/types/isolator.go delete mode 100644 vendor/github.com/appc/spec/schema/types/isolator_linux_specific.go delete mode 100644 vendor/github.com/appc/spec/schema/types/isolator_resources.go delete mode 100644 vendor/github.com/appc/spec/schema/types/isolator_unix.go delete mode 100644 vendor/github.com/appc/spec/schema/types/labels.go delete mode 100644 vendor/github.com/appc/spec/schema/types/mountpoint.go delete mode 100644 vendor/github.com/appc/spec/schema/types/port.go delete mode 100644 vendor/github.com/appc/spec/schema/types/resource/BUILD delete mode 100644 vendor/github.com/appc/spec/schema/types/resource/README.md delete mode 100644 vendor/github.com/appc/spec/schema/types/resource/amount.go delete mode 100644 vendor/github.com/appc/spec/schema/types/resource/math.go delete mode 100644 vendor/github.com/appc/spec/schema/types/resource/quantity.go delete mode 100644 vendor/github.com/appc/spec/schema/types/resource/scale_int.go delete mode 100644 vendor/github.com/appc/spec/schema/types/resource/suffix.go delete mode 100644 vendor/github.com/appc/spec/schema/types/semver.go delete mode 100644 vendor/github.com/appc/spec/schema/types/url.go delete mode 100644 vendor/github.com/appc/spec/schema/types/user_annotations.go delete mode 100644 vendor/github.com/appc/spec/schema/types/user_labels.go delete mode 100644 vendor/github.com/appc/spec/schema/types/uuid.go delete mode 100644 vendor/github.com/appc/spec/schema/types/volume.go delete mode 100644 vendor/github.com/appc/spec/schema/version.go delete mode 100644 vendor/github.com/coreos/go-systemd/unit/BUILD delete mode 100644 vendor/github.com/coreos/go-systemd/unit/deserialize.go delete mode 100644 vendor/github.com/coreos/go-systemd/unit/escape.go delete mode 100644 vendor/github.com/coreos/go-systemd/unit/option.go delete mode 100644 vendor/github.com/coreos/go-systemd/unit/serialize.go delete mode 100644 vendor/go4.org/AUTHORS delete mode 100644 vendor/go4.org/LICENSE delete mode 100644 vendor/go4.org/errorutil/BUILD delete mode 100644 vendor/go4.org/errorutil/highlight.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 7b8bc58998a..de186fc1b8f 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -141,26 +141,6 @@ "ImportPath": "github.com/abbot/go-http-auth", "Rev": "c0ef4539dfab4d21c8ef20ba2924f9fc6f186d35" }, - { - "ImportPath": "github.com/appc/spec/schema", - "Comment": "v0.8.9-17-gfc380db", - "Rev": "fc380db5fc13c6dd71a5b0bf2af0d182865d1b1d" - }, - { - "ImportPath": "github.com/appc/spec/schema/common", - "Comment": "v0.8.9-17-gfc380db", - "Rev": "fc380db5fc13c6dd71a5b0bf2af0d182865d1b1d" - }, - { - "ImportPath": "github.com/appc/spec/schema/types", - "Comment": "v0.8.9-17-gfc380db", - "Rev": "fc380db5fc13c6dd71a5b0bf2af0d182865d1b1d" - }, - { - "ImportPath": "github.com/appc/spec/schema/types/resource", - "Comment": "v0.8.9-17-gfc380db", - "Rev": "fc380db5fc13c6dd71a5b0bf2af0d182865d1b1d" - }, { "ImportPath": "github.com/armon/circbuf", "Rev": "bbbad097214e2918d8543d5201d12bfd7bca254d" @@ -928,11 +908,6 @@ "Comment": "v14", "Rev": "48702e0da86bd25e76cfef347e2adeb434a0d0a6" }, - { - "ImportPath": "github.com/coreos/go-systemd/unit", - "Comment": "v14", - "Rev": "48702e0da86bd25e76cfef347e2adeb434a0d0a6" - }, { "ImportPath": "github.com/coreos/go-systemd/util", "Comment": "v14", @@ -1229,12 +1204,10 @@ }, { "ImportPath": "github.com/garyburd/redigo/internal", - "Comment": "v1.0.0-1-gb8dc900", "Rev": "b8dc90050f24c1a73a52f107f3f575be67b21b7c" }, { "ImportPath": "github.com/garyburd/redigo/redis", - "Comment": "v1.0.0-1-gb8dc900", "Rev": "b8dc90050f24c1a73a52f107f3f575be67b21b7c" }, { @@ -2815,10 +2788,6 @@ "Comment": "v1.0-13-g5292687", "Rev": "5292687f5379e01054407da44d7c4590a61fd3de" }, - { - "ImportPath": "go4.org/errorutil", - "Rev": "03efcb870d84809319ea509714dd6d19a1498483" - }, { "ImportPath": "golang.org/x/crypto/bcrypt", "Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067" diff --git a/Godeps/LICENSES b/Godeps/LICENSES index b57935261ca..1fe4ae4ef93 100644 --- a/Godeps/LICENSES +++ b/Godeps/LICENSES @@ -916,846 +916,6 @@ SUBDIRECTORIES ================================================================================ -================================================================================ -= vendor/github.com/appc/spec/schema licensed under: = - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - - -= vendor/github.com/appc/spec/LICENSE d2794c0df5b907fdace235a619d80314 -================================================================================ - - -================================================================================ -= vendor/github.com/appc/spec/schema/common licensed under: = - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - - -= vendor/github.com/appc/spec/LICENSE d2794c0df5b907fdace235a619d80314 -================================================================================ - - -================================================================================ -= vendor/github.com/appc/spec/schema/types licensed under: = - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - - -= vendor/github.com/appc/spec/LICENSE d2794c0df5b907fdace235a619d80314 -================================================================================ - - -================================================================================ -= vendor/github.com/appc/spec/schema/types/resource licensed under: = - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - - -= vendor/github.com/appc/spec/LICENSE d2794c0df5b907fdace235a619d80314 -================================================================================ - - ================================================================================ = vendor/github.com/armon/circbuf licensed under: = @@ -32629,205 +31789,6 @@ third-party archives. ================================================================================ -================================================================================ -= vendor/github.com/coreos/go-systemd/unit licensed under: = - -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. - -= vendor/github.com/coreos/go-systemd/LICENSE 19cbd64715b51267a47bf3750cc6a8a5 -================================================================================ - - ================================================================================ = vendor/github.com/coreos/go-systemd/util licensed under: = @@ -88620,216 +87581,6 @@ SOFTWARE. ================================================================================ -================================================================================ -= vendor/go4.org/errorutil licensed under: = - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - - -= vendor/go4.org/LICENSE fa818a259cbed7ce8bc2a22d35a464fc -================================================================================ - - ================================================================================ = vendor/golang.org/x/crypto/bcrypt licensed under: = diff --git a/vendor/BUILD b/vendor/BUILD index a2c666dc453..815d6817cb4 100644 --- a/vendor/BUILD +++ b/vendor/BUILD @@ -31,7 +31,6 @@ filegroup( "//vendor/github.com/PuerkitoBio/purell:all-srcs", "//vendor/github.com/PuerkitoBio/urlesc:all-srcs", "//vendor/github.com/abbot/go-http-auth:all-srcs", - "//vendor/github.com/appc/spec/schema:all-srcs", "//vendor/github.com/armon/circbuf:all-srcs", "//vendor/github.com/asaskevich/govalidator:all-srcs", "//vendor/github.com/aws/aws-sdk-go/aws:all-srcs", @@ -125,7 +124,6 @@ filegroup( "//vendor/github.com/coreos/go-systemd/daemon:all-srcs", "//vendor/github.com/coreos/go-systemd/dbus:all-srcs", "//vendor/github.com/coreos/go-systemd/journal:all-srcs", - "//vendor/github.com/coreos/go-systemd/unit:all-srcs", "//vendor/github.com/coreos/go-systemd/util:all-srcs", "//vendor/github.com/coreos/pkg/capnslog:all-srcs", "//vendor/github.com/coreos/pkg/dlopen:all-srcs", @@ -349,7 +347,6 @@ filegroup( "//vendor/github.com/xanzy/go-cloudstack/cloudstack:all-srcs", "//vendor/github.com/xiang90/probing:all-srcs", "//vendor/github.com/xyproto/simpleredis:all-srcs", - "//vendor/go4.org/errorutil:all-srcs", "//vendor/golang.org/x/crypto/bcrypt:all-srcs", "//vendor/golang.org/x/crypto/blowfish:all-srcs", "//vendor/golang.org/x/crypto/cryptobyte:all-srcs", diff --git a/vendor/github.com/appc/spec/LICENSE b/vendor/github.com/appc/spec/LICENSE deleted file mode 100644 index e06d2081865..00000000000 --- a/vendor/github.com/appc/spec/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - diff --git a/vendor/github.com/appc/spec/schema/BUILD b/vendor/github.com/appc/spec/schema/BUILD deleted file mode 100644 index 049a9e63d68..00000000000 --- a/vendor/github.com/appc/spec/schema/BUILD +++ /dev/null @@ -1,36 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "image.go", - "kind.go", - "pod.go", - "version.go", - ], - importpath = "github.com/appc/spec/schema", - visibility = ["//visibility:public"], - deps = [ - "//vendor/github.com/appc/spec/schema/types:go_default_library", - "//vendor/go4.org/errorutil:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [ - ":package-srcs", - "//vendor/github.com/appc/spec/schema/common:all-srcs", - "//vendor/github.com/appc/spec/schema/types:all-srcs", - ], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/appc/spec/schema/common/BUILD b/vendor/github.com/appc/spec/schema/common/BUILD deleted file mode 100644 index 720a34c1f65..00000000000 --- a/vendor/github.com/appc/spec/schema/common/BUILD +++ /dev/null @@ -1,22 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = ["common.go"], - importpath = "github.com/appc/spec/schema/common", - visibility = ["//visibility:public"], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/appc/spec/schema/common/common.go b/vendor/github.com/appc/spec/schema/common/common.go deleted file mode 100644 index ffc0f6f9b4a..00000000000 --- a/vendor/github.com/appc/spec/schema/common/common.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 common - -import ( - "fmt" - "net/url" - "strings" -) - -// MakeQueryString takes a comma-separated LABEL=VALUE string and returns an -// "&"-separated string with URL escaped values. -// -// Examples: -// version=1.0.0,label=v1+v2 -> version=1.0.0&label=v1%2Bv2 -// name=db,source=/tmp$1 -> name=db&source=%2Ftmp%241 -func MakeQueryString(app string) (string, error) { - parts := strings.Split(app, ",") - escapedParts := make([]string, len(parts)) - for i, s := range parts { - p := strings.SplitN(s, "=", 2) - if len(p) != 2 { - return "", fmt.Errorf("malformed string %q - has a label without a value: %s", app, p[0]) - } - escapedParts[i] = fmt.Sprintf("%s=%s", p[0], url.QueryEscape(p[1])) - } - return strings.Join(escapedParts, "&"), nil -} diff --git a/vendor/github.com/appc/spec/schema/doc.go b/vendor/github.com/appc/spec/schema/doc.go deleted file mode 100644 index ba381543f87..00000000000 --- a/vendor/github.com/appc/spec/schema/doc.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 schema provides definitions for the JSON schema of the different -// manifests in the App Container Specification. The manifests are canonically -// represented in their respective structs: -// - `ImageManifest` -// - `PodManifest` -// -// Validation is performed through serialization: if a blob of JSON data will -// unmarshal to one of the *Manifests, it is considered a valid implementation -// of the standard. Similarly, if a constructed *Manifest struct marshals -// successfully to JSON, it must be valid. -package schema diff --git a/vendor/github.com/appc/spec/schema/image.go b/vendor/github.com/appc/spec/schema/image.go deleted file mode 100644 index fac4c794c32..00000000000 --- a/vendor/github.com/appc/spec/schema/image.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 schema - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - - "github.com/appc/spec/schema/types" - - "go4.org/errorutil" -) - -const ( - ACIExtension = ".aci" - ImageManifestKind = types.ACKind("ImageManifest") -) - -type ImageManifest struct { - ACKind types.ACKind `json:"acKind"` - ACVersion types.SemVer `json:"acVersion"` - Name types.ACIdentifier `json:"name"` - Labels types.Labels `json:"labels,omitempty"` - App *types.App `json:"app,omitempty"` - Annotations types.Annotations `json:"annotations,omitempty"` - Dependencies types.Dependencies `json:"dependencies,omitempty"` - PathWhitelist []string `json:"pathWhitelist,omitempty"` -} - -// imageManifest is a model to facilitate extra validation during the -// unmarshalling of the ImageManifest -type imageManifest ImageManifest - -func BlankImageManifest() *ImageManifest { - return &ImageManifest{ACKind: ImageManifestKind, ACVersion: AppContainerVersion} -} - -func (im *ImageManifest) UnmarshalJSON(data []byte) error { - a := imageManifest(*im) - err := json.Unmarshal(data, &a) - if err != nil { - if serr, ok := err.(*json.SyntaxError); ok { - line, col, highlight := errorutil.HighlightBytePosition(bytes.NewReader(data), serr.Offset) - return fmt.Errorf("\nError at line %d, column %d\n%s%v", line, col, highlight, err) - } - return err - } - nim := ImageManifest(a) - if err := nim.assertValid(); err != nil { - return err - } - *im = nim - return nil -} - -func (im ImageManifest) MarshalJSON() ([]byte, error) { - if err := im.assertValid(); err != nil { - return nil, err - } - return json.Marshal(imageManifest(im)) -} - -var imKindError = types.InvalidACKindError(ImageManifestKind) - -// assertValid performs extra assertions on an ImageManifest to ensure that -// fields are set appropriately, etc. It is used exclusively when marshalling -// and unmarshalling an ImageManifest. Most field-specific validation is -// performed through the individual types being marshalled; assertValid() -// should only deal with higher-level validation. -func (im *ImageManifest) assertValid() error { - if im.ACKind != ImageManifestKind { - return imKindError - } - if im.ACVersion.Empty() { - return errors.New(`acVersion must be set`) - } - if im.Name.Empty() { - return errors.New(`name must be set`) - } - return nil -} - -func (im *ImageManifest) GetLabel(name string) (val string, ok bool) { - return im.Labels.Get(name) -} - -func (im *ImageManifest) GetAnnotation(name string) (val string, ok bool) { - return im.Annotations.Get(name) -} diff --git a/vendor/github.com/appc/spec/schema/kind.go b/vendor/github.com/appc/spec/schema/kind.go deleted file mode 100644 index 5dc4f957ecf..00000000000 --- a/vendor/github.com/appc/spec/schema/kind.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 schema - -import ( - "encoding/json" - - "github.com/appc/spec/schema/types" -) - -type Kind struct { - ACVersion types.SemVer `json:"acVersion"` - ACKind types.ACKind `json:"acKind"` -} - -type kind Kind - -func (k *Kind) UnmarshalJSON(data []byte) error { - nk := kind{} - err := json.Unmarshal(data, &nk) - if err != nil { - return err - } - *k = Kind(nk) - return nil -} - -func (k Kind) MarshalJSON() ([]byte, error) { - return json.Marshal(kind(k)) -} diff --git a/vendor/github.com/appc/spec/schema/pod.go b/vendor/github.com/appc/spec/schema/pod.go deleted file mode 100644 index 9ed6c9e0a66..00000000000 --- a/vendor/github.com/appc/spec/schema/pod.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 schema - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - - "github.com/appc/spec/schema/types" - - "go4.org/errorutil" -) - -const PodManifestKind = types.ACKind("PodManifest") - -type PodManifest struct { - ACVersion types.SemVer `json:"acVersion"` - ACKind types.ACKind `json:"acKind"` - Apps AppList `json:"apps"` - Volumes []types.Volume `json:"volumes"` - Isolators []types.Isolator `json:"isolators"` - Annotations types.Annotations `json:"annotations"` - Ports []types.ExposedPort `json:"ports"` - UserAnnotations types.UserAnnotations `json:"userAnnotations,omitempty"` - UserLabels types.UserLabels `json:"userLabels,omitempty"` -} - -// podManifest is a model to facilitate extra validation during the -// unmarshalling of the PodManifest -type podManifest PodManifest - -func BlankPodManifest() *PodManifest { - return &PodManifest{ACKind: PodManifestKind, ACVersion: AppContainerVersion} -} - -func (pm *PodManifest) UnmarshalJSON(data []byte) error { - p := podManifest(*pm) - err := json.Unmarshal(data, &p) - if err != nil { - if serr, ok := err.(*json.SyntaxError); ok { - line, col, highlight := errorutil.HighlightBytePosition(bytes.NewReader(data), serr.Offset) - return fmt.Errorf("\nError at line %d, column %d\n%s%v", line, col, highlight, err) - } - return err - } - npm := PodManifest(p) - if err := npm.assertValid(); err != nil { - return err - } - *pm = npm - return nil -} - -func (pm PodManifest) MarshalJSON() ([]byte, error) { - if err := pm.assertValid(); err != nil { - return nil, err - } - return json.Marshal(podManifest(pm)) -} - -var pmKindError = types.InvalidACKindError(PodManifestKind) - -// assertValid performs extra assertions on an PodManifest to -// ensure that fields are set appropriately, etc. It is used exclusively when -// marshalling and unmarshalling an PodManifest. Most -// field-specific validation is performed through the individual types being -// marshalled; assertValid() should only deal with higher-level validation. -func (pm *PodManifest) assertValid() error { - if pm.ACKind != PodManifestKind { - return pmKindError - } - return nil -} - -type AppList []RuntimeApp - -type appList AppList - -func (al *AppList) UnmarshalJSON(data []byte) error { - a := appList{} - err := json.Unmarshal(data, &a) - if err != nil { - return err - } - nal := AppList(a) - if err := nal.assertValid(); err != nil { - return err - } - *al = nal - return nil -} - -func (al AppList) MarshalJSON() ([]byte, error) { - if err := al.assertValid(); err != nil { - return nil, err - } - return json.Marshal(appList(al)) -} - -func (al AppList) assertValid() error { - seen := map[types.ACName]bool{} - for _, a := range al { - if _, ok := seen[a.Name]; ok { - return fmt.Errorf(`duplicate apps of name %q`, a.Name) - } - seen[a.Name] = true - } - return nil -} - -// Get retrieves an app by the specified name from the AppList; if there is -// no such app, nil is returned. The returned *RuntimeApp MUST be considered -// read-only. -func (al AppList) Get(name types.ACName) *RuntimeApp { - for _, a := range al { - if name.Equals(a.Name) { - aa := a - return &aa - } - } - return nil -} - -// Mount describes the mapping between a volume and the path it is mounted -// inside of an app's filesystem. -// The AppVolume is optional. If missing, the pod-level Volume of the -// same name shall be used. -type Mount struct { - Volume types.ACName `json:"volume"` - Path string `json:"path"` - AppVolume *types.Volume `json:"appVolume,omitempty"` -} - -func (r Mount) assertValid() error { - if r.Volume.Empty() { - return errors.New("volume must be set") - } - if r.Path == "" { - return errors.New("path must be set") - } - return nil -} - -// RuntimeApp describes an application referenced in a PodManifest -type RuntimeApp struct { - Name types.ACName `json:"name"` - Image RuntimeImage `json:"image"` - App *types.App `json:"app,omitempty"` - ReadOnlyRootFS bool `json:"readOnlyRootFS,omitempty"` - Mounts []Mount `json:"mounts,omitempty"` - Annotations types.Annotations `json:"annotations,omitempty"` -} - -// RuntimeImage describes an image referenced in a RuntimeApp -type RuntimeImage struct { - Name *types.ACIdentifier `json:"name,omitempty"` - ID types.Hash `json:"id"` - Labels types.Labels `json:"labels,omitempty"` -} diff --git a/vendor/github.com/appc/spec/schema/types/BUILD b/vendor/github.com/appc/spec/schema/types/BUILD deleted file mode 100644 index b248f29e446..00000000000 --- a/vendor/github.com/appc/spec/schema/types/BUILD +++ /dev/null @@ -1,57 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "acidentifier.go", - "ackind.go", - "acname.go", - "annotations.go", - "app.go", - "date.go", - "dependencies.go", - "doc.go", - "environment.go", - "errors.go", - "event_handler.go", - "exec.go", - "hash.go", - "isolator.go", - "isolator_linux_specific.go", - "isolator_resources.go", - "isolator_unix.go", - "labels.go", - "mountpoint.go", - "port.go", - "semver.go", - "url.go", - "user_annotations.go", - "user_labels.go", - "uuid.go", - "volume.go", - ], - importpath = "github.com/appc/spec/schema/types", - visibility = ["//visibility:public"], - deps = [ - "//vendor/github.com/appc/spec/schema/common:go_default_library", - "//vendor/github.com/appc/spec/schema/types/resource:go_default_library", - "//vendor/github.com/coreos/go-semver/semver:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [ - ":package-srcs", - "//vendor/github.com/appc/spec/schema/types/resource:all-srcs", - ], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/appc/spec/schema/types/acidentifier.go b/vendor/github.com/appc/spec/schema/types/acidentifier.go deleted file mode 100644 index 904eda5cbc3..00000000000 --- a/vendor/github.com/appc/spec/schema/types/acidentifier.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" - "regexp" - "strings" -) - -var ( - // ValidACIdentifier is a regular expression that defines a valid ACIdentifier - ValidACIdentifier = regexp.MustCompile("^[a-z0-9]+([-._~/][a-z0-9]+)*$") - - invalidACIdentifierChars = regexp.MustCompile("[^a-z0-9-._~/]") - invalidACIdentifierEdges = regexp.MustCompile("(^[-._~/]+)|([-._~/]+$)") - - ErrEmptyACIdentifier = ACIdentifierError("ACIdentifier cannot be empty") - ErrInvalidEdgeInACIdentifier = ACIdentifierError("ACIdentifier must start and end with only lower case " + - "alphanumeric characters") - ErrInvalidCharInACIdentifier = ACIdentifierError("ACIdentifier must contain only lower case " + - `alphanumeric characters plus "-._~/"`) -) - -// ACIdentifier (an App-Container Identifier) is a format used by keys in image names -// and image labels of the App Container Standard. An ACIdentifier is restricted to numeric -// and lowercase URI unreserved characters defined in URI RFC[1]; all alphabetical characters -// must be lowercase only. Furthermore, the first and last character ("edges") must be -// alphanumeric, and an ACIdentifier cannot be empty. Programmatically, an ACIdentifier must -// conform to the regular expression ValidACIdentifier. -// -// [1] http://tools.ietf.org/html/rfc3986#section-2.3 -type ACIdentifier string - -func (n ACIdentifier) String() string { - return string(n) -} - -// Set sets the ACIdentifier to the given value, if it is valid; if not, -// an error is returned. -func (n *ACIdentifier) Set(s string) error { - nn, err := NewACIdentifier(s) - if err == nil { - *n = *nn - } - return err -} - -// Equals checks whether a given ACIdentifier is equal to this one. -func (n ACIdentifier) Equals(o ACIdentifier) bool { - return strings.ToLower(string(n)) == strings.ToLower(string(o)) -} - -// Empty returns a boolean indicating whether this ACIdentifier is empty. -func (n ACIdentifier) Empty() bool { - return n.String() == "" -} - -// NewACIdentifier generates a new ACIdentifier from a string. If the given string is -// not a valid ACIdentifier, nil and an error are returned. -func NewACIdentifier(s string) (*ACIdentifier, error) { - n := ACIdentifier(s) - if err := n.assertValid(); err != nil { - return nil, err - } - return &n, nil -} - -// MustACIdentifier generates a new ACIdentifier from a string, If the given string is -// not a valid ACIdentifier, it panics. -func MustACIdentifier(s string) *ACIdentifier { - n, err := NewACIdentifier(s) - if err != nil { - panic(err) - } - return n -} - -func (n ACIdentifier) assertValid() error { - s := string(n) - if len(s) == 0 { - return ErrEmptyACIdentifier - } - if invalidACIdentifierChars.MatchString(s) { - return ErrInvalidCharInACIdentifier - } - if invalidACIdentifierEdges.MatchString(s) { - return ErrInvalidEdgeInACIdentifier - } - return nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface -func (n *ACIdentifier) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - nn, err := NewACIdentifier(s) - if err != nil { - return err - } - *n = *nn - return nil -} - -// MarshalJSON implements the json.Marshaler interface -func (n ACIdentifier) MarshalJSON() ([]byte, error) { - if err := n.assertValid(); err != nil { - return nil, err - } - return json.Marshal(n.String()) -} - -// SanitizeACIdentifier replaces every invalid ACIdentifier character in s with an underscore -// making it a legal ACIdentifier string. If the character is an upper case letter it -// replaces it with its lower case. It also removes illegal edge characters -// (hyphens, period, underscore, tilde and slash). -// -// This is a helper function and its algorithm is not part of the spec. It -// should not be called without the user explicitly asking for a suggestion. -func SanitizeACIdentifier(s string) (string, error) { - s = strings.ToLower(s) - s = invalidACIdentifierChars.ReplaceAllString(s, "_") - s = invalidACIdentifierEdges.ReplaceAllString(s, "") - - if s == "" { - return "", errors.New("must contain at least one valid character") - } - - return s, nil -} diff --git a/vendor/github.com/appc/spec/schema/types/ackind.go b/vendor/github.com/appc/spec/schema/types/ackind.go deleted file mode 100644 index 1793ca8de8e..00000000000 --- a/vendor/github.com/appc/spec/schema/types/ackind.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "fmt" -) - -var ( - ErrNoACKind = ACKindError("ACKind must be set") -) - -// ACKind wraps a string to define a field which must be set with one of -// several ACKind values. If it is unset, or has an invalid value, the field -// will refuse to marshal/unmarshal. -type ACKind string - -func (a ACKind) String() string { - return string(a) -} - -func (a ACKind) assertValid() error { - s := a.String() - switch s { - case "ImageManifest", "PodManifest": - return nil - case "": - return ErrNoACKind - default: - msg := fmt.Sprintf("bad ACKind: %s", s) - return ACKindError(msg) - } -} - -func (a ACKind) MarshalJSON() ([]byte, error) { - if err := a.assertValid(); err != nil { - return nil, err - } - return json.Marshal(a.String()) -} - -func (a *ACKind) UnmarshalJSON(data []byte) error { - var s string - err := json.Unmarshal(data, &s) - if err != nil { - return err - } - na := ACKind(s) - if err := na.assertValid(); err != nil { - return err - } - *a = na - return nil -} diff --git a/vendor/github.com/appc/spec/schema/types/acname.go b/vendor/github.com/appc/spec/schema/types/acname.go deleted file mode 100644 index 5ececffb7f2..00000000000 --- a/vendor/github.com/appc/spec/schema/types/acname.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" - "regexp" - "strings" -) - -var ( - // ValidACName is a regular expression that defines a valid ACName - ValidACName = regexp.MustCompile("^[a-z0-9]+([-][a-z0-9]+)*$") - - invalidACNameChars = regexp.MustCompile("[^a-z0-9-]") - invalidACNameEdges = regexp.MustCompile("(^[-]+)|([-]+$)") - - ErrEmptyACName = ACNameError("ACName cannot be empty") - ErrInvalidEdgeInACName = ACNameError("ACName must start and end with only lower case " + - "alphanumeric characters") - ErrInvalidCharInACName = ACNameError("ACName must contain only lower case " + - `alphanumeric characters plus "-"`) -) - -// ACName (an App-Container Name) is a format used by keys in different formats -// of the App Container Standard. An ACName is restricted to numeric and lowercase -// characters accepted by the DNS RFC[1] plus "-"; all alphabetical characters must -// be lowercase only. Furthermore, the first and last character ("edges") must be -// alphanumeric, and an ACName cannot be empty. Programmatically, an ACName must -// conform to the regular expression ValidACName. -// -// [1] http://tools.ietf.org/html/rfc1123#page-13 -type ACName string - -func (n ACName) String() string { - return string(n) -} - -// Set sets the ACName to the given value, if it is valid; if not, -// an error is returned. -func (n *ACName) Set(s string) error { - nn, err := NewACName(s) - if err == nil { - *n = *nn - } - return err -} - -// Equals checks whether a given ACName is equal to this one. -func (n ACName) Equals(o ACName) bool { - return strings.ToLower(string(n)) == strings.ToLower(string(o)) -} - -// Empty returns a boolean indicating whether this ACName is empty. -func (n ACName) Empty() bool { - return n.String() == "" -} - -// NewACName generates a new ACName from a string. If the given string is -// not a valid ACName, nil and an error are returned. -func NewACName(s string) (*ACName, error) { - n := ACName(s) - if err := n.assertValid(); err != nil { - return nil, err - } - return &n, nil -} - -// MustACName generates a new ACName from a string, If the given string is -// not a valid ACName, it panics. -func MustACName(s string) *ACName { - n, err := NewACName(s) - if err != nil { - panic(err) - } - return n -} - -func (n ACName) assertValid() error { - s := string(n) - if len(s) == 0 { - return ErrEmptyACName - } - if invalidACNameChars.MatchString(s) { - return ErrInvalidCharInACName - } - if invalidACNameEdges.MatchString(s) { - return ErrInvalidEdgeInACName - } - return nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface -func (n *ACName) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - nn, err := NewACName(s) - if err != nil { - return err - } - *n = *nn - return nil -} - -// MarshalJSON implements the json.Marshaler interface -func (n ACName) MarshalJSON() ([]byte, error) { - if err := n.assertValid(); err != nil { - return nil, err - } - return json.Marshal(n.String()) -} - -// SanitizeACName replaces every invalid ACName character in s with a dash -// making it a legal ACName string. If the character is an upper case letter it -// replaces it with its lower case. It also removes illegal edge characters -// (hyphens). -// -// This is a helper function and its algorithm is not part of the spec. It -// should not be called without the user explicitly asking for a suggestion. -func SanitizeACName(s string) (string, error) { - s = strings.ToLower(s) - s = invalidACNameChars.ReplaceAllString(s, "-") - s = invalidACNameEdges.ReplaceAllString(s, "") - - if s == "" { - return "", errors.New("must contain at least one valid character") - } - - return s, nil -} diff --git a/vendor/github.com/appc/spec/schema/types/annotations.go b/vendor/github.com/appc/spec/schema/types/annotations.go deleted file mode 100644 index ce7743bf53f..00000000000 --- a/vendor/github.com/appc/spec/schema/types/annotations.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "fmt" -) - -type Annotations []Annotation - -type annotations Annotations - -type Annotation struct { - Name ACIdentifier `json:"name"` - Value string `json:"value"` -} - -func (a Annotations) assertValid() error { - seen := map[ACIdentifier]string{} - for _, anno := range a { - _, ok := seen[anno.Name] - if ok { - return fmt.Errorf(`duplicate annotations of name %q`, anno.Name) - } - seen[anno.Name] = anno.Value - } - if c, ok := seen["created"]; ok { - if _, err := NewDate(c); err != nil { - return err - } - } - if h, ok := seen["homepage"]; ok { - if _, err := NewURL(h); err != nil { - return err - } - } - if d, ok := seen["documentation"]; ok { - if _, err := NewURL(d); err != nil { - return err - } - } - - return nil -} - -func (a Annotations) MarshalJSON() ([]byte, error) { - if err := a.assertValid(); err != nil { - return nil, err - } - return json.Marshal(annotations(a)) -} - -func (a *Annotations) UnmarshalJSON(data []byte) error { - var ja annotations - if err := json.Unmarshal(data, &ja); err != nil { - return err - } - na := Annotations(ja) - if err := na.assertValid(); err != nil { - return err - } - *a = na - return nil -} - -// Retrieve the value of an annotation by the given name from Annotations, if -// it exists. -func (a Annotations) Get(name string) (val string, ok bool) { - for _, anno := range a { - if anno.Name.String() == name { - return anno.Value, true - } - } - return "", false -} - -// Set sets the value of an annotation by the given name, overwriting if one already exists. -func (a *Annotations) Set(name ACIdentifier, value string) { - for i, anno := range *a { - if anno.Name.Equals(name) { - (*a)[i] = Annotation{ - Name: name, - Value: value, - } - return - } - } - anno := Annotation{ - Name: name, - Value: value, - } - *a = append(*a, anno) -} diff --git a/vendor/github.com/appc/spec/schema/types/app.go b/vendor/github.com/appc/spec/schema/types/app.go deleted file mode 100644 index 0ef68c892f8..00000000000 --- a/vendor/github.com/appc/spec/schema/types/app.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" - "fmt" - "path" -) - -type App struct { - Exec Exec `json:"exec"` - EventHandlers []EventHandler `json:"eventHandlers,omitempty"` - User string `json:"user"` - Group string `json:"group"` - SupplementaryGIDs []int `json:"supplementaryGIDs,omitempty"` - WorkingDirectory string `json:"workingDirectory,omitempty"` - Environment Environment `json:"environment,omitempty"` - MountPoints []MountPoint `json:"mountPoints,omitempty"` - Ports []Port `json:"ports,omitempty"` - Isolators Isolators `json:"isolators,omitempty"` - UserAnnotations UserAnnotations `json:"userAnnotations,omitempty"` - UserLabels UserLabels `json:"userLabels,omitempty"` -} - -// app is a model to facilitate extra validation during the -// unmarshalling of the App -type app App - -func (a *App) UnmarshalJSON(data []byte) error { - ja := app(*a) - err := json.Unmarshal(data, &ja) - if err != nil { - return err - } - na := App(ja) - if err := na.assertValid(); err != nil { - return err - } - if na.Environment == nil { - na.Environment = make(Environment, 0) - } - *a = na - return nil -} - -func (a App) MarshalJSON() ([]byte, error) { - if err := a.assertValid(); err != nil { - return nil, err - } - return json.Marshal(app(a)) -} - -func (a *App) assertValid() error { - if err := a.Exec.assertValid(); err != nil { - return err - } - if a.User == "" { - return errors.New(`user is required`) - } - if a.Group == "" { - return errors.New(`group is required`) - } - if !path.IsAbs(a.WorkingDirectory) && a.WorkingDirectory != "" { - return errors.New("workingDirectory must be an absolute path") - } - eh := make(map[string]bool) - for _, e := range a.EventHandlers { - name := e.Name - if eh[name] { - return fmt.Errorf("Only one eventHandler of name %q allowed", name) - } - eh[name] = true - } - if err := a.Environment.assertValid(); err != nil { - return err - } - if err := a.Isolators.assertValid(); err != nil { - return err - } - return nil -} diff --git a/vendor/github.com/appc/spec/schema/types/date.go b/vendor/github.com/appc/spec/schema/types/date.go deleted file mode 100644 index 4458bf45d94..00000000000 --- a/vendor/github.com/appc/spec/schema/types/date.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "fmt" - "time" -) - -// Date wraps time.Time to marshal/unmarshal to/from JSON strings in strict -// accordance with RFC3339 -// TODO(jonboulle): golang's implementation seems slightly buggy here; -// according to http://tools.ietf.org/html/rfc3339#section-5.6 , applications -// may choose to separate the date and time with a space instead of a T -// character (for example, `date --rfc-3339` on GNU coreutils) - but this is -// considered an error by go's parser. File a bug? -type Date time.Time - -func NewDate(s string) (*Date, error) { - t, err := time.Parse(time.RFC3339, s) - if err != nil { - return nil, fmt.Errorf("bad Date: %v", err) - } - d := Date(t) - return &d, nil -} - -func (d Date) String() string { - return time.Time(d).Format(time.RFC3339) -} - -func (d *Date) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - nd, err := NewDate(s) - if err != nil { - return err - } - *d = *nd - return nil -} - -func (d Date) MarshalJSON() ([]byte, error) { - return json.Marshal(d.String()) -} diff --git a/vendor/github.com/appc/spec/schema/types/dependencies.go b/vendor/github.com/appc/spec/schema/types/dependencies.go deleted file mode 100644 index fb399e4041f..00000000000 --- a/vendor/github.com/appc/spec/schema/types/dependencies.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" -) - -type Dependencies []Dependency - -type Dependency struct { - ImageName ACIdentifier `json:"imageName"` - ImageID *Hash `json:"imageID,omitempty"` - Labels Labels `json:"labels,omitempty"` - Size uint `json:"size,omitempty"` -} - -type dependency Dependency - -func (d Dependency) assertValid() error { - if len(d.ImageName) < 1 { - return errors.New(`imageName cannot be empty`) - } - return nil -} - -func (d Dependency) MarshalJSON() ([]byte, error) { - if err := d.assertValid(); err != nil { - return nil, err - } - return json.Marshal(dependency(d)) -} - -func (d *Dependency) UnmarshalJSON(data []byte) error { - var jd dependency - if err := json.Unmarshal(data, &jd); err != nil { - return err - } - nd := Dependency(jd) - if err := nd.assertValid(); err != nil { - return err - } - *d = nd - return nil -} diff --git a/vendor/github.com/appc/spec/schema/types/doc.go b/vendor/github.com/appc/spec/schema/types/doc.go deleted file mode 100644 index 9c540851b05..00000000000 --- a/vendor/github.com/appc/spec/schema/types/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types contains structs representing the various types in the app -// container specification. It is used by the [schema manifest types](../) -// to enforce validation. -package types diff --git a/vendor/github.com/appc/spec/schema/types/environment.go b/vendor/github.com/appc/spec/schema/types/environment.go deleted file mode 100644 index f152a6b88df..00000000000 --- a/vendor/github.com/appc/spec/schema/types/environment.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "fmt" - "regexp" -) - -var ( - envPattern = regexp.MustCompile("^[A-Za-z_][A-Za-z_0-9]*$") -) - -type Environment []EnvironmentVariable - -type environment Environment - -type EnvironmentVariable struct { - Name string `json:"name"` - Value string `json:"value"` -} - -func (ev EnvironmentVariable) assertValid() error { - if len(ev.Name) == 0 { - return fmt.Errorf(`environment variable name must not be empty`) - } - if !envPattern.MatchString(ev.Name) { - return fmt.Errorf(`environment variable does not have valid identifier %q`, ev.Name) - } - return nil -} - -func (e Environment) assertValid() error { - seen := map[string]bool{} - for _, env := range e { - if err := env.assertValid(); err != nil { - return err - } - _, ok := seen[env.Name] - if ok { - return fmt.Errorf(`duplicate environment variable of name %q`, env.Name) - } - seen[env.Name] = true - } - - return nil -} - -func (e Environment) MarshalJSON() ([]byte, error) { - if err := e.assertValid(); err != nil { - return nil, err - } - return json.Marshal(environment(e)) -} - -func (e *Environment) UnmarshalJSON(data []byte) error { - var je environment - if err := json.Unmarshal(data, &je); err != nil { - return err - } - ne := Environment(je) - if err := ne.assertValid(); err != nil { - return err - } - *e = ne - return nil -} - -// Retrieve the value of an environment variable by the given name from -// Environment, if it exists. -func (e Environment) Get(name string) (value string, ok bool) { - for _, env := range e { - if env.Name == name { - return env.Value, true - } - } - return "", false -} - -// Set sets the value of an environment variable by the given name, -// overwriting if one already exists. -func (e *Environment) Set(name string, value string) { - for i, env := range *e { - if env.Name == name { - (*e)[i] = EnvironmentVariable{ - Name: name, - Value: value, - } - return - } - } - env := EnvironmentVariable{ - Name: name, - Value: value, - } - *e = append(*e, env) -} diff --git a/vendor/github.com/appc/spec/schema/types/errors.go b/vendor/github.com/appc/spec/schema/types/errors.go deleted file mode 100644 index bb46515944b..00000000000 --- a/vendor/github.com/appc/spec/schema/types/errors.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import "fmt" - -// An ACKindError is returned when the wrong ACKind is set in a manifest -type ACKindError string - -func (e ACKindError) Error() string { - return string(e) -} - -func InvalidACKindError(kind ACKind) ACKindError { - return ACKindError(fmt.Sprintf("missing or bad ACKind (must be %#v)", kind)) -} - -// An ACVersionError is returned when a bad ACVersion is set in a manifest -type ACVersionError string - -func (e ACVersionError) Error() string { - return string(e) -} - -// An ACIdentifierError is returned when a bad value is used for an ACIdentifier -type ACIdentifierError string - -func (e ACIdentifierError) Error() string { - return string(e) -} - -// An ACNameError is returned when a bad value is used for an ACName -type ACNameError string - -func (e ACNameError) Error() string { - return string(e) -} diff --git a/vendor/github.com/appc/spec/schema/types/event_handler.go b/vendor/github.com/appc/spec/schema/types/event_handler.go deleted file mode 100644 index f40c642be40..00000000000 --- a/vendor/github.com/appc/spec/schema/types/event_handler.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" - "fmt" -) - -type EventHandler struct { - Name string `json:"name"` - Exec Exec `json:"exec"` -} - -type eventHandler EventHandler - -func (e EventHandler) assertValid() error { - s := e.Name - switch s { - case "pre-start", "post-stop": - return nil - case "": - return errors.New(`eventHandler "name" cannot be empty`) - default: - return fmt.Errorf(`bad eventHandler "name": %q`, s) - } -} - -func (e EventHandler) MarshalJSON() ([]byte, error) { - if err := e.assertValid(); err != nil { - return nil, err - } - return json.Marshal(eventHandler(e)) -} - -func (e *EventHandler) UnmarshalJSON(data []byte) error { - var je eventHandler - err := json.Unmarshal(data, &je) - if err != nil { - return err - } - ne := EventHandler(je) - if err := ne.assertValid(); err != nil { - return err - } - *e = ne - return nil -} diff --git a/vendor/github.com/appc/spec/schema/types/exec.go b/vendor/github.com/appc/spec/schema/types/exec.go deleted file mode 100644 index fa8b156cfb0..00000000000 --- a/vendor/github.com/appc/spec/schema/types/exec.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import "encoding/json" - -type Exec []string - -type exec Exec - -func (e Exec) assertValid() error { - return nil -} - -func (e Exec) MarshalJSON() ([]byte, error) { - if err := e.assertValid(); err != nil { - return nil, err - } - return json.Marshal(exec(e)) -} - -func (e *Exec) UnmarshalJSON(data []byte) error { - var je exec - err := json.Unmarshal(data, &je) - if err != nil { - return err - } - ne := Exec(je) - if err := ne.assertValid(); err != nil { - return err - } - *e = ne - return nil -} diff --git a/vendor/github.com/appc/spec/schema/types/hash.go b/vendor/github.com/appc/spec/schema/types/hash.go deleted file mode 100644 index 1c060a47a0a..00000000000 --- a/vendor/github.com/appc/spec/schema/types/hash.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "crypto/sha512" - "encoding/json" - "errors" - "fmt" - "reflect" - "strings" -) - -const ( - maxHashSize = (sha512.Size / 2) + len("sha512-") -) - -// Hash encodes a hash specified in a string of the form: -// "-" -// for example -// "sha512-06c733b1838136838e6d2d3e8fa5aea4c7905e92[...]" -// Valid types are currently: -// * sha512 -type Hash struct { - typ string - Val string -} - -func NewHash(s string) (*Hash, error) { - elems := strings.Split(s, "-") - if len(elems) != 2 { - return nil, errors.New("badly formatted hash string") - } - nh := Hash{ - typ: elems[0], - Val: elems[1], - } - if err := nh.assertValid(); err != nil { - return nil, err - } - return &nh, nil -} - -func (h Hash) String() string { - return fmt.Sprintf("%s-%s", h.typ, h.Val) -} - -func (h *Hash) Set(s string) error { - nh, err := NewHash(s) - if err == nil { - *h = *nh - } - return err -} - -func (h Hash) Empty() bool { - return reflect.DeepEqual(h, Hash{}) -} - -func (h Hash) assertValid() error { - switch h.typ { - case "sha512": - case "": - return fmt.Errorf("unexpected empty hash type") - default: - return fmt.Errorf("unrecognized hash type: %v", h.typ) - } - if h.Val == "" { - return fmt.Errorf("unexpected empty hash value") - } - return nil -} - -func (h *Hash) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - nh, err := NewHash(s) - if err != nil { - return err - } - *h = *nh - return nil -} - -func (h Hash) MarshalJSON() ([]byte, error) { - if err := h.assertValid(); err != nil { - return nil, err - } - return json.Marshal(h.String()) -} - -func NewHashSHA512(b []byte) *Hash { - h := sha512.New() - h.Write(b) - nh, _ := NewHash(fmt.Sprintf("sha512-%x", h.Sum(nil))) - return nh -} - -func ShortHash(hash string) string { - if len(hash) > maxHashSize { - return hash[:maxHashSize] - } - return hash -} diff --git a/vendor/github.com/appc/spec/schema/types/isolator.go b/vendor/github.com/appc/spec/schema/types/isolator.go deleted file mode 100644 index fcd1801e64e..00000000000 --- a/vendor/github.com/appc/spec/schema/types/isolator.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" - "fmt" -) - -var ( - isolatorMap map[ACIdentifier]IsolatorValueConstructor - - // ErrIncompatibleIsolator is returned whenever an Isolators set contains - // conflicting IsolatorValue instances - ErrIncompatibleIsolator = errors.New("isolators set contains incompatible types") - // ErrInvalidIsolator is returned upon validation failures due to improper - // or partially constructed Isolator instances (eg. from incomplete direct construction) - ErrInvalidIsolator = errors.New("invalid isolator") -) - -func init() { - isolatorMap = make(map[ACIdentifier]IsolatorValueConstructor) -} - -type IsolatorValueConstructor func() IsolatorValue - -func AddIsolatorValueConstructor(n ACIdentifier, i IsolatorValueConstructor) { - isolatorMap[n] = i -} - -func AddIsolatorName(n ACIdentifier, ns map[ACIdentifier]struct{}) { - ns[n] = struct{}{} -} - -// Isolators encapsulates a list of individual Isolators for the ImageManifest -// and PodManifest schemas. -type Isolators []Isolator - -// assertValid checks that every single isolator is valid and that -// the whole set is well built -func (isolators Isolators) assertValid() error { - typesMap := make(map[ACIdentifier]bool) - for _, i := range isolators { - v := i.Value() - if v == nil { - return ErrInvalidIsolator - } - if err := v.AssertValid(); err != nil { - return err - } - if _, ok := typesMap[i.Name]; ok { - if !v.multipleAllowed() { - return fmt.Errorf(`isolators set contains too many instances of type %s"`, i.Name) - } - } - for _, c := range v.Conflicts() { - if _, found := typesMap[c]; found { - return ErrIncompatibleIsolator - } - } - typesMap[i.Name] = true - } - return nil -} - -// GetByName returns the last isolator in the list by the given name. -func (is *Isolators) GetByName(name ACIdentifier) *Isolator { - var i Isolator - for j := len(*is) - 1; j >= 0; j-- { - i = []Isolator(*is)[j] - if i.Name == name { - return &i - } - } - return nil -} - -// ReplaceIsolatorsByName overrides matching isolator types with a new -// isolator, deleting them all and appending the new one instead -func (is *Isolators) ReplaceIsolatorsByName(newIs Isolator, oldNames []ACIdentifier) { - var i Isolator - for j := len(*is) - 1; j >= 0; j-- { - i = []Isolator(*is)[j] - for _, name := range oldNames { - if i.Name == name { - *is = append((*is)[:j], (*is)[j+1:]...) - } - } - } - *is = append((*is)[:], newIs) - return -} - -// Unrecognized returns a set of isolators that are not recognized. -// An isolator is not recognized if it has not had an associated -// constructor registered with AddIsolatorValueConstructor. -func (is *Isolators) Unrecognized() Isolators { - u := Isolators{} - for _, i := range *is { - if i.value == nil { - u = append(u, i) - } - } - return u -} - -// IsolatorValue encapsulates the actual value of an Isolator which may be -// serialized as any arbitrary JSON blob. Specific Isolator types should -// implement this interface to facilitate unmarshalling and validation. -type IsolatorValue interface { - // UnmarshalJSON unserialize a JSON-encoded isolator - UnmarshalJSON(b []byte) error - // AssertValid returns a non-nil error value if an IsolatorValue is not valid - // according to appc spec - AssertValid() error - // Conflicts returns a list of conflicting isolators types, which cannot co-exist - // together with this IsolatorValue - Conflicts() []ACIdentifier - // multipleAllowed specifies whether multiple isolator instances are allowed - // for this isolator type - multipleAllowed() bool -} - -// Isolator is a model for unmarshalling isolator types from their JSON-encoded -// representation. -type Isolator struct { - // Name is the name of the Isolator type as defined in the specification. - Name ACIdentifier `json:"name"` - // ValueRaw captures the raw JSON value of an Isolator that was - // unmarshalled. This field is used for unmarshalling only. It MUST NOT - // be referenced by external users of the Isolator struct. It is - // exported only to satisfy Go's unfortunate requirement that fields - // must be capitalized to be unmarshalled successfully. - ValueRaw *json.RawMessage `json:"value"` - // value captures the "true" value of the isolator. - value IsolatorValue -} - -// isolator is a shadow type used for unmarshalling. -type isolator Isolator - -// Value returns the raw Value of this Isolator. Users should perform a type -// switch/assertion on this value to extract the underlying isolator type. -func (i *Isolator) Value() IsolatorValue { - return i.value -} - -// UnmarshalJSON populates this Isolator from a JSON-encoded representation. To -// unmarshal the Value of the Isolator, it will use the appropriate constructor -// as registered by AddIsolatorValueConstructor. -func (i *Isolator) UnmarshalJSON(b []byte) error { - var ii isolator - err := json.Unmarshal(b, &ii) - if err != nil { - return err - } - - var dst IsolatorValue - con, ok := isolatorMap[ii.Name] - if ok { - dst = con() - err = dst.UnmarshalJSON(*ii.ValueRaw) - if err != nil { - return err - } - err = dst.AssertValid() - if err != nil { - return err - } - } - - i.value = dst - i.ValueRaw = ii.ValueRaw - i.Name = ii.Name - - return nil -} diff --git a/vendor/github.com/appc/spec/schema/types/isolator_linux_specific.go b/vendor/github.com/appc/spec/schema/types/isolator_linux_specific.go deleted file mode 100644 index 3d5dc9fa285..00000000000 --- a/vendor/github.com/appc/spec/schema/types/isolator_linux_specific.go +++ /dev/null @@ -1,529 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" - "fmt" - "strings" - "unicode" -) - -const ( - LinuxCapabilitiesRetainSetName = "os/linux/capabilities-retain-set" - LinuxCapabilitiesRevokeSetName = "os/linux/capabilities-remove-set" - LinuxNoNewPrivilegesName = "os/linux/no-new-privileges" - LinuxSeccompRemoveSetName = "os/linux/seccomp-remove-set" - LinuxSeccompRetainSetName = "os/linux/seccomp-retain-set" - LinuxOOMScoreAdjName = "os/linux/oom-score-adj" - LinuxCPUSharesName = "os/linux/cpu-shares" - LinuxSELinuxContextName = "os/linux/selinux-context" -) - -var LinuxIsolatorNames = make(map[ACIdentifier]struct{}) - -func init() { - for name, con := range map[ACIdentifier]IsolatorValueConstructor{ - LinuxCapabilitiesRevokeSetName: func() IsolatorValue { return &LinuxCapabilitiesRevokeSet{} }, - LinuxCapabilitiesRetainSetName: func() IsolatorValue { return &LinuxCapabilitiesRetainSet{} }, - LinuxNoNewPrivilegesName: func() IsolatorValue { v := LinuxNoNewPrivileges(false); return &v }, - LinuxOOMScoreAdjName: func() IsolatorValue { v := LinuxOOMScoreAdj(0); return &v }, - LinuxCPUSharesName: func() IsolatorValue { v := LinuxCPUShares(1024); return &v }, - LinuxSeccompRemoveSetName: func() IsolatorValue { return &LinuxSeccompRemoveSet{} }, - LinuxSeccompRetainSetName: func() IsolatorValue { return &LinuxSeccompRetainSet{} }, - LinuxSELinuxContextName: func() IsolatorValue { return &LinuxSELinuxContext{} }, - } { - AddIsolatorName(name, LinuxIsolatorNames) - AddIsolatorValueConstructor(name, con) - } -} - -type LinuxNoNewPrivileges bool - -func (l LinuxNoNewPrivileges) AssertValid() error { - return nil -} - -// TODO(lucab): both need to be clarified in spec, -// see https://github.com/appc/spec/issues/625 -func (l LinuxNoNewPrivileges) multipleAllowed() bool { - return true -} -func (l LinuxNoNewPrivileges) Conflicts() []ACIdentifier { - return nil -} - -func (l *LinuxNoNewPrivileges) UnmarshalJSON(b []byte) error { - var v bool - err := json.Unmarshal(b, &v) - if err != nil { - return err - } - - *l = LinuxNoNewPrivileges(v) - - return nil -} - -type AsIsolator interface { - AsIsolator() (*Isolator, error) -} - -type LinuxCapabilitiesSet interface { - Set() []LinuxCapability - AssertValid() error -} - -type LinuxCapability string - -type linuxCapabilitiesSetValue struct { - Set []LinuxCapability `json:"set"` -} - -type linuxCapabilitiesSetBase struct { - val linuxCapabilitiesSetValue -} - -func (l linuxCapabilitiesSetBase) AssertValid() error { - if len(l.val.Set) == 0 { - return errors.New("set must be non-empty") - } - return nil -} - -// TODO(lucab): both need to be clarified in spec, -// see https://github.com/appc/spec/issues/625 -func (l linuxCapabilitiesSetBase) multipleAllowed() bool { - return true -} -func (l linuxCapabilitiesSetBase) Conflicts() []ACIdentifier { - return nil -} - -func (l *linuxCapabilitiesSetBase) UnmarshalJSON(b []byte) error { - var v linuxCapabilitiesSetValue - err := json.Unmarshal(b, &v) - if err != nil { - return err - } - - l.val = v - - return err -} - -func (l linuxCapabilitiesSetBase) Set() []LinuxCapability { - return l.val.Set -} - -type LinuxCapabilitiesRetainSet struct { - linuxCapabilitiesSetBase -} - -func NewLinuxCapabilitiesRetainSet(caps ...string) (*LinuxCapabilitiesRetainSet, error) { - l := LinuxCapabilitiesRetainSet{ - linuxCapabilitiesSetBase{ - linuxCapabilitiesSetValue{ - make([]LinuxCapability, len(caps)), - }, - }, - } - for i, c := range caps { - l.linuxCapabilitiesSetBase.val.Set[i] = LinuxCapability(c) - } - if err := l.AssertValid(); err != nil { - return nil, err - } - return &l, nil -} - -func (l LinuxCapabilitiesRetainSet) AsIsolator() (*Isolator, error) { - b, err := json.Marshal(l.linuxCapabilitiesSetBase.val) - if err != nil { - return nil, err - } - rm := json.RawMessage(b) - return &Isolator{ - Name: LinuxCapabilitiesRetainSetName, - ValueRaw: &rm, - value: &l, - }, nil -} - -type LinuxCapabilitiesRevokeSet struct { - linuxCapabilitiesSetBase -} - -func NewLinuxCapabilitiesRevokeSet(caps ...string) (*LinuxCapabilitiesRevokeSet, error) { - l := LinuxCapabilitiesRevokeSet{ - linuxCapabilitiesSetBase{ - linuxCapabilitiesSetValue{ - make([]LinuxCapability, len(caps)), - }, - }, - } - for i, c := range caps { - l.linuxCapabilitiesSetBase.val.Set[i] = LinuxCapability(c) - } - if err := l.AssertValid(); err != nil { - return nil, err - } - return &l, nil -} - -func (l LinuxCapabilitiesRevokeSet) AsIsolator() (*Isolator, error) { - b, err := json.Marshal(l.linuxCapabilitiesSetBase.val) - if err != nil { - return nil, err - } - rm := json.RawMessage(b) - return &Isolator{ - Name: LinuxCapabilitiesRevokeSetName, - ValueRaw: &rm, - value: &l, - }, nil -} - -type LinuxSeccompSet interface { - Set() []LinuxSeccompEntry - Errno() LinuxSeccompErrno - AssertValid() error -} - -type LinuxSeccompEntry string -type LinuxSeccompErrno string - -type linuxSeccompValue struct { - Set []LinuxSeccompEntry `json:"set"` - Errno LinuxSeccompErrno `json:"errno"` -} - -type linuxSeccompBase struct { - val linuxSeccompValue -} - -func (l linuxSeccompBase) multipleAllowed() bool { - return false -} - -func (l linuxSeccompBase) AssertValid() error { - if len(l.val.Set) == 0 { - return errors.New("set must be non-empty") - } - if l.val.Errno == "" { - return nil - } - for _, c := range l.val.Errno { - if !unicode.IsUpper(c) { - return errors.New("errno must be an upper case string") - } - } - return nil -} - -func (l *linuxSeccompBase) UnmarshalJSON(b []byte) error { - var v linuxSeccompValue - err := json.Unmarshal(b, &v) - if err != nil { - return err - } - l.val = v - return nil -} - -func (l linuxSeccompBase) Set() []LinuxSeccompEntry { - return l.val.Set -} - -func (l linuxSeccompBase) Errno() LinuxSeccompErrno { - return l.val.Errno -} - -type LinuxSeccompRetainSet struct { - linuxSeccompBase -} - -func (l LinuxSeccompRetainSet) Conflicts() []ACIdentifier { - return []ACIdentifier{LinuxSeccompRemoveSetName} -} - -func NewLinuxSeccompRetainSet(errno string, syscall ...string) (*LinuxSeccompRetainSet, error) { - l := LinuxSeccompRetainSet{ - linuxSeccompBase{ - linuxSeccompValue{ - make([]LinuxSeccompEntry, len(syscall)), - LinuxSeccompErrno(errno), - }, - }, - } - for i, c := range syscall { - l.linuxSeccompBase.val.Set[i] = LinuxSeccompEntry(c) - } - if err := l.AssertValid(); err != nil { - return nil, err - } - return &l, nil -} - -func (l LinuxSeccompRetainSet) AsIsolator() (*Isolator, error) { - b, err := json.Marshal(l.linuxSeccompBase.val) - if err != nil { - return nil, err - } - rm := json.RawMessage(b) - return &Isolator{ - Name: LinuxSeccompRetainSetName, - ValueRaw: &rm, - value: &l, - }, nil -} - -type LinuxSeccompRemoveSet struct { - linuxSeccompBase -} - -func (l LinuxSeccompRemoveSet) Conflicts() []ACIdentifier { - return []ACIdentifier{LinuxSeccompRetainSetName} -} - -func NewLinuxSeccompRemoveSet(errno string, syscall ...string) (*LinuxSeccompRemoveSet, error) { - l := LinuxSeccompRemoveSet{ - linuxSeccompBase{ - linuxSeccompValue{ - make([]LinuxSeccompEntry, len(syscall)), - LinuxSeccompErrno(errno), - }, - }, - } - for i, c := range syscall { - l.linuxSeccompBase.val.Set[i] = LinuxSeccompEntry(c) - } - if err := l.AssertValid(); err != nil { - return nil, err - } - return &l, nil -} - -func (l LinuxSeccompRemoveSet) AsIsolator() (*Isolator, error) { - b, err := json.Marshal(l.linuxSeccompBase.val) - if err != nil { - return nil, err - } - rm := json.RawMessage(b) - return &Isolator{ - Name: LinuxSeccompRemoveSetName, - ValueRaw: &rm, - value: &l, - }, nil -} - -// LinuxCPUShares assigns the CPU time share weight to the processes executed. -// See https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#CPUShares=weight, -// https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt -type LinuxCPUShares int - -func NewLinuxCPUShares(val int) (*LinuxCPUShares, error) { - l := LinuxCPUShares(val) - if err := l.AssertValid(); err != nil { - return nil, err - } - - return &l, nil -} - -func (l LinuxCPUShares) AssertValid() error { - if l < 2 || l > 262144 { - return fmt.Errorf("%s must be between 2 and 262144, got %d", LinuxCPUSharesName, l) - } - return nil -} - -func (l LinuxCPUShares) multipleAllowed() bool { - return false -} - -func (l LinuxCPUShares) Conflicts() []ACIdentifier { - return nil -} - -func (l *LinuxCPUShares) UnmarshalJSON(b []byte) error { - var v int - err := json.Unmarshal(b, &v) - if err != nil { - return err - } - - *l = LinuxCPUShares(v) - return nil -} - -func (l LinuxCPUShares) AsIsolator() Isolator { - b, err := json.Marshal(l) - if err != nil { - panic(err) - } - rm := json.RawMessage(b) - return Isolator{ - Name: LinuxCPUSharesName, - ValueRaw: &rm, - value: &l, - } -} - -// LinuxOOMScoreAdj is equivalent to /proc/[pid]/oom_score_adj -type LinuxOOMScoreAdj int // -1000 to 1000 - -func NewLinuxOOMScoreAdj(val int) (*LinuxOOMScoreAdj, error) { - l := LinuxOOMScoreAdj(val) - if err := l.AssertValid(); err != nil { - return nil, err - } - - return &l, nil -} - -func (l LinuxOOMScoreAdj) AssertValid() error { - if l < -1000 || l > 1000 { - return fmt.Errorf("%s must be between -1000 and 1000, got %d", LinuxOOMScoreAdjName, l) - } - return nil -} - -func (l LinuxOOMScoreAdj) multipleAllowed() bool { - return false -} - -func (l LinuxOOMScoreAdj) Conflicts() []ACIdentifier { - return nil -} - -func (l *LinuxOOMScoreAdj) UnmarshalJSON(b []byte) error { - var v int - err := json.Unmarshal(b, &v) - if err != nil { - return err - } - - *l = LinuxOOMScoreAdj(v) - return nil -} - -func (l LinuxOOMScoreAdj) AsIsolator() Isolator { - b, err := json.Marshal(l) - if err != nil { - panic(err) - } - rm := json.RawMessage(b) - return Isolator{ - Name: LinuxOOMScoreAdjName, - ValueRaw: &rm, - value: &l, - } -} - -type LinuxSELinuxUser string -type LinuxSELinuxRole string -type LinuxSELinuxType string -type LinuxSELinuxLevel string - -type linuxSELinuxValue struct { - User LinuxSELinuxUser `json:"user"` - Role LinuxSELinuxRole `json:"role"` - Type LinuxSELinuxType `json:"type"` - Level LinuxSELinuxLevel `json:"level"` -} - -type LinuxSELinuxContext struct { - val linuxSELinuxValue -} - -func (l LinuxSELinuxContext) AssertValid() error { - if l.val.User == "" || strings.Contains(string(l.val.User), ":") { - return fmt.Errorf("invalid user value %q", l.val.User) - } - if l.val.Role == "" || strings.Contains(string(l.val.Role), ":") { - return fmt.Errorf("invalid role value %q", l.val.Role) - } - if l.val.Type == "" || strings.Contains(string(l.val.Type), ":") { - return fmt.Errorf("invalid type value %q", l.val.Type) - } - if l.val.Level == "" { - return fmt.Errorf("invalid level value %q", l.val.Level) - } - return nil -} - -func (l *LinuxSELinuxContext) UnmarshalJSON(b []byte) error { - var v linuxSELinuxValue - err := json.Unmarshal(b, &v) - if err != nil { - return err - } - l.val = v - return nil -} - -func (l LinuxSELinuxContext) User() LinuxSELinuxUser { - return l.val.User -} - -func (l LinuxSELinuxContext) Role() LinuxSELinuxRole { - return l.val.Role -} - -func (l LinuxSELinuxContext) Type() LinuxSELinuxType { - return l.val.Type -} - -func (l LinuxSELinuxContext) Level() LinuxSELinuxLevel { - return l.val.Level -} - -func (l LinuxSELinuxContext) multipleAllowed() bool { - return false -} - -func (l LinuxSELinuxContext) Conflicts() []ACIdentifier { - return nil -} - -func NewLinuxSELinuxContext(selinuxUser, selinuxRole, selinuxType, selinuxLevel string) (*LinuxSELinuxContext, error) { - l := LinuxSELinuxContext{ - linuxSELinuxValue{ - LinuxSELinuxUser(selinuxUser), - LinuxSELinuxRole(selinuxRole), - LinuxSELinuxType(selinuxType), - LinuxSELinuxLevel(selinuxLevel), - }, - } - if err := l.AssertValid(); err != nil { - return nil, err - } - return &l, nil -} - -func (l LinuxSELinuxContext) AsIsolator() (*Isolator, error) { - b, err := json.Marshal(l.val) - if err != nil { - return nil, err - } - rm := json.RawMessage(b) - return &Isolator{ - Name: LinuxSELinuxContextName, - ValueRaw: &rm, - value: &l, - }, nil -} diff --git a/vendor/github.com/appc/spec/schema/types/isolator_resources.go b/vendor/github.com/appc/spec/schema/types/isolator_resources.go deleted file mode 100644 index 2ec250d4f97..00000000000 --- a/vendor/github.com/appc/spec/schema/types/isolator_resources.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/appc/spec/schema/types/resource" -) - -var ( - ErrDefaultTrue = errors.New("default must be false") - ErrDefaultRequired = errors.New("default must be true") - ErrRequestNonEmpty = errors.New("request not supported by this resource, must be empty") - - ResourceIsolatorNames = make(map[ACIdentifier]struct{}) -) - -const ( - ResourceBlockBandwidthName = "resource/block-bandwidth" - ResourceBlockIOPSName = "resource/block-iops" - ResourceCPUName = "resource/cpu" - ResourceMemoryName = "resource/memory" - ResourceNetworkBandwidthName = "resource/network-bandwidth" -) - -func init() { - for name, con := range map[ACIdentifier]IsolatorValueConstructor{ - ResourceBlockBandwidthName: func() IsolatorValue { return &ResourceBlockBandwidth{} }, - ResourceBlockIOPSName: func() IsolatorValue { return &ResourceBlockIOPS{} }, - ResourceCPUName: func() IsolatorValue { return &ResourceCPU{} }, - ResourceMemoryName: func() IsolatorValue { return &ResourceMemory{} }, - ResourceNetworkBandwidthName: func() IsolatorValue { return &ResourceNetworkBandwidth{} }, - } { - AddIsolatorName(name, ResourceIsolatorNames) - AddIsolatorValueConstructor(name, con) - } -} - -type Resource interface { - Limit() *resource.Quantity - Request() *resource.Quantity - Default() bool -} - -type ResourceBase struct { - val resourceValue -} - -type resourceValue struct { - Default bool `json:"default"` - Request *resource.Quantity `json:"request"` - Limit *resource.Quantity `json:"limit"` -} - -func (r ResourceBase) Limit() *resource.Quantity { - return r.val.Limit -} -func (r ResourceBase) Request() *resource.Quantity { - return r.val.Request -} -func (r ResourceBase) Default() bool { - return r.val.Default -} - -func (r *ResourceBase) UnmarshalJSON(b []byte) error { - return json.Unmarshal(b, &r.val) -} - -func (r ResourceBase) AssertValid() error { - return nil -} - -// TODO(lucab): both need to be clarified in spec, -// see https://github.com/appc/spec/issues/625 -func (l ResourceBase) multipleAllowed() bool { - return true -} -func (l ResourceBase) Conflicts() []ACIdentifier { - return nil -} - -type ResourceBlockBandwidth struct { - ResourceBase -} - -func (r ResourceBlockBandwidth) AssertValid() error { - if r.Default() != true { - return ErrDefaultRequired - } - if r.Request() != nil { - return ErrRequestNonEmpty - } - return nil -} - -type ResourceBlockIOPS struct { - ResourceBase -} - -func (r ResourceBlockIOPS) AssertValid() error { - if r.Default() != true { - return ErrDefaultRequired - } - if r.Request() != nil { - return ErrRequestNonEmpty - } - return nil -} - -type ResourceCPU struct { - ResourceBase -} - -func (r ResourceCPU) String() string { - return fmt.Sprintf("ResourceCPU(request=%s, limit=%s)", r.Request(), r.Limit()) -} - -func (r ResourceCPU) AssertValid() error { - if r.Default() != false { - return ErrDefaultTrue - } - return nil -} - -func (r ResourceCPU) AsIsolator() Isolator { - isol := isolatorMap[ResourceCPUName]() - - b, err := json.Marshal(r.val) - if err != nil { - panic(err) - } - valRaw := json.RawMessage(b) - return Isolator{ - Name: ResourceCPUName, - ValueRaw: &valRaw, - value: isol, - } -} - -func NewResourceCPUIsolator(request, limit string) (*ResourceCPU, error) { - req, err := resource.ParseQuantity(request) - if err != nil { - return nil, fmt.Errorf("error parsing request: %v", err) - } - lim, err := resource.ParseQuantity(limit) - if err != nil { - return nil, fmt.Errorf("error parsing limit: %v", err) - } - res := &ResourceCPU{ - ResourceBase{ - resourceValue{ - Request: &req, - Limit: &lim, - }, - }, - } - if err := res.AssertValid(); err != nil { - // should never happen - return nil, err - } - return res, nil -} - -type ResourceMemory struct { - ResourceBase -} - -func (r ResourceMemory) String() string { - return fmt.Sprintf("ResourceMemory(request=%s, limit=%s)", r.Request(), r.Limit()) -} - -func (r ResourceMemory) AssertValid() error { - if r.Default() != false { - return ErrDefaultTrue - } - return nil -} - -func (r ResourceMemory) AsIsolator() Isolator { - isol := isolatorMap[ResourceMemoryName]() - - b, err := json.Marshal(r.val) - if err != nil { - panic(err) - } - valRaw := json.RawMessage(b) - return Isolator{ - Name: ResourceMemoryName, - ValueRaw: &valRaw, - value: isol, - } -} - -func NewResourceMemoryIsolator(request, limit string) (*ResourceMemory, error) { - req, err := resource.ParseQuantity(request) - if err != nil { - return nil, fmt.Errorf("error parsing request: %v", err) - } - lim, err := resource.ParseQuantity(limit) - if err != nil { - return nil, fmt.Errorf("error parsing limit: %v", err) - } - res := &ResourceMemory{ - ResourceBase{ - resourceValue{ - Request: &req, - Limit: &lim, - }, - }, - } - if err := res.AssertValid(); err != nil { - // should never happen - return nil, err - } - return res, nil -} - -type ResourceNetworkBandwidth struct { - ResourceBase -} - -func (r ResourceNetworkBandwidth) AssertValid() error { - if r.Default() != true { - return ErrDefaultRequired - } - if r.Request() != nil { - return ErrRequestNonEmpty - } - return nil -} diff --git a/vendor/github.com/appc/spec/schema/types/isolator_unix.go b/vendor/github.com/appc/spec/schema/types/isolator_unix.go deleted file mode 100644 index ac0111a7deb..00000000000 --- a/vendor/github.com/appc/spec/schema/types/isolator_unix.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2016 The appc Authors -// -// 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 types - -import ( - "encoding/json" -) - -var ( - UnixIsolatorNames = make(map[ACIdentifier]struct{}) -) - -const ( - //TODO(lucab): add "ulimit" isolators - UnixSysctlName = "os/unix/sysctl" -) - -func init() { - for name, con := range map[ACIdentifier]IsolatorValueConstructor{ - UnixSysctlName: func() IsolatorValue { return &UnixSysctl{} }, - } { - AddIsolatorName(name, UnixIsolatorNames) - AddIsolatorValueConstructor(name, con) - } -} - -type UnixSysctl map[string]string - -func (s *UnixSysctl) UnmarshalJSON(b []byte) error { - var v map[string]string - err := json.Unmarshal(b, &v) - if err != nil { - return err - } - *s = UnixSysctl(v) - return err -} - -func (s UnixSysctl) AssertValid() error { - return nil -} - -func (s UnixSysctl) multipleAllowed() bool { - return false -} -func (s UnixSysctl) Conflicts() []ACIdentifier { - return nil -} - -func (s UnixSysctl) AsIsolator() Isolator { - isol := isolatorMap[UnixSysctlName]() - - b, err := json.Marshal(s) - if err != nil { - panic(err) - } - valRaw := json.RawMessage(b) - return Isolator{ - Name: UnixSysctlName, - ValueRaw: &valRaw, - value: isol, - } -} - -func NewUnixSysctlIsolator(cfg map[string]string) (*UnixSysctl, error) { - s := UnixSysctl(cfg) - if err := s.AssertValid(); err != nil { - return nil, err - } - return &s, nil -} diff --git a/vendor/github.com/appc/spec/schema/types/labels.go b/vendor/github.com/appc/spec/schema/types/labels.go deleted file mode 100644 index 89fa4285d4a..00000000000 --- a/vendor/github.com/appc/spec/schema/types/labels.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "fmt" - "sort" -) - -var ValidOSArch = map[string][]string{ - "linux": {"amd64", "i386", "aarch64", "aarch64_be", "armv6l", "armv7l", "armv7b", "ppc64", "ppc64le", "s390x"}, - "freebsd": {"amd64", "i386", "arm"}, - "darwin": {"x86_64", "i386"}, -} - -type Labels []Label - -type labels Labels - -type Label struct { - Name ACIdentifier `json:"name"` - Value string `json:"value"` -} - -// {appc,go}ArchTuple are internal helper types used to translate arch tuple between go and appc -type appcArchTuple struct { - appcOs string - appcArch string -} -type goArchTuple struct { - goOs string - goArch string - goArchFlavor string -} - -// IsValidOsArch checks if a OS-architecture combination is valid given a map -// of valid OS-architectures -func IsValidOSArch(labels map[ACIdentifier]string, validOSArch map[string][]string) error { - if os, ok := labels["os"]; ok { - if validArchs, ok := validOSArch[os]; !ok { - // Not a whitelisted OS. TODO: how to warn rather than fail? - validOses := make([]string, 0, len(validOSArch)) - for validOs := range validOSArch { - validOses = append(validOses, validOs) - } - sort.Strings(validOses) - return fmt.Errorf(`bad os %#v (must be one of: %v)`, os, validOses) - } else { - // Whitelisted OS. We check arch here, as arch makes sense only - // when os is defined. - if arch, ok := labels["arch"]; ok { - found := false - for _, validArch := range validArchs { - if arch == validArch { - found = true - break - } - } - if !found { - return fmt.Errorf(`bad arch %#v for %v (must be one of: %v)`, arch, os, validArchs) - } - } - } - } - return nil -} - -func (l Labels) assertValid() error { - seen := map[ACIdentifier]string{} - for _, lbl := range l { - if lbl.Name == "name" { - return fmt.Errorf(`invalid label name: "name"`) - } - _, ok := seen[lbl.Name] - if ok { - return fmt.Errorf(`duplicate labels of name %q`, lbl.Name) - } - seen[lbl.Name] = lbl.Value - } - return IsValidOSArch(seen, ValidOSArch) -} - -func (l Labels) MarshalJSON() ([]byte, error) { - if err := l.assertValid(); err != nil { - return nil, err - } - return json.Marshal(labels(l)) -} - -func (l *Labels) UnmarshalJSON(data []byte) error { - var jl labels - if err := json.Unmarshal(data, &jl); err != nil { - return err - } - nl := Labels(jl) - if err := nl.assertValid(); err != nil { - return err - } - *l = nl - return nil -} - -// Get retrieves the value of the label by the given name from Labels, if it exists -func (l Labels) Get(name string) (val string, ok bool) { - for _, lbl := range l { - if lbl.Name.String() == name { - return lbl.Value, true - } - } - return "", false -} - -// ToMap creates a map[ACIdentifier]string. -func (l Labels) ToMap() map[ACIdentifier]string { - labelsMap := make(map[ACIdentifier]string) - for _, lbl := range l { - labelsMap[lbl.Name] = lbl.Value - } - return labelsMap -} - -// LabelsFromMap creates Labels from a map[ACIdentifier]string -func LabelsFromMap(labelsMap map[ACIdentifier]string) (Labels, error) { - labels := Labels{} - for n, v := range labelsMap { - labels = append(labels, Label{Name: n, Value: v}) - } - if err := labels.assertValid(); err != nil { - return nil, err - } - return labels, nil -} - -// ToAppcOSArch translates a Golang arch tuple (OS, architecture, flavor) into -// an appc arch tuple (OS, architecture) -func ToAppcOSArch(goOs string, goArch string, goArchFlavor string) (appcOs string, appcArch string, e error) { - tabularAppcToGo := map[goArchTuple]appcArchTuple{ - {"linux", "amd64", ""}: {"linux", "amd64"}, - {"linux", "386", ""}: {"linux", "i386"}, - {"linux", "arm64", ""}: {"linux", "aarch64"}, - {"linux", "arm", ""}: {"linux", "armv6l"}, - {"linux", "arm", "6"}: {"linux", "armv6l"}, - {"linux", "arm", "7"}: {"linux", "armv7l"}, - {"linux", "ppc64", ""}: {"linux", "ppc64"}, - {"linux", "ppc64le", ""}: {"linux", "ppc64le"}, - {"linux", "s390x", ""}: {"linux", "s390x"}, - - {"freebsd", "amd64", ""}: {"freebsd", "amd64"}, - {"freebsd", "386", ""}: {"freebsd", "i386"}, - {"freebsd", "arm", ""}: {"freebsd", "arm"}, - {"freebsd", "arm", "5"}: {"freebsd", "arm"}, - {"freebsd", "arm", "6"}: {"freebsd", "arm"}, - {"freebsd", "arm", "7"}: {"freebsd", "arm"}, - - {"darwin", "amd64", ""}: {"darwin", "x86_64"}, - {"darwin", "386", ""}: {"darwin", "i386"}, - } - archTuple, ok := tabularAppcToGo[goArchTuple{goOs, goArch, goArchFlavor}] - if !ok { - return "", "", fmt.Errorf("unknown arch tuple: %q - %q - %q", goOs, goArch, goArchFlavor) - } - return archTuple.appcOs, archTuple.appcArch, nil -} - -// ToGoOSArch translates an appc arch tuple (OS, architecture) into -// a Golang arch tuple (OS, architecture, flavor) -func ToGoOSArch(appcOs string, appcArch string) (goOs string, goArch string, goArchFlavor string, e error) { - tabularGoToAppc := map[appcArchTuple]goArchTuple{ - // {"linux", "aarch64_be"}: nil, - // {"linux", "armv7b"}: nil, - {"linux", "aarch64"}: {"linux", "arm64", ""}, - {"linux", "amd64"}: {"linux", "amd64", ""}, - {"linux", "armv6l"}: {"linux", "arm", "6"}, - {"linux", "armv7l"}: {"linux", "arm", "7"}, - {"linux", "i386"}: {"linux", "386", ""}, - {"linux", "ppc64"}: {"linux", "ppc64", ""}, - {"linux", "ppc64le"}: {"linux", "ppc64le", ""}, - {"linux", "s390x"}: {"linux", "s390x", ""}, - - {"freebsd", "amd64"}: {"freebsd", "amd64", ""}, - {"freebsd", "arm"}: {"freebsd", "arm", "6"}, - {"freebsd", "386"}: {"freebsd", "i386", ""}, - - {"darwin", "amd64"}: {"darwin", "x86_64", ""}, - {"darwin", "386"}: {"darwin", "i386", ""}, - } - - archTuple, ok := tabularGoToAppc[appcArchTuple{appcOs, appcArch}] - if !ok { - return "", "", "", fmt.Errorf("unknown arch tuple: %q - %q", appcOs, appcArch) - } - return archTuple.goOs, archTuple.goArch, archTuple.goArchFlavor, nil -} diff --git a/vendor/github.com/appc/spec/schema/types/mountpoint.go b/vendor/github.com/appc/spec/schema/types/mountpoint.go deleted file mode 100644 index 9d4e52b3d0d..00000000000 --- a/vendor/github.com/appc/spec/schema/types/mountpoint.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "errors" - "fmt" - "net/url" - "strconv" - - "github.com/appc/spec/schema/common" -) - -// MountPoint is the application-side manifestation of a Volume. -type MountPoint struct { - Name ACName `json:"name"` - Path string `json:"path"` - ReadOnly bool `json:"readOnly,omitempty"` -} - -func (mount MountPoint) assertValid() error { - if mount.Name.Empty() { - return errors.New("name must be set") - } - if len(mount.Path) == 0 { - return errors.New("path must be set") - } - return nil -} - -// MountPointFromString takes a command line mountpoint parameter and returns a mountpoint -// -// It is useful for actool patch-manifest --mounts -// -// Example mountpoint parameters: -// database,path=/tmp,readOnly=true -func MountPointFromString(mp string) (*MountPoint, error) { - var mount MountPoint - - mp = "name=" + mp - mpQuery, err := common.MakeQueryString(mp) - if err != nil { - return nil, err - } - - v, err := url.ParseQuery(mpQuery) - if err != nil { - return nil, err - } - for key, val := range v { - if len(val) > 1 { - return nil, fmt.Errorf("label %s with multiple values %q", key, val) - } - - switch key { - case "name": - acn, err := NewACName(val[0]) - if err != nil { - return nil, err - } - mount.Name = *acn - case "path": - mount.Path = val[0] - case "readOnly": - ro, err := strconv.ParseBool(val[0]) - if err != nil { - return nil, err - } - mount.ReadOnly = ro - default: - return nil, fmt.Errorf("unknown mountpoint parameter %q", key) - } - } - err = mount.assertValid() - if err != nil { - return nil, err - } - - return &mount, nil -} diff --git a/vendor/github.com/appc/spec/schema/types/port.go b/vendor/github.com/appc/spec/schema/types/port.go deleted file mode 100644 index 2d54515037a..00000000000 --- a/vendor/github.com/appc/spec/schema/types/port.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" - "fmt" - "net" - "net/url" - "strconv" - - "github.com/appc/spec/schema/common" -) - -// Port represents a port as offered by an application *inside* -// the pod. -type Port struct { - Name ACName `json:"name"` - Protocol string `json:"protocol"` - Port uint `json:"port"` - Count uint `json:"count"` - SocketActivated bool `json:"socketActivated"` -} - -// ExposedPort represents a port listening on the host side. -// The PodPort is optional -- if missing, then try and find the pod-side -// information by matching names -type ExposedPort struct { - Name ACName `json:"name"` - HostPort uint `json:"hostPort"` - HostIP net.IP `json:"hostIP,omitempty"` // optional - PodPort *Port `json:"podPort,omitempty"` // optional. If missing, try and find a corresponding App's port -} - -type port Port - -func (p *Port) UnmarshalJSON(data []byte) error { - var pp port - if err := json.Unmarshal(data, &pp); err != nil { - return err - } - np := Port(pp) - if err := np.assertValid(); err != nil { - return err - } - if np.Count == 0 { - np.Count = 1 - } - *p = np - return nil -} - -func (p Port) MarshalJSON() ([]byte, error) { - if err := p.assertValid(); err != nil { - return nil, err - } - return json.Marshal(port(p)) -} - -func (p Port) assertValid() error { - // Although there are no guarantees, most (if not all) - // transport protocols use 16 bit ports - if p.Port > 65535 || p.Port < 1 { - return errors.New("port must be in 1-65535 range") - } - if p.Port+p.Count > 65536 { - return errors.New("end of port range must be in 1-65535 range") - } - return nil -} - -// PortFromString takes a command line port parameter and returns a port -// -// It is useful for actool patch-manifest --ports -// -// Example port parameters: -// health-check,protocol=udp,port=8000 -// query,protocol=tcp,port=8080,count=1,socketActivated=true -func PortFromString(pt string) (*Port, error) { - var port Port - - pt = "name=" + pt - ptQuery, err := common.MakeQueryString(pt) - if err != nil { - return nil, err - } - - v, err := url.ParseQuery(ptQuery) - if err != nil { - return nil, err - } - for key, val := range v { - if len(val) > 1 { - return nil, fmt.Errorf("label %s with multiple values %q", key, val) - } - - switch key { - case "name": - acn, err := NewACName(val[0]) - if err != nil { - return nil, err - } - port.Name = *acn - case "protocol": - port.Protocol = val[0] - case "port": - p, err := strconv.ParseUint(val[0], 10, 16) - if err != nil { - return nil, err - } - port.Port = uint(p) - case "count": - cnt, err := strconv.ParseUint(val[0], 10, 16) - if err != nil { - return nil, err - } - port.Count = uint(cnt) - case "socketActivated": - sa, err := strconv.ParseBool(val[0]) - if err != nil { - return nil, err - } - port.SocketActivated = sa - default: - return nil, fmt.Errorf("unknown port parameter %q", key) - } - } - err = port.assertValid() - if err != nil { - return nil, err - } - - return &port, nil -} diff --git a/vendor/github.com/appc/spec/schema/types/resource/BUILD b/vendor/github.com/appc/spec/schema/types/resource/BUILD deleted file mode 100644 index 44ddf6140be..00000000000 --- a/vendor/github.com/appc/spec/schema/types/resource/BUILD +++ /dev/null @@ -1,32 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "amount.go", - "math.go", - "quantity.go", - "scale_int.go", - "suffix.go", - ], - importpath = "github.com/appc/spec/schema/types/resource", - visibility = ["//visibility:public"], - deps = [ - "//vendor/github.com/spf13/pflag:go_default_library", - "//vendor/gopkg.in/inf.v0:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/appc/spec/schema/types/resource/README.md b/vendor/github.com/appc/spec/schema/types/resource/README.md deleted file mode 100644 index b3c16d25127..00000000000 --- a/vendor/github.com/appc/spec/schema/types/resource/README.md +++ /dev/null @@ -1,4 +0,0 @@ -This package was copied in from the Kubernetes repo to avoid a cyclic -dependency. These files were taken from master from -github.com/kubernetes/kubernetes at commit hash -b0deb2eb8f4037421077f77cb163dbb4c0a2a9f5. diff --git a/vendor/github.com/appc/spec/schema/types/resource/amount.go b/vendor/github.com/appc/spec/schema/types/resource/amount.go deleted file mode 100644 index 6ae823a0229..00000000000 --- a/vendor/github.com/appc/spec/schema/types/resource/amount.go +++ /dev/null @@ -1,298 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors All rights reserved. - -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 resource - -import ( - "math/big" - "strconv" - - inf "gopkg.in/inf.v0" -) - -// Scale is used for getting and setting the base-10 scaled value. -// Base-2 scales are omitted for mathematical simplicity. -// See Quantity.ScaledValue for more details. -type Scale int32 - -// infScale adapts a Scale value to an inf.Scale value. -func (s Scale) infScale() inf.Scale { - return inf.Scale(-s) // inf.Scale is upside-down -} - -const ( - Nano Scale = -9 - Micro Scale = -6 - Milli Scale = -3 - Kilo Scale = 3 - Mega Scale = 6 - Giga Scale = 9 - Tera Scale = 12 - Peta Scale = 15 - Exa Scale = 18 -) - -var ( - Zero = int64Amount{} - - // Used by quantity strings - treat as read only - zeroBytes = []byte("0") -) - -// int64Amount represents a fixed precision numerator and arbitrary scale exponent. It is faster -// than operations on inf.Dec for values that can be represented as int64. -type int64Amount struct { - value int64 - scale Scale -} - -// Sign returns 0 if the value is zero, -1 if it is less than 0, or 1 if it is greater than 0. -func (a int64Amount) Sign() int { - switch { - case a.value == 0: - return 0 - case a.value > 0: - return 1 - default: - return -1 - } -} - -// AsInt64 returns the current amount as an int64 at scale 0, or false if the value cannot be -// represented in an int64 OR would result in a loss of precision. This method is intended as -// an optimization to avoid calling AsDec. -func (a int64Amount) AsInt64() (int64, bool) { - if a.scale == 0 { - return a.value, true - } - if a.scale < 0 { - // TODO: attempt to reduce factors, although it is assumed that factors are reduced prior - // to the int64Amount being created. - return 0, false - } - return positiveScaleInt64(a.value, a.scale) -} - -// AsScaledInt64 returns an int64 representing the value of this amount at the specified scale, -// rounding up, or false if that would result in overflow. (1e20).AsScaledInt64(1) would result -// in overflow because 1e19 is not representable as an int64. Note that setting a scale larger -// than the current value may result in loss of precision - i.e. (1e-6).AsScaledInt64(0) would -// return 1, because 0.000001 is rounded up to 1. -func (a int64Amount) AsScaledInt64(scale Scale) (result int64, ok bool) { - if a.scale < scale { - result, _ = negativeScaleInt64(a.value, scale-a.scale) - return result, true - } - return positiveScaleInt64(a.value, a.scale-scale) -} - -// AsDec returns an inf.Dec representation of this value. -func (a int64Amount) AsDec() *inf.Dec { - var base inf.Dec - base.SetUnscaled(a.value) - base.SetScale(inf.Scale(-a.scale)) - return &base -} - -// Cmp returns 0 if a and b are equal, 1 if a is greater than b, or -1 if a is less than b. -func (a int64Amount) Cmp(b int64Amount) int { - switch { - case a.scale == b.scale: - // compare only the unscaled portion - case a.scale > b.scale: - result, remainder, exact := divideByScaleInt64(b.value, a.scale-b.scale) - if !exact { - return a.AsDec().Cmp(b.AsDec()) - } - if result == a.value { - switch { - case remainder == 0: - return 0 - case remainder > 0: - return -1 - default: - return 1 - } - } - b.value = result - default: - result, remainder, exact := divideByScaleInt64(a.value, b.scale-a.scale) - if !exact { - return a.AsDec().Cmp(b.AsDec()) - } - if result == b.value { - switch { - case remainder == 0: - return 0 - case remainder > 0: - return 1 - default: - return -1 - } - } - a.value = result - } - - switch { - case a.value == b.value: - return 0 - case a.value < b.value: - return -1 - default: - return 1 - } -} - -// Add adds two int64Amounts together, matching scales. It will return false and not mutate -// a if overflow or underflow would result. -func (a *int64Amount) Add(b int64Amount) bool { - switch { - case b.value == 0: - return true - case a.value == 0: - a.value = b.value - a.scale = b.scale - return true - case a.scale == b.scale: - c, ok := int64Add(a.value, b.value) - if !ok { - return false - } - a.value = c - case a.scale > b.scale: - c, ok := positiveScaleInt64(a.value, a.scale-b.scale) - if !ok { - return false - } - c, ok = int64Add(c, b.value) - if !ok { - return false - } - a.scale = b.scale - a.value = c - default: - c, ok := positiveScaleInt64(b.value, b.scale-a.scale) - if !ok { - return false - } - c, ok = int64Add(a.value, c) - if !ok { - return false - } - a.value = c - } - return true -} - -// Sub removes the value of b from the current amount, or returns false if underflow would result. -func (a *int64Amount) Sub(b int64Amount) bool { - return a.Add(int64Amount{value: -b.value, scale: b.scale}) -} - -// AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision -// was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6. -func (a int64Amount) AsScale(scale Scale) (int64Amount, bool) { - if a.scale >= scale { - return a, true - } - result, exact := negativeScaleInt64(a.value, scale-a.scale) - return int64Amount{value: result, scale: scale}, exact -} - -// AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns -// either that buffer or a larger buffer and the current exponent of the value. The value is adjusted -// until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3. -func (a int64Amount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) { - mantissa := a.value - exponent = int32(a.scale) - - amount, times := removeInt64Factors(mantissa, 10) - exponent += int32(times) - - // make sure exponent is a multiple of 3 - var ok bool - switch exponent % 3 { - case 1, -2: - amount, ok = int64MultiplyScale10(amount) - if !ok { - return infDecAmount{a.AsDec()}.AsCanonicalBytes(out) - } - exponent = exponent - 1 - case 2, -1: - amount, ok = int64MultiplyScale100(amount) - if !ok { - return infDecAmount{a.AsDec()}.AsCanonicalBytes(out) - } - exponent = exponent - 2 - } - return strconv.AppendInt(out, amount, 10), exponent -} - -// AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns -// either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would -// return []byte("2048"), 1. -func (a int64Amount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) { - value, ok := a.AsScaledInt64(0) - if !ok { - return infDecAmount{a.AsDec()}.AsCanonicalBase1024Bytes(out) - } - amount, exponent := removeInt64Factors(value, 1024) - return strconv.AppendInt(out, amount, 10), exponent -} - -// infDecAmount implements common operations over an inf.Dec that are specific to the quantity -// representation. -type infDecAmount struct { - *inf.Dec -} - -// AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision -// was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6. -func (a infDecAmount) AsScale(scale Scale) (infDecAmount, bool) { - tmp := &inf.Dec{} - tmp.Round(a.Dec, scale.infScale(), inf.RoundUp) - return infDecAmount{tmp}, tmp.Cmp(a.Dec) == 0 -} - -// AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns -// either that buffer or a larger buffer and the current exponent of the value. The value is adjusted -// until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3. -func (a infDecAmount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) { - mantissa := a.Dec.UnscaledBig() - exponent = int32(-a.Dec.Scale()) - amount := big.NewInt(0).Set(mantissa) - // move all factors of 10 into the exponent for easy reasoning - amount, times := removeBigIntFactors(amount, bigTen) - exponent += times - - // make sure exponent is a multiple of 3 - for exponent%3 != 0 { - amount.Mul(amount, bigTen) - exponent-- - } - - return append(out, amount.String()...), exponent -} - -// AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns -// either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would -// return []byte("2048"), 1. -func (a infDecAmount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) { - tmp := &inf.Dec{} - tmp.Round(a.Dec, 0, inf.RoundUp) - amount, exponent := removeBigIntFactors(tmp.UnscaledBig(), big1024) - return append(out, amount.String()...), exponent -} diff --git a/vendor/github.com/appc/spec/schema/types/resource/math.go b/vendor/github.com/appc/spec/schema/types/resource/math.go deleted file mode 100644 index 163aafa5db6..00000000000 --- a/vendor/github.com/appc/spec/schema/types/resource/math.go +++ /dev/null @@ -1,327 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors All rights reserved. - -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 resource - -import ( - "math/big" - - inf "gopkg.in/inf.v0" -) - -const ( - // maxInt64Factors is the highest value that will be checked when removing factors of 10 from an int64. - // It is also the maximum decimal digits that can be represented with an int64. - maxInt64Factors = 18 -) - -var ( - // Commonly needed big.Int values-- treat as read only! - bigTen = big.NewInt(10) - bigZero = big.NewInt(0) - bigOne = big.NewInt(1) - bigThousand = big.NewInt(1000) - big1024 = big.NewInt(1024) - - // Commonly needed inf.Dec values-- treat as read only! - decZero = inf.NewDec(0, 0) - decOne = inf.NewDec(1, 0) - decMinusOne = inf.NewDec(-1, 0) - decThousand = inf.NewDec(1000, 0) - dec1024 = inf.NewDec(1024, 0) - decMinus1024 = inf.NewDec(-1024, 0) - - // Largest (in magnitude) number allowed. - maxAllowed = infDecAmount{inf.NewDec((1<<63)-1, 0)} // == max int64 - - // The maximum value we can represent milli-units for. - // Compare with the return value of Quantity.Value() to - // see if it's safe to use Quantity.MilliValue(). - MaxMilliValue = int64(((1 << 63) - 1) / 1000) -) - -const mostNegative = -(mostPositive + 1) -const mostPositive = 1<<63 - 1 - -// int64Add returns a+b, or false if that would overflow int64. -func int64Add(a, b int64) (int64, bool) { - c := a + b - switch { - case a > 0 && b > 0: - if c < 0 { - return 0, false - } - case a < 0 && b < 0: - if c > 0 { - return 0, false - } - if a == mostNegative && b == mostNegative { - return 0, false - } - } - return c, true -} - -// int64Multiply returns a*b, or false if that would overflow or underflow int64. -func int64Multiply(a, b int64) (int64, bool) { - if a == 0 || b == 0 || a == 1 || b == 1 { - return a * b, true - } - if a == mostNegative || b == mostNegative { - return 0, false - } - c := a * b - return c, c/b == a -} - -// int64MultiplyScale returns a*b, assuming b is greater than one, or false if that would overflow or underflow int64. -// Use when b is known to be greater than one. -func int64MultiplyScale(a int64, b int64) (int64, bool) { - if a == 0 || a == 1 { - return a * b, true - } - if a == mostNegative && b != 1 { - return 0, false - } - c := a * b - return c, c/b == a -} - -// int64MultiplyScale10 multiplies a by 10, or returns false if that would overflow. This method is faster than -// int64Multiply(a, 10) because the compiler can optimize constant factor multiplication. -func int64MultiplyScale10(a int64) (int64, bool) { - if a == 0 || a == 1 { - return a * 10, true - } - if a == mostNegative { - return 0, false - } - c := a * 10 - return c, c/10 == a -} - -// int64MultiplyScale100 multiplies a by 100, or returns false if that would overflow. This method is faster than -// int64Multiply(a, 100) because the compiler can optimize constant factor multiplication. -func int64MultiplyScale100(a int64) (int64, bool) { - if a == 0 || a == 1 { - return a * 100, true - } - if a == mostNegative { - return 0, false - } - c := a * 100 - return c, c/100 == a -} - -// int64MultiplyScale1000 multiplies a by 1000, or returns false if that would overflow. This method is faster than -// int64Multiply(a, 1000) because the compiler can optimize constant factor multiplication. -func int64MultiplyScale1000(a int64) (int64, bool) { - if a == 0 || a == 1 { - return a * 1000, true - } - if a == mostNegative { - return 0, false - } - c := a * 1000 - return c, c/1000 == a -} - -// positiveScaleInt64 multiplies base by 10^scale, returning false if the -// value overflows. Passing a negative scale is undefined. -func positiveScaleInt64(base int64, scale Scale) (int64, bool) { - switch scale { - case 0: - return base, true - case 1: - return int64MultiplyScale10(base) - case 2: - return int64MultiplyScale100(base) - case 3: - return int64MultiplyScale1000(base) - case 6: - return int64MultiplyScale(base, 1000000) - case 9: - return int64MultiplyScale(base, 1000000000) - default: - value := base - var ok bool - for i := Scale(0); i < scale; i++ { - if value, ok = int64MultiplyScale(value, 10); !ok { - return 0, false - } - } - return value, true - } -} - -// negativeScaleInt64 reduces base by the provided scale, rounding up, until the -// value is zero or the scale is reached. Passing a negative scale is undefined. -// The value returned, if not exact, is rounded away from zero. -func negativeScaleInt64(base int64, scale Scale) (result int64, exact bool) { - if scale == 0 { - return base, true - } - - value := base - var fraction bool - for i := Scale(0); i < scale; i++ { - if !fraction && value%10 != 0 { - fraction = true - } - value = value / 10 - if value == 0 { - if fraction { - if base > 0 { - return 1, false - } - return -1, false - } - return 0, true - } - } - if fraction { - if base > 0 { - value += 1 - } else { - value += -1 - } - } - return value, !fraction -} - -func pow10Int64(b int64) int64 { - switch b { - case 0: - return 1 - case 1: - return 10 - case 2: - return 100 - case 3: - return 1000 - case 4: - return 10000 - case 5: - return 100000 - case 6: - return 1000000 - case 7: - return 10000000 - case 8: - return 100000000 - case 9: - return 1000000000 - case 10: - return 10000000000 - case 11: - return 100000000000 - case 12: - return 1000000000000 - case 13: - return 10000000000000 - case 14: - return 100000000000000 - case 15: - return 1000000000000000 - case 16: - return 10000000000000000 - case 17: - return 100000000000000000 - case 18: - return 1000000000000000000 - default: - return 0 - } -} - -// powInt64 raises a to the bth power. Is not overflow aware. -func powInt64(a, b int64) int64 { - p := int64(1) - for b > 0 { - if b&1 != 0 { - p *= a - } - b >>= 1 - a *= a - } - return p -} - -// negativeScaleInt64 returns the result of dividing base by scale * 10 and the remainder, or -// false if no such division is possible. Dividing by negative scales is undefined. -func divideByScaleInt64(base int64, scale Scale) (result, remainder int64, exact bool) { - if scale == 0 { - return base, 0, true - } - // the max scale representable in base 10 in an int64 is 18 decimal places - if scale >= 18 { - return 0, base, false - } - divisor := pow10Int64(int64(scale)) - return base / divisor, base % divisor, true -} - -// removeInt64Factors divides in a loop; the return values have the property that -// value == result * base ^ scale -func removeInt64Factors(value int64, base int64) (result int64, times int32) { - times = 0 - result = value - negative := result < 0 - if negative { - result = -result - } - switch base { - // allow the compiler to optimize the common cases - case 10: - for result >= 10 && result%10 == 0 { - times++ - result = result / 10 - } - // allow the compiler to optimize the common cases - case 1024: - for result >= 1024 && result%1024 == 0 { - times++ - result = result / 1024 - } - default: - for result >= base && result%base == 0 { - times++ - result = result / base - } - } - if negative { - result = -result - } - return result, times -} - -// removeBigIntFactors divides in a loop; the return values have the property that -// d == result * factor ^ times -// d may be modified in place. -// If d == 0, then the return values will be (0, 0) -func removeBigIntFactors(d, factor *big.Int) (result *big.Int, times int32) { - q := big.NewInt(0) - m := big.NewInt(0) - for d.Cmp(bigZero) != 0 { - q.DivMod(d, factor, m) - if m.Cmp(bigZero) != 0 { - break - } - times++ - d, q = q, d - } - return d, times -} diff --git a/vendor/github.com/appc/spec/schema/types/resource/quantity.go b/vendor/github.com/appc/spec/schema/types/resource/quantity.go deleted file mode 100644 index 96877b4c946..00000000000 --- a/vendor/github.com/appc/spec/schema/types/resource/quantity.go +++ /dev/null @@ -1,768 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors All rights reserved. - -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 resource - -import ( - "bytes" - "errors" - "fmt" - "math/big" - "regexp" - "strconv" - "strings" - - flag "github.com/spf13/pflag" - - inf "gopkg.in/inf.v0" -) - -// Quantity is a fixed-point representation of a number. -// It provides convenient marshaling/unmarshaling in JSON and YAML, -// in addition to String() and Int64() accessors. -// -// The serialization format is: -// -// ::= -// (Note that may be empty, from the "" case in .) -// ::= 0 | 1 | ... | 9 -// ::= | -// ::= | . | . | . -// ::= "+" | "-" -// ::= | -// ::= | | -// ::= Ki | Mi | Gi | Ti | Pi | Ei -// (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) -// ::= m | "" | k | M | G | T | P | E -// (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) -// ::= "e" | "E" -// -// No matter which of the three exponent forms is used, no quantity may represent -// a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal -// places. Numbers larger or more precise will be capped or rounded up. -// (E.g.: 0.1m will rounded up to 1m.) -// This may be extended in the future if we require larger or smaller quantities. -// -// When a Quantity is parsed from a string, it will remember the type of suffix -// it had, and will use the same type again when it is serialized. -// -// Before serializing, Quantity will be put in "canonical form". -// This means that Exponent/suffix will be adjusted up or down (with a -// corresponding increase or decrease in Mantissa) such that: -// a. No precision is lost -// b. No fractional digits will be emitted -// c. The exponent (or suffix) is as large as possible. -// The sign will be omitted unless the number is negative. -// -// Examples: -// 1.5 will be serialized as "1500m" -// 1.5Gi will be serialized as "1536Mi" -// -// NOTE: We reserve the right to amend this canonical format, perhaps to -// allow 1.5 to be canonical. -// TODO: Remove above disclaimer after all bikeshedding about format is over, -// or after March 2015. -// -// Note that the quantity will NEVER be internally represented by a -// floating point number. That is the whole point of this exercise. -// -// Non-canonical values will still parse as long as they are well formed, -// but will be re-emitted in their canonical form. (So always use canonical -// form, or don't diff.) -// -// This format is intended to make it difficult to use these numbers without -// writing some sort of special handling code in the hopes that that will -// cause implementors to also use a fixed point implementation. -// -// +gencopy=false -// +protobuf=true -// +protobuf.embed=string -// +protobuf.options.marshal=false -// +protobuf.options.(gogoproto.goproto_stringer)=false -type Quantity struct { - // i is the quantity in int64 scaled form, if d.Dec == nil - i int64Amount - // d is the quantity in inf.Dec form if d.Dec != nil - d infDecAmount - // s is the generated value of this quantity to avoid recalculation - s string - - // Change Format at will. See the comment for Canonicalize for - // more details. - Format -} - -// CanonicalValue allows a quantity amount to be converted to a string. -type CanonicalValue interface { - // AsCanonicalBytes returns a byte array representing the string representation - // of the value mantissa and an int32 representing its exponent in base-10. Callers may - // pass a byte slice to the method to avoid allocations. - AsCanonicalBytes(out []byte) ([]byte, int32) - // AsCanonicalBase1024Bytes returns a byte array representing the string representation - // of the value mantissa and an int32 representing its exponent in base-1024. Callers - // may pass a byte slice to the method to avoid allocations. - AsCanonicalBase1024Bytes(out []byte) ([]byte, int32) -} - -// Format lists the three possible formattings of a quantity. -type Format string - -const ( - DecimalExponent = Format("DecimalExponent") // e.g., 12e6 - BinarySI = Format("BinarySI") // e.g., 12Mi (12 * 2^20) - DecimalSI = Format("DecimalSI") // e.g., 12M (12 * 10^6) -) - -// MustParse turns the given string into a quantity or panics; for tests -// or others cases where you know the string is valid. -func MustParse(str string) Quantity { - q, err := ParseQuantity(str) - if err != nil { - panic(fmt.Errorf("cannot parse '%v': %v", str, err)) - } - return q -} - -const ( - // splitREString is used to separate a number from its suffix; as such, - // this is overly permissive, but that's OK-- it will be checked later. - splitREString = "^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" -) - -var ( - // splitRE is used to get the various parts of a number. - splitRE = regexp.MustCompile(splitREString) - - // Errors that could happen while parsing a string. - ErrFormatWrong = errors.New("quantities must match the regular expression '" + splitREString + "'") - ErrNumeric = errors.New("unable to parse numeric part of quantity") - ErrSuffix = errors.New("unable to parse quantity's suffix") -) - -// parseQuantityString is a fast scanner for quantity values. -func parseQuantityString(str string) (positive bool, value, num, denom, suffix string, err error) { - positive = true - pos := 0 - end := len(str) - - // handle leading sign - if pos < end { - switch str[0] { - case '-': - positive = false - pos++ - case '+': - pos++ - } - } - - // strip leading zeros -Zeroes: - for i := pos; ; i++ { - if i >= end { - num = "0" - value = num - return - } - switch str[i] { - case '0': - pos++ - default: - break Zeroes - } - } - - // extract the numerator -Num: - for i := pos; ; i++ { - if i >= end { - num = str[pos:end] - value = str[0:end] - return - } - switch str[i] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - num = str[pos:i] - pos = i - break Num - } - } - - // if we stripped all numerator positions, always return 0 - if len(num) == 0 { - num = "0" - } - - // handle a denominator - if pos < end && str[pos] == '.' { - pos++ - Denom: - for i := pos; ; i++ { - if i >= end { - denom = str[pos:end] - value = str[0:end] - return - } - switch str[i] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - denom = str[pos:i] - pos = i - break Denom - } - } - // TODO: we currently allow 1.G, but we may not want to in the future. - // if len(denom) == 0 { - // err = ErrFormatWrong - // return - // } - } - value = str[0:pos] - - // grab the elements of the suffix - suffixStart := pos - for i := pos; ; i++ { - if i >= end { - suffix = str[suffixStart:end] - return - } - if !strings.ContainsAny(str[i:i+1], "eEinumkKMGTP") { - pos = i - break - } - } - if pos < end { - switch str[pos] { - case '-', '+': - pos++ - } - } -Suffix: - for i := pos; ; i++ { - if i >= end { - suffix = str[suffixStart:end] - return - } - switch str[i] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - break Suffix - } - } - // we encountered a non decimal in the Suffix loop, but the last character - // was not a valid exponent - err = ErrFormatWrong - return -} - -// ParseQuantity turns str into a Quantity, or returns an error. -func ParseQuantity(str string) (Quantity, error) { - if len(str) == 0 { - return Quantity{}, ErrFormatWrong - } - if str == "0" { - return Quantity{Format: DecimalSI, s: str}, nil - } - - positive, value, num, denom, suf, err := parseQuantityString(str) - if err != nil { - return Quantity{}, err - } - - base, exponent, format, ok := quantitySuffixer.interpret(suffix(suf)) - if !ok { - return Quantity{}, ErrSuffix - } - - precision := int32(0) - scale := int32(0) - mantissa := int64(1) - switch format { - case DecimalExponent, DecimalSI: - scale = exponent - precision = maxInt64Factors - int32(len(num)+len(denom)) - case BinarySI: - scale = 0 - switch { - case exponent >= 0 && len(denom) == 0: - // only handle positive binary numbers with the fast path - mantissa = int64(int64(mantissa) << uint64(exponent)) - // 1Mi (2^20) has ~6 digits of decimal precision, so exponent*3/10 -1 is roughly the precision - precision = 15 - int32(len(num)) - int32(float32(exponent)*3/10) - 1 - default: - precision = -1 - } - } - - if precision >= 0 { - // if we have a denominator, shift the entire value to the left by the number of places in the - // denominator - scale -= int32(len(denom)) - if scale >= int32(Nano) { - shifted := num + denom - - var value int64 - value, err := strconv.ParseInt(shifted, 10, 64) - if err != nil { - return Quantity{}, ErrNumeric - } - if result, ok := int64Multiply(value, int64(mantissa)); ok { - if !positive { - result = -result - } - // if the number is in canonical form, reuse the string - switch format { - case BinarySI: - if exponent%10 == 0 && (value&0x07 != 0) { - return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil - } - default: - if scale%3 == 0 && !strings.HasSuffix(shifted, "000") && shifted[0] != '0' { - return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil - } - } - return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format}, nil - } - } - } - - amount := new(inf.Dec) - if _, ok := amount.SetString(value); !ok { - return Quantity{}, ErrNumeric - } - - // So that no one but us has to think about suffixes, remove it. - if base == 10 { - amount.SetScale(amount.Scale() + Scale(exponent).infScale()) - } else if base == 2 { - // numericSuffix = 2 ** exponent - numericSuffix := big.NewInt(1).Lsh(bigOne, uint(exponent)) - ub := amount.UnscaledBig() - amount.SetUnscaledBig(ub.Mul(ub, numericSuffix)) - } - - // Cap at min/max bounds. - sign := amount.Sign() - if sign == -1 { - amount.Neg(amount) - } - - // This rounds non-zero values up to the minimum representable value, under the theory that - // if you want some resources, you should get some resources, even if you asked for way too small - // of an amount. Arguably, this should be inf.RoundHalfUp (normal rounding), but that would have - // the side effect of rounding values < .5n to zero. - if v, ok := amount.Unscaled(); v != int64(0) || !ok { - amount.Round(amount, Nano.infScale(), inf.RoundUp) - } - - // The max is just a simple cap. - // TODO: this prevents accumulating quantities greater than int64, for instance quota across a cluster - if format == BinarySI && amount.Cmp(maxAllowed.Dec) > 0 { - amount.Set(maxAllowed.Dec) - } - - if format == BinarySI && amount.Cmp(decOne) < 0 && amount.Cmp(decZero) > 0 { - // This avoids rounding and hopefully confusion, too. - format = DecimalSI - } - if sign == -1 { - amount.Neg(amount) - } - - return Quantity{d: infDecAmount{amount}, Format: format}, nil -} - -// CanonicalizeBytes returns the canonical form of q and its suffix (see comment on Quantity). -// -// Note about BinarySI: -// * If q.Format is set to BinarySI and q.Amount represents a non-zero value between -// -1 and +1, it will be emitted as if q.Format were DecimalSI. -// * Otherwise, if q.Format is set to BinarySI, frational parts of q.Amount will be -// rounded up. (1.1i becomes 2i.) -func (q *Quantity) CanonicalizeBytes(out []byte) (result, suffix []byte) { - if q.IsZero() { - return zeroBytes, nil - } - - var rounded CanonicalValue - format := q.Format - switch format { - case DecimalExponent, DecimalSI: - case BinarySI: - if q.CmpInt64(-1024) > 0 && q.CmpInt64(1024) < 0 { - // This avoids rounding and hopefully confusion, too. - format = DecimalSI - } else { - var exact bool - if rounded, exact = q.AsScale(0); !exact { - // Don't lose precision-- show as DecimalSI - format = DecimalSI - } - } - default: - format = DecimalExponent - } - - // TODO: If BinarySI formatting is requested but would cause rounding, upgrade to - // one of the other formats. - switch format { - case DecimalExponent, DecimalSI: - number, exponent := q.AsCanonicalBytes(out) - suffix, _ := quantitySuffixer.constructBytes(10, exponent, format) - return number, suffix - default: - // format must be BinarySI - number, exponent := rounded.AsCanonicalBase1024Bytes(out) - suffix, _ := quantitySuffixer.constructBytes(2, exponent*10, format) - return number, suffix - } -} - -// AsInt64 returns a representation of the current value as an int64 if a fast conversion -// is possible. If false is returned, callers must use the inf.Dec form of this quantity. -func (q *Quantity) AsInt64() (int64, bool) { - if q.d.Dec != nil { - return 0, false - } - return q.i.AsInt64() -} - -// ToDec promotes the quantity in place to use an inf.Dec representation and returns itself. -func (q *Quantity) ToDec() *Quantity { - if q.d.Dec == nil { - q.d.Dec = q.i.AsDec() - q.i = int64Amount{} - } - return q -} - -// AsDec returns the quantity as represented by a scaled inf.Dec. -func (q *Quantity) AsDec() *inf.Dec { - if q.d.Dec != nil { - return q.d.Dec - } - q.d.Dec = q.i.AsDec() - q.i = int64Amount{} - return q.d.Dec -} - -// AsCanonicalBytes returns the canonical byte representation of this quantity as a mantissa -// and base 10 exponent. The out byte slice may be passed to the method to avoid an extra -// allocation. -func (q *Quantity) AsCanonicalBytes(out []byte) (result []byte, exponent int32) { - if q.d.Dec != nil { - return q.d.AsCanonicalBytes(out) - } - return q.i.AsCanonicalBytes(out) -} - -// IsZero returns true if the quantity is equal to zero. -func (q *Quantity) IsZero() bool { - if q.d.Dec != nil { - return q.d.Dec.Sign() == 0 - } - return q.i.value == 0 -} - -// Sign returns 0 if the quantity is zero, -1 if the quantity is less than zero, or 1 if the -// quantity is greater than zero. -func (q *Quantity) Sign() int { - if q.d.Dec != nil { - return q.d.Dec.Sign() - } - return q.i.Sign() -} - -// AsScaled returns the current value, rounded up to the provided scale, and returns -// false if the scale resulted in a loss of precision. -func (q *Quantity) AsScale(scale Scale) (CanonicalValue, bool) { - if q.d.Dec != nil { - return q.d.AsScale(scale) - } - return q.i.AsScale(scale) -} - -// RoundUp updates the quantity to the provided scale, ensuring that the value is at -// least 1. False is returned if the rounding operation resulted in a loss of precision. -// Negative numbers are rounded away from zero (-9 scale 1 rounds to -10). -func (q *Quantity) RoundUp(scale Scale) bool { - if q.d.Dec != nil { - q.s = "" - d, exact := q.d.AsScale(scale) - q.d = d - return exact - } - // avoid clearing the string value if we have already calculated it - if q.i.scale >= scale { - return true - } - q.s = "" - i, exact := q.i.AsScale(scale) - q.i = i - return exact -} - -// Add adds the provide y quantity to the current value. If the current value is zero, -// the format of the quantity will be updated to the format of y. -func (q *Quantity) Add(y Quantity) { - q.s = "" - if q.d.Dec == nil && y.d.Dec == nil { - if q.i.value == 0 { - q.Format = y.Format - } - if q.i.Add(y.i) { - return - } - } else if q.IsZero() { - q.Format = y.Format - } - q.ToDec().d.Dec.Add(q.d.Dec, y.AsDec()) -} - -// Sub subtracts the provided quantity from the current value in place. If the current -// value is zero, the format of the quantity will be updated to the format of y. -func (q *Quantity) Sub(y Quantity) { - q.s = "" - if q.IsZero() { - q.Format = y.Format - } - if q.d.Dec == nil && y.d.Dec == nil && q.i.Sub(y.i) { - return - } - q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec()) -} - -// Cmp returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the -// quantity is greater than y. -func (q *Quantity) Cmp(y Quantity) int { - if q.d.Dec == nil && y.d.Dec == nil { - return q.i.Cmp(y.i) - } - return q.AsDec().Cmp(y.AsDec()) -} - -// CmpInt64 returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the -// quantity is greater than y. -func (q *Quantity) CmpInt64(y int64) int { - if q.d.Dec != nil { - return q.d.Dec.Cmp(inf.NewDec(y, inf.Scale(0))) - } - return q.i.Cmp(int64Amount{value: y}) -} - -// Neg sets quantity to be the negative value of itself. -func (q *Quantity) Neg() { - q.s = "" - if q.d.Dec == nil { - q.i.value = -q.i.value - return - } - q.d.Dec.Neg(q.d.Dec) -} - -// int64QuantityExpectedBytes is the expected width in bytes of the canonical string representation -// of most Quantity values. -const int64QuantityExpectedBytes = 18 - -// String formats the Quantity as a string, caching the result if not calculated. -// String is an expensive operation and caching this result significantly reduces the cost of -// normal parse / marshal operations on Quantity. -func (q *Quantity) String() string { - if len(q.s) == 0 { - result := make([]byte, 0, int64QuantityExpectedBytes) - number, suffix := q.CanonicalizeBytes(result) - number = append(number, suffix...) - q.s = string(number) - } - return q.s -} - -// MarshalJSON implements the json.Marshaller interface. -func (q Quantity) MarshalJSON() ([]byte, error) { - if len(q.s) > 0 { - out := make([]byte, len(q.s)+2) - out[0], out[len(out)-1] = '"', '"' - copy(out[1:], q.s) - return out, nil - } - result := make([]byte, int64QuantityExpectedBytes, int64QuantityExpectedBytes) - result[0] = '"' - number, suffix := q.CanonicalizeBytes(result[1:1]) - // if the same slice was returned to us that we passed in, avoid another allocation by copying number into - // the source slice and returning that - if len(number) > 0 && &number[0] == &result[1] && (len(number)+len(suffix)+2) <= int64QuantityExpectedBytes { - number = append(number, suffix...) - number = append(number, '"') - return result[:1+len(number)], nil - } - // if CanonicalizeBytes needed more space than our slice provided, we may need to allocate again so use - // append - result = result[:1] - result = append(result, number...) - result = append(result, suffix...) - result = append(result, '"') - return result, nil -} - -// UnmarshalJSON implements the json.Unmarshaller interface. -// TODO: Remove support for leading/trailing whitespace -func (q *Quantity) UnmarshalJSON(value []byte) error { - l := len(value) - if l == 4 && bytes.Equal(value, []byte("null")) { - q.d.Dec = nil - q.i = int64Amount{} - return nil - } - if l >= 2 && value[0] == '"' && value[l-1] == '"' { - value = value[1 : l-1] - } - - parsed, err := ParseQuantity(strings.TrimSpace(string(value))) - if err != nil { - return err - } - - // This copy is safe because parsed will not be referred to again. - *q = parsed - return nil -} - -// NewQuantity returns a new Quantity representing the given -// value in the given format. -func NewQuantity(value int64, format Format) *Quantity { - return &Quantity{ - i: int64Amount{value: value}, - Format: format, - } -} - -// NewMilliQuantity returns a new Quantity representing the given -// value * 1/1000 in the given format. Note that BinarySI formatting -// will round fractional values, and will be changed to DecimalSI for -// values x where (-1 < x < 1) && (x != 0). -func NewMilliQuantity(value int64, format Format) *Quantity { - return &Quantity{ - i: int64Amount{value: value, scale: -3}, - Format: format, - } -} - -// NewScaledQuantity returns a new Quantity representing the given -// value * 10^scale in DecimalSI format. -func NewScaledQuantity(value int64, scale Scale) *Quantity { - return &Quantity{ - i: int64Amount{value: value, scale: scale}, - Format: DecimalSI, - } -} - -// Value returns the value of q; any fractional part will be lost. -func (q *Quantity) Value() int64 { - return q.ScaledValue(0) -} - -// MilliValue returns the value of ceil(q * 1000); this could overflow an int64; -// if that's a concern, call Value() first to verify the number is small enough. -func (q *Quantity) MilliValue() int64 { - return q.ScaledValue(Milli) -} - -// ScaledValue returns the value of ceil(q * 10^scale); this could overflow an int64. -// To detect overflow, call Value() first and verify the expected magnitude. -func (q *Quantity) ScaledValue(scale Scale) int64 { - if q.d.Dec == nil { - i, _ := q.i.AsScaledInt64(scale) - return i - } - dec := q.d.Dec - return scaledValue(dec.UnscaledBig(), int(dec.Scale()), int(scale.infScale())) -} - -// Set sets q's value to be value. -func (q *Quantity) Set(value int64) { - q.SetScaled(value, 0) -} - -// SetMilli sets q's value to be value * 1/1000. -func (q *Quantity) SetMilli(value int64) { - q.SetScaled(value, Milli) -} - -// SetScaled sets q's value to be value * 10^scale -func (q *Quantity) SetScaled(value int64, scale Scale) { - q.s = "" - q.d.Dec = nil - q.i = int64Amount{value: value, scale: scale} -} - -// Copy is a convenience function that makes a deep copy for you. Non-deep -// copies of quantities share pointers and you will regret that. -func (q *Quantity) Copy() *Quantity { - if q.d.Dec == nil { - return &Quantity{ - s: q.s, - i: q.i, - Format: q.Format, - } - } - tmp := &inf.Dec{} - return &Quantity{ - s: q.s, - d: infDecAmount{tmp.Set(q.d.Dec)}, - Format: q.Format, - } -} - -// qFlag is a helper type for the Flag function -type qFlag struct { - dest *Quantity -} - -// Sets the value of the internal Quantity. (used by flag & pflag) -func (qf qFlag) Set(val string) error { - q, err := ParseQuantity(val) - if err != nil { - return err - } - // This copy is OK because q will not be referenced again. - *qf.dest = q - return nil -} - -// Converts the value of the internal Quantity to a string. (used by flag & pflag) -func (qf qFlag) String() string { - return qf.dest.String() -} - -// States the type of flag this is (Quantity). (used by pflag) -func (qf qFlag) Type() string { - return "quantity" -} - -// QuantityFlag is a helper that makes a quantity flag (using standard flag package). -// Will panic if defaultValue is not a valid quantity. -func QuantityFlag(flagName, defaultValue, description string) *Quantity { - q := MustParse(defaultValue) - flag.Var(NewQuantityFlagValue(&q), flagName, description) - return &q -} - -// NewQuantityFlagValue returns an object that can be used to back a flag, -// pointing at the given Quantity variable. -func NewQuantityFlagValue(q *Quantity) flag.Value { - return qFlag{q} -} diff --git a/vendor/github.com/appc/spec/schema/types/resource/scale_int.go b/vendor/github.com/appc/spec/schema/types/resource/scale_int.go deleted file mode 100644 index 173de1a2171..00000000000 --- a/vendor/github.com/appc/spec/schema/types/resource/scale_int.go +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors All rights reserved. - -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 resource - -import ( - "math" - "math/big" - "sync" -) - -var ( - // A sync pool to reduce allocation. - intPool sync.Pool - maxInt64 = big.NewInt(math.MaxInt64) -) - -func init() { - intPool.New = func() interface{} { - return &big.Int{} - } -} - -// scaledValue scales given unscaled value from scale to new Scale and returns -// an int64. It ALWAYS rounds up the result when scale down. The final result might -// overflow. -// -// scale, newScale represents the scale of the unscaled decimal. -// The mathematical value of the decimal is unscaled * 10**(-scale). -func scaledValue(unscaled *big.Int, scale, newScale int) int64 { - dif := scale - newScale - if dif == 0 { - return unscaled.Int64() - } - - // Handle scale up - // This is an easy case, we do not need to care about rounding and overflow. - // If any intermediate operation causes overflow, the result will overflow. - if dif < 0 { - return unscaled.Int64() * int64(math.Pow10(-dif)) - } - - // Handle scale down - // We have to be careful about the intermediate operations. - - // fast path when unscaled < max.Int64 and exp(10,dif) < max.Int64 - const log10MaxInt64 = 19 - if unscaled.Cmp(maxInt64) < 0 && dif < log10MaxInt64 { - divide := int64(math.Pow10(dif)) - result := unscaled.Int64() / divide - mod := unscaled.Int64() % divide - if mod != 0 { - return result + 1 - } - return result - } - - // We should only convert back to int64 when getting the result. - divisor := intPool.Get().(*big.Int) - exp := intPool.Get().(*big.Int) - result := intPool.Get().(*big.Int) - defer func() { - intPool.Put(divisor) - intPool.Put(exp) - intPool.Put(result) - }() - - // divisor = 10^(dif) - // TODO: create loop up table if exp costs too much. - divisor.Exp(bigTen, exp.SetInt64(int64(dif)), nil) - // reuse exp - remainder := exp - - // result = unscaled / divisor - // remainder = unscaled % divisor - result.DivMod(unscaled, divisor, remainder) - if remainder.Sign() != 0 { - return result.Int64() + 1 - } - - return result.Int64() -} diff --git a/vendor/github.com/appc/spec/schema/types/resource/suffix.go b/vendor/github.com/appc/spec/schema/types/resource/suffix.go deleted file mode 100644 index 0aa2ce2bf60..00000000000 --- a/vendor/github.com/appc/spec/schema/types/resource/suffix.go +++ /dev/null @@ -1,198 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors All rights reserved. - -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 resource - -import ( - "strconv" -) - -type suffix string - -// suffixer can interpret and construct suffixes. -type suffixer interface { - interpret(suffix) (base, exponent int32, fmt Format, ok bool) - construct(base, exponent int32, fmt Format) (s suffix, ok bool) - constructBytes(base, exponent int32, fmt Format) (s []byte, ok bool) -} - -// quantitySuffixer handles suffixes for all three formats that quantity -// can handle. -var quantitySuffixer = newSuffixer() - -type bePair struct { - base, exponent int32 -} - -type listSuffixer struct { - suffixToBE map[suffix]bePair - beToSuffix map[bePair]suffix - beToSuffixBytes map[bePair][]byte -} - -func (ls *listSuffixer) addSuffix(s suffix, pair bePair) { - if ls.suffixToBE == nil { - ls.suffixToBE = map[suffix]bePair{} - } - if ls.beToSuffix == nil { - ls.beToSuffix = map[bePair]suffix{} - } - if ls.beToSuffixBytes == nil { - ls.beToSuffixBytes = map[bePair][]byte{} - } - ls.suffixToBE[s] = pair - ls.beToSuffix[pair] = s - ls.beToSuffixBytes[pair] = []byte(s) -} - -func (ls *listSuffixer) lookup(s suffix) (base, exponent int32, ok bool) { - pair, ok := ls.suffixToBE[s] - if !ok { - return 0, 0, false - } - return pair.base, pair.exponent, true -} - -func (ls *listSuffixer) construct(base, exponent int32) (s suffix, ok bool) { - s, ok = ls.beToSuffix[bePair{base, exponent}] - return -} - -func (ls *listSuffixer) constructBytes(base, exponent int32) (s []byte, ok bool) { - s, ok = ls.beToSuffixBytes[bePair{base, exponent}] - return -} - -type suffixHandler struct { - decSuffixes listSuffixer - binSuffixes listSuffixer -} - -type fastLookup struct { - *suffixHandler -} - -func (l fastLookup) interpret(s suffix) (base, exponent int32, format Format, ok bool) { - switch s { - case "": - return 10, 0, DecimalSI, true - case "n": - return 10, -9, DecimalSI, true - case "u": - return 10, -6, DecimalSI, true - case "m": - return 10, -3, DecimalSI, true - case "k": - return 10, 3, DecimalSI, true - case "M": - return 10, 6, DecimalSI, true - case "G": - return 10, 9, DecimalSI, true - } - return l.suffixHandler.interpret(s) -} - -func newSuffixer() suffixer { - sh := &suffixHandler{} - - // IMPORTANT: if you change this section you must change fastLookup - - sh.binSuffixes.addSuffix("Ki", bePair{2, 10}) - sh.binSuffixes.addSuffix("Mi", bePair{2, 20}) - sh.binSuffixes.addSuffix("Gi", bePair{2, 30}) - sh.binSuffixes.addSuffix("Ti", bePair{2, 40}) - sh.binSuffixes.addSuffix("Pi", bePair{2, 50}) - sh.binSuffixes.addSuffix("Ei", bePair{2, 60}) - // Don't emit an error when trying to produce - // a suffix for 2^0. - sh.decSuffixes.addSuffix("", bePair{2, 0}) - - sh.decSuffixes.addSuffix("n", bePair{10, -9}) - sh.decSuffixes.addSuffix("u", bePair{10, -6}) - sh.decSuffixes.addSuffix("m", bePair{10, -3}) - sh.decSuffixes.addSuffix("", bePair{10, 0}) - sh.decSuffixes.addSuffix("k", bePair{10, 3}) - sh.decSuffixes.addSuffix("M", bePair{10, 6}) - sh.decSuffixes.addSuffix("G", bePair{10, 9}) - sh.decSuffixes.addSuffix("T", bePair{10, 12}) - sh.decSuffixes.addSuffix("P", bePair{10, 15}) - sh.decSuffixes.addSuffix("E", bePair{10, 18}) - - return fastLookup{sh} -} - -func (sh *suffixHandler) construct(base, exponent int32, fmt Format) (s suffix, ok bool) { - switch fmt { - case DecimalSI: - return sh.decSuffixes.construct(base, exponent) - case BinarySI: - return sh.binSuffixes.construct(base, exponent) - case DecimalExponent: - if base != 10 { - return "", false - } - if exponent == 0 { - return "", true - } - return suffix("e" + strconv.FormatInt(int64(exponent), 10)), true - } - return "", false -} - -func (sh *suffixHandler) constructBytes(base, exponent int32, format Format) (s []byte, ok bool) { - switch format { - case DecimalSI: - return sh.decSuffixes.constructBytes(base, exponent) - case BinarySI: - return sh.binSuffixes.constructBytes(base, exponent) - case DecimalExponent: - if base != 10 { - return nil, false - } - if exponent == 0 { - return nil, true - } - result := make([]byte, 8, 8) - result[0] = 'e' - number := strconv.AppendInt(result[1:1], int64(exponent), 10) - if &result[1] == &number[0] { - return result[:1+len(number)], true - } - result = append(result[:1], number...) - return result, true - } - return nil, false -} - -func (sh *suffixHandler) interpret(suffix suffix) (base, exponent int32, fmt Format, ok bool) { - // Try lookup tables first - if b, e, ok := sh.decSuffixes.lookup(suffix); ok { - return b, e, DecimalSI, true - } - if b, e, ok := sh.binSuffixes.lookup(suffix); ok { - return b, e, BinarySI, true - } - - if len(suffix) > 1 && (suffix[0] == 'E' || suffix[0] == 'e') { - parsed, err := strconv.ParseInt(string(suffix[1:]), 10, 64) - if err != nil { - return 0, 0, DecimalExponent, false - } - return 10, int32(parsed), DecimalExponent, true - } - - return 0, 0, DecimalExponent, false -} diff --git a/vendor/github.com/appc/spec/schema/types/semver.go b/vendor/github.com/appc/spec/schema/types/semver.go deleted file mode 100644 index 0008181a5ec..00000000000 --- a/vendor/github.com/appc/spec/schema/types/semver.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - - "github.com/coreos/go-semver/semver" -) - -var ( - ErrNoZeroSemVer = ACVersionError("SemVer cannot be zero") - ErrBadSemVer = ACVersionError("SemVer is bad") -) - -// SemVer implements the Unmarshaler interface to define a field that must be -// a semantic version string -// TODO(jonboulle): extend upstream instead of wrapping? -type SemVer semver.Version - -// NewSemVer generates a new SemVer from a string. If the given string does -// not represent a valid SemVer, nil and an error are returned. -func NewSemVer(s string) (*SemVer, error) { - nsv, err := semver.NewVersion(s) - if err != nil { - return nil, ErrBadSemVer - } - v := SemVer(*nsv) - if v.Empty() { - return nil, ErrNoZeroSemVer - } - return &v, nil -} - -func (sv SemVer) LessThanMajor(versionB SemVer) bool { - majorA := semver.Version(sv).Major - majorB := semver.Version(versionB).Major - if majorA < majorB { - return true - } - return false -} - -func (sv SemVer) LessThanExact(versionB SemVer) bool { - vA := semver.Version(sv) - vB := semver.Version(versionB) - return vA.LessThan(vB) -} - -func (sv SemVer) String() string { - s := semver.Version(sv) - return s.String() -} - -func (sv SemVer) Empty() bool { - return semver.Version(sv) == semver.Version{} -} - -// UnmarshalJSON implements the json.Unmarshaler interface -func (sv *SemVer) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - v, err := NewSemVer(s) - if err != nil { - return err - } - *sv = *v - return nil -} - -// MarshalJSON implements the json.Marshaler interface -func (sv SemVer) MarshalJSON() ([]byte, error) { - if sv.Empty() { - return nil, ErrNoZeroSemVer - } - return json.Marshal(sv.String()) -} diff --git a/vendor/github.com/appc/spec/schema/types/url.go b/vendor/github.com/appc/spec/schema/types/url.go deleted file mode 100644 index d4f8f337da4..00000000000 --- a/vendor/github.com/appc/spec/schema/types/url.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "fmt" - "net/url" -) - -// URL wraps url.URL to marshal/unmarshal to/from JSON strings and enforce -// that the scheme is HTTP/HTTPS only -type URL url.URL - -func NewURL(s string) (*URL, error) { - uu, err := url.Parse(s) - if err != nil { - return nil, fmt.Errorf("bad URL: %v", err) - } - nu := URL(*uu) - if err := nu.assertValidScheme(); err != nil { - return nil, err - } - return &nu, nil -} - -func (u URL) String() string { - uu := url.URL(u) - return uu.String() -} - -func (u URL) assertValidScheme() error { - switch u.Scheme { - case "http", "https": - return nil - default: - return fmt.Errorf("bad URL scheme, must be http/https") - } -} - -func (u *URL) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - nu, err := NewURL(s) - if err != nil { - return err - } - *u = *nu - return nil -} - -func (u URL) MarshalJSON() ([]byte, error) { - if err := u.assertValidScheme(); err != nil { - return nil, err - } - return json.Marshal(u.String()) -} diff --git a/vendor/github.com/appc/spec/schema/types/user_annotations.go b/vendor/github.com/appc/spec/schema/types/user_annotations.go deleted file mode 100644 index 63ba434ea5d..00000000000 --- a/vendor/github.com/appc/spec/schema/types/user_annotations.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 The appc Authors -// -// 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 types - -// UserAnnotations are arbitrary key-value pairs, to be supplied and interpreted by the user -type UserAnnotations map[string]string diff --git a/vendor/github.com/appc/spec/schema/types/user_labels.go b/vendor/github.com/appc/spec/schema/types/user_labels.go deleted file mode 100644 index 5ed927c9e8e..00000000000 --- a/vendor/github.com/appc/spec/schema/types/user_labels.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -// UserLabels are arbitrary key-value pairs, to be supplied and interpreted by the user -type UserLabels map[string]string diff --git a/vendor/github.com/appc/spec/schema/types/uuid.go b/vendor/github.com/appc/spec/schema/types/uuid.go deleted file mode 100644 index 4925b7606d3..00000000000 --- a/vendor/github.com/appc/spec/schema/types/uuid.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "reflect" - "strings" -) - -var ( - ErrNoEmptyUUID = errors.New("UUID cannot be empty") -) - -// UUID encodes an RFC4122-compliant UUID, marshaled to/from a string -// TODO(jonboulle): vendor a package for this? -// TODO(jonboulle): consider more flexibility in input string formats. -// Right now, we only accept: -// "6733C088-A507-4694-AABF-EDBE4FC5266F" -// "6733C088A5074694AABFEDBE4FC5266F" -type UUID [16]byte - -func (u UUID) String() string { - return fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:16]) -} - -func (u *UUID) Set(s string) error { - nu, err := NewUUID(s) - if err == nil { - *u = *nu - } - return err -} - -// NewUUID generates a new UUID from the given string. If the string does not -// represent a valid UUID, nil and an error are returned. -func NewUUID(s string) (*UUID, error) { - s = strings.Replace(s, "-", "", -1) - if len(s) != 32 { - return nil, errors.New("bad UUID length != 32") - } - dec, err := hex.DecodeString(s) - if err != nil { - return nil, err - } - var u UUID - for i, b := range dec { - u[i] = b - } - return &u, nil -} - -func (u UUID) Empty() bool { - return reflect.DeepEqual(u, UUID{}) -} - -func (u *UUID) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - uu, err := NewUUID(s) - if uu.Empty() { - return ErrNoEmptyUUID - } - if err == nil { - *u = *uu - } - return err -} - -func (u UUID) MarshalJSON() ([]byte, error) { - if u.Empty() { - return nil, ErrNoEmptyUUID - } - return json.Marshal(u.String()) -} diff --git a/vendor/github.com/appc/spec/schema/types/volume.go b/vendor/github.com/appc/spec/schema/types/volume.go deleted file mode 100644 index 0986a61d25f..00000000000 --- a/vendor/github.com/appc/spec/schema/types/volume.go +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 types - -import ( - "encoding/json" - "errors" - "fmt" - "net/url" - "path/filepath" - "strconv" - "strings" - - "github.com/appc/spec/schema/common" -) - -const ( - emptyVolumeDefaultMode = "0755" - emptyVolumeDefaultUID = 0 - emptyVolumeDefaultGID = 0 -) - -// Volume encapsulates a volume which should be mounted into the filesystem -// of all apps in a PodManifest -type Volume struct { - Name ACName `json:"name"` - Kind string `json:"kind"` - - // currently used only by "host" - // TODO(jonboulle): factor out? - Source string `json:"source,omitempty"` - ReadOnly *bool `json:"readOnly,omitempty"` - Recursive *bool `json:"recursive,omitempty"` - - // currently used only by "empty" - Mode *string `json:"mode,omitempty"` - UID *int `json:"uid,omitempty"` - GID *int `json:"gid,omitempty"` -} - -type volume Volume - -func (v Volume) assertValid() error { - if v.Name.Empty() { - return errors.New("name must be set") - } - - switch v.Kind { - case "empty": - if v.Source != "" { - return errors.New("source for empty volume must be empty") - } - if v.Mode == nil { - return errors.New("mode for empty volume must be set") - } - if v.UID == nil { - return errors.New("uid for empty volume must be set") - } - if v.GID == nil { - return errors.New("gid for empty volume must be set") - } - return nil - case "host": - if v.Source == "" { - return errors.New("source for host volume cannot be empty") - } - if v.Mode != nil { - return errors.New("mode for host volume cannot be set") - } - if v.UID != nil { - return errors.New("uid for host volume cannot be set") - } - if v.GID != nil { - return errors.New("gid for host volume cannot be set") - } - if !filepath.IsAbs(v.Source) { - return errors.New("source for host volume must be absolute path") - } - return nil - default: - return errors.New(`unrecognized volume kind: should be one of "empty", "host"`) - } -} - -func (v *Volume) UnmarshalJSON(data []byte) error { - var vv volume - if err := json.Unmarshal(data, &vv); err != nil { - return err - } - nv := Volume(vv) - maybeSetDefaults(&nv) - if err := nv.assertValid(); err != nil { - return err - } - *v = nv - return nil -} - -func (v Volume) MarshalJSON() ([]byte, error) { - if err := v.assertValid(); err != nil { - return nil, err - } - return json.Marshal(volume(v)) -} - -func (v Volume) String() string { - s := []string{ - v.Name.String(), - ",kind=", - v.Kind, - } - if v.Source != "" { - s = append(s, ",source=") - s = append(s, v.Source) - } - if v.ReadOnly != nil { - s = append(s, ",readOnly=") - s = append(s, strconv.FormatBool(*v.ReadOnly)) - } - if v.Recursive != nil { - s = append(s, ",recursive=") - s = append(s, strconv.FormatBool(*v.Recursive)) - } - switch v.Kind { - case "empty": - if *v.Mode != emptyVolumeDefaultMode { - s = append(s, ",mode=") - s = append(s, *v.Mode) - } - if *v.UID != emptyVolumeDefaultUID { - s = append(s, ",uid=") - s = append(s, strconv.Itoa(*v.UID)) - } - if *v.GID != emptyVolumeDefaultGID { - s = append(s, ",gid=") - s = append(s, strconv.Itoa(*v.GID)) - } - } - return strings.Join(s, "") -} - -// VolumeFromString takes a command line volume parameter and returns a volume -// -// Example volume parameters: -// database,kind=host,source=/tmp,readOnly=true,recursive=true -func VolumeFromString(vp string) (*Volume, error) { - vp = "name=" + vp - vpQuery, err := common.MakeQueryString(vp) - if err != nil { - return nil, err - } - - v, err := url.ParseQuery(vpQuery) - if err != nil { - return nil, err - } - return VolumeFromParams(v) -} - -func VolumeFromParams(params map[string][]string) (*Volume, error) { - var vol Volume - for key, val := range params { - val := val - if len(val) > 1 { - return nil, fmt.Errorf("label %s with multiple values %q", key, val) - } - - switch key { - case "name": - acn, err := NewACName(val[0]) - if err != nil { - return nil, err - } - vol.Name = *acn - case "kind": - vol.Kind = val[0] - case "source": - vol.Source = val[0] - case "readOnly": - ro, err := strconv.ParseBool(val[0]) - if err != nil { - return nil, err - } - vol.ReadOnly = &ro - case "recursive": - rec, err := strconv.ParseBool(val[0]) - if err != nil { - return nil, err - } - vol.Recursive = &rec - case "mode": - vol.Mode = &val[0] - case "uid": - u, err := strconv.Atoi(val[0]) - if err != nil { - return nil, err - } - vol.UID = &u - case "gid": - g, err := strconv.Atoi(val[0]) - if err != nil { - return nil, err - } - vol.GID = &g - default: - return nil, fmt.Errorf("unknown volume parameter %q", key) - } - } - - maybeSetDefaults(&vol) - - if err := vol.assertValid(); err != nil { - return nil, err - } - - return &vol, nil -} - -// maybeSetDefaults sets the correct default values for certain fields on a -// Volume if they are not already been set. These fields are not -// pre-populated on all Volumes as the Volume type is polymorphic. -func maybeSetDefaults(vol *Volume) { - if vol.Kind == "empty" { - if vol.Mode == nil { - m := emptyVolumeDefaultMode - vol.Mode = &m - } - if vol.UID == nil { - u := emptyVolumeDefaultUID - vol.UID = &u - } - if vol.GID == nil { - g := emptyVolumeDefaultGID - vol.GID = &g - } - } -} diff --git a/vendor/github.com/appc/spec/schema/version.go b/vendor/github.com/appc/spec/schema/version.go deleted file mode 100644 index 1fa0802949b..00000000000 --- a/vendor/github.com/appc/spec/schema/version.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015 The appc Authors -// -// 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 schema - -import ( - "github.com/appc/spec/schema/types" -) - -const ( - // version represents the canonical version of the appc spec and tooling. - // For now, the schema and tooling is coupled with the spec itself, so - // this must be kept in sync with the VERSION file in the root of the repo. - version string = "0.8.9+git" -) - -var ( - // AppContainerVersion is the SemVer representation of version - AppContainerVersion types.SemVer -) - -func init() { - v, err := types.NewSemVer(version) - if err != nil { - panic(err) - } - AppContainerVersion = *v -} diff --git a/vendor/github.com/coreos/go-systemd/unit/BUILD b/vendor/github.com/coreos/go-systemd/unit/BUILD deleted file mode 100644 index 554136a7844..00000000000 --- a/vendor/github.com/coreos/go-systemd/unit/BUILD +++ /dev/null @@ -1,27 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "deserialize.go", - "escape.go", - "option.go", - "serialize.go", - ], - importpath = "github.com/coreos/go-systemd/unit", - visibility = ["//visibility:public"], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/coreos/go-systemd/unit/deserialize.go b/vendor/github.com/coreos/go-systemd/unit/deserialize.go deleted file mode 100644 index 8a88162f98b..00000000000 --- a/vendor/github.com/coreos/go-systemd/unit/deserialize.go +++ /dev/null @@ -1,276 +0,0 @@ -// 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 unit - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "io" - "strings" - "unicode" -) - -const ( - // SYSTEMD_LINE_MAX mimics the maximum line length that systemd can use. - // On typical systemd platforms (i.e. modern Linux), this will most - // commonly be 2048, so let's use that as a sanity check. - // Technically, we should probably pull this at runtime: - // SYSTEMD_LINE_MAX = int(C.sysconf(C.__SC_LINE_MAX)) - // but this would introduce an (unfortunate) dependency on cgo - SYSTEMD_LINE_MAX = 2048 - - // characters that systemd considers indicate a newline - SYSTEMD_NEWLINE = "\r\n" -) - -var ( - ErrLineTooLong = fmt.Errorf("line too long (max %d bytes)", SYSTEMD_LINE_MAX) -) - -// Deserialize parses a systemd unit file into a list of UnitOption objects. -func Deserialize(f io.Reader) (opts []*UnitOption, err error) { - lexer, optchan, errchan := newLexer(f) - go lexer.lex() - - for opt := range optchan { - opts = append(opts, &(*opt)) - } - - err = <-errchan - return opts, err -} - -func newLexer(f io.Reader) (*lexer, <-chan *UnitOption, <-chan error) { - optchan := make(chan *UnitOption) - errchan := make(chan error, 1) - buf := bufio.NewReader(f) - - return &lexer{buf, optchan, errchan, ""}, optchan, errchan -} - -type lexer struct { - buf *bufio.Reader - optchan chan *UnitOption - errchan chan error - section string -} - -func (l *lexer) lex() { - var err error - defer func() { - close(l.optchan) - close(l.errchan) - }() - next := l.lexNextSection - for next != nil { - if l.buf.Buffered() >= SYSTEMD_LINE_MAX { - // systemd truncates lines longer than LINE_MAX - // https://bugs.freedesktop.org/show_bug.cgi?id=85308 - // Rather than allowing this to pass silently, let's - // explicitly gate people from encountering this - line, err := l.buf.Peek(SYSTEMD_LINE_MAX) - if err != nil { - l.errchan <- err - return - } - if bytes.IndexAny(line, SYSTEMD_NEWLINE) == -1 { - l.errchan <- ErrLineTooLong - return - } - } - - next, err = next() - if err != nil { - l.errchan <- err - return - } - } -} - -type lexStep func() (lexStep, error) - -func (l *lexer) lexSectionName() (lexStep, error) { - sec, err := l.buf.ReadBytes(']') - if err != nil { - return nil, errors.New("unable to find end of section") - } - - return l.lexSectionSuffixFunc(string(sec[:len(sec)-1])), nil -} - -func (l *lexer) lexSectionSuffixFunc(section string) lexStep { - return func() (lexStep, error) { - garbage, _, err := l.toEOL() - if err != nil { - return nil, err - } - - garbage = bytes.TrimSpace(garbage) - if len(garbage) > 0 { - return nil, fmt.Errorf("found garbage after section name %s: %v", l.section, garbage) - } - - return l.lexNextSectionOrOptionFunc(section), nil - } -} - -func (l *lexer) ignoreLineFunc(next lexStep) lexStep { - return func() (lexStep, error) { - for { - line, _, err := l.toEOL() - if err != nil { - return nil, err - } - - line = bytes.TrimSuffix(line, []byte{' '}) - - // lack of continuation means this line has been exhausted - if !bytes.HasSuffix(line, []byte{'\\'}) { - break - } - } - - // reached end of buffer, safe to exit - return next, nil - } -} - -func (l *lexer) lexNextSection() (lexStep, error) { - r, _, err := l.buf.ReadRune() - if err != nil { - if err == io.EOF { - err = nil - } - return nil, err - } - - if r == '[' { - return l.lexSectionName, nil - } else if isComment(r) { - return l.ignoreLineFunc(l.lexNextSection), nil - } - - return l.lexNextSection, nil -} - -func (l *lexer) lexNextSectionOrOptionFunc(section string) lexStep { - return func() (lexStep, error) { - r, _, err := l.buf.ReadRune() - if err != nil { - if err == io.EOF { - err = nil - } - return nil, err - } - - if unicode.IsSpace(r) { - return l.lexNextSectionOrOptionFunc(section), nil - } else if r == '[' { - return l.lexSectionName, nil - } else if isComment(r) { - return l.ignoreLineFunc(l.lexNextSectionOrOptionFunc(section)), nil - } - - l.buf.UnreadRune() - return l.lexOptionNameFunc(section), nil - } -} - -func (l *lexer) lexOptionNameFunc(section string) lexStep { - return func() (lexStep, error) { - var partial bytes.Buffer - for { - r, _, err := l.buf.ReadRune() - if err != nil { - return nil, err - } - - if r == '\n' || r == '\r' { - return nil, errors.New("unexpected newline encountered while parsing option name") - } - - if r == '=' { - break - } - - partial.WriteRune(r) - } - - name := strings.TrimSpace(partial.String()) - return l.lexOptionValueFunc(section, name, bytes.Buffer{}), nil - } -} - -func (l *lexer) lexOptionValueFunc(section, name string, partial bytes.Buffer) lexStep { - return func() (lexStep, error) { - for { - line, eof, err := l.toEOL() - if err != nil { - return nil, err - } - - if len(bytes.TrimSpace(line)) == 0 { - break - } - - partial.Write(line) - - // lack of continuation means this value has been exhausted - idx := bytes.LastIndex(line, []byte{'\\'}) - if idx == -1 || idx != (len(line)-1) { - break - } - - if !eof { - partial.WriteRune('\n') - } - - return l.lexOptionValueFunc(section, name, partial), nil - } - - val := partial.String() - if strings.HasSuffix(val, "\n") { - // A newline was added to the end, so the file didn't end with a backslash. - // => Keep the newline - val = strings.TrimSpace(val) + "\n" - } else { - val = strings.TrimSpace(val) - } - l.optchan <- &UnitOption{Section: section, Name: name, Value: val} - - return l.lexNextSectionOrOptionFunc(section), nil - } -} - -// toEOL reads until the end-of-line or end-of-file. -// Returns (data, EOFfound, error) -func (l *lexer) toEOL() ([]byte, bool, error) { - line, err := l.buf.ReadBytes('\n') - // ignore EOF here since it's roughly equivalent to EOL - if err != nil && err != io.EOF { - return nil, false, err - } - - line = bytes.TrimSuffix(line, []byte{'\r'}) - line = bytes.TrimSuffix(line, []byte{'\n'}) - - return line, err == io.EOF, nil -} - -func isComment(r rune) bool { - return r == '#' || r == ';' -} diff --git a/vendor/github.com/coreos/go-systemd/unit/escape.go b/vendor/github.com/coreos/go-systemd/unit/escape.go deleted file mode 100644 index 63b11726dba..00000000000 --- a/vendor/github.com/coreos/go-systemd/unit/escape.go +++ /dev/null @@ -1,116 +0,0 @@ -// 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. - -// Implements systemd-escape [--unescape] [--path] - -package unit - -import ( - "fmt" - "strconv" - "strings" -) - -const ( - allowed = `:_.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789` -) - -// If isPath is true: -// We remove redundant '/'s, the leading '/', and trailing '/'. -// If the result is empty, a '/' is inserted. -// -// We always: -// Replace the following characters with `\x%x`: -// Leading `.` -// `-`, `\`, and anything not in this set: `:-_.\[0-9a-zA-Z]` -// Replace '/' with '-'. -func escape(unescaped string, isPath bool) string { - e := []byte{} - inSlashes := false - start := true - for i := 0; i < len(unescaped); i++ { - c := unescaped[i] - if isPath { - if c == '/' { - inSlashes = true - continue - } else if inSlashes { - inSlashes = false - if !start { - e = append(e, '-') - } - } - } - - if c == '/' { - e = append(e, '-') - } else if start && c == '.' || strings.IndexByte(allowed, c) == -1 { - e = append(e, []byte(fmt.Sprintf(`\x%x`, c))...) - } else { - e = append(e, c) - } - start = false - } - if isPath && len(e) == 0 { - e = append(e, '-') - } - return string(e) -} - -// If isPath is true: -// We always return a string beginning with '/'. -// -// We always: -// Replace '-' with '/'. -// Replace `\x%x` with the value represented in hex. -func unescape(escaped string, isPath bool) string { - u := []byte{} - for i := 0; i < len(escaped); i++ { - c := escaped[i] - if c == '-' { - c = '/' - } else if c == '\\' && len(escaped)-i >= 4 && escaped[i+1] == 'x' { - n, err := strconv.ParseInt(escaped[i+2:i+4], 16, 8) - if err == nil { - c = byte(n) - i += 3 - } - } - u = append(u, c) - } - if isPath && (len(u) == 0 || u[0] != '/') { - u = append([]byte("/"), u...) - } - return string(u) -} - -// UnitNameEscape escapes a string as `systemd-escape` would -func UnitNameEscape(unescaped string) string { - return escape(unescaped, false) -} - -// UnitNameUnescape unescapes a string as `systemd-escape --unescape` would -func UnitNameUnescape(escaped string) string { - return unescape(escaped, false) -} - -// UnitNamePathEscape escapes a string as `systemd-escape --path` would -func UnitNamePathEscape(unescaped string) string { - return escape(unescaped, true) -} - -// UnitNamePathUnescape unescapes a string as `systemd-escape --path --unescape` would -func UnitNamePathUnescape(escaped string) string { - return unescape(escaped, true) -} diff --git a/vendor/github.com/coreos/go-systemd/unit/option.go b/vendor/github.com/coreos/go-systemd/unit/option.go deleted file mode 100644 index e5d21e19d91..00000000000 --- a/vendor/github.com/coreos/go-systemd/unit/option.go +++ /dev/null @@ -1,54 +0,0 @@ -// 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 unit - -import ( - "fmt" -) - -type UnitOption struct { - Section string - Name string - Value string -} - -func NewUnitOption(section, name, value string) *UnitOption { - return &UnitOption{Section: section, Name: name, Value: value} -} - -func (uo *UnitOption) String() string { - return fmt.Sprintf("{Section: %q, Name: %q, Value: %q}", uo.Section, uo.Name, uo.Value) -} - -func (uo *UnitOption) Match(other *UnitOption) bool { - return uo.Section == other.Section && - uo.Name == other.Name && - uo.Value == other.Value -} - -func AllMatch(u1 []*UnitOption, u2 []*UnitOption) bool { - length := len(u1) - if length != len(u2) { - return false - } - - for i := 0; i < length; i++ { - if !u1[i].Match(u2[i]) { - return false - } - } - - return true -} diff --git a/vendor/github.com/coreos/go-systemd/unit/serialize.go b/vendor/github.com/coreos/go-systemd/unit/serialize.go deleted file mode 100644 index e07799cad61..00000000000 --- a/vendor/github.com/coreos/go-systemd/unit/serialize.go +++ /dev/null @@ -1,75 +0,0 @@ -// 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 unit - -import ( - "bytes" - "io" -) - -// Serialize encodes all of the given UnitOption objects into a -// unit file. When serialized the options are sorted in their -// supplied order but grouped by section. -func Serialize(opts []*UnitOption) io.Reader { - var buf bytes.Buffer - - if len(opts) == 0 { - return &buf - } - - // Index of sections -> ordered options - idx := map[string][]*UnitOption{} - // Separately preserve order in which sections were seen - sections := []string{} - for _, opt := range opts { - sec := opt.Section - if _, ok := idx[sec]; !ok { - sections = append(sections, sec) - } - idx[sec] = append(idx[sec], opt) - } - - for i, sect := range sections { - writeSectionHeader(&buf, sect) - writeNewline(&buf) - - opts := idx[sect] - for _, opt := range opts { - writeOption(&buf, opt) - writeNewline(&buf) - } - if i < len(sections)-1 { - writeNewline(&buf) - } - } - - return &buf -} - -func writeNewline(buf *bytes.Buffer) { - buf.WriteRune('\n') -} - -func writeSectionHeader(buf *bytes.Buffer, section string) { - buf.WriteRune('[') - buf.WriteString(section) - buf.WriteRune(']') -} - -func writeOption(buf *bytes.Buffer, opt *UnitOption) { - buf.WriteString(opt.Name) - buf.WriteRune('=') - buf.WriteString(opt.Value) -} diff --git a/vendor/go4.org/AUTHORS b/vendor/go4.org/AUTHORS deleted file mode 100644 index d1ad485f52f..00000000000 --- a/vendor/go4.org/AUTHORS +++ /dev/null @@ -1,8 +0,0 @@ -# This is the official list of go4 authors for copyright purposes. -# This is distinct from the CONTRIBUTORS file, which is the list of -# people who have contributed, even if they don't own the copyright on -# their work. - -Mathieu Lonjaret -Daniel Theophanes -Google diff --git a/vendor/go4.org/LICENSE b/vendor/go4.org/LICENSE deleted file mode 100644 index 8f71f43fee3..00000000000 --- a/vendor/go4.org/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - diff --git a/vendor/go4.org/errorutil/BUILD b/vendor/go4.org/errorutil/BUILD deleted file mode 100644 index 30a5dd2db92..00000000000 --- a/vendor/go4.org/errorutil/BUILD +++ /dev/null @@ -1,22 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = ["highlight.go"], - importpath = "go4.org/errorutil", - visibility = ["//visibility:public"], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) diff --git a/vendor/go4.org/errorutil/highlight.go b/vendor/go4.org/errorutil/highlight.go deleted file mode 100644 index aace6a46cce..00000000000 --- a/vendor/go4.org/errorutil/highlight.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 2011 Google 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 errorutil helps make better error messages. -package errorutil - -import ( - "bufio" - "bytes" - "fmt" - "io" - "strings" -) - -// HighlightBytePosition takes a reader and the location in bytes of a parse -// error (for instance, from json.SyntaxError.Offset) and returns the line, column, -// and pretty-printed context around the error with an arrow indicating the exact -// position of the syntax error. -func HighlightBytePosition(f io.Reader, pos int64) (line, col int, highlight string) { - line = 1 - br := bufio.NewReader(f) - lastLine := "" - thisLine := new(bytes.Buffer) - for n := int64(0); n < pos; n++ { - b, err := br.ReadByte() - if err != nil { - break - } - if b == '\n' { - lastLine = thisLine.String() - thisLine.Reset() - line++ - col = 1 - } else { - col++ - thisLine.WriteByte(b) - } - } - if line > 1 { - highlight += fmt.Sprintf("%5d: %s\n", line-1, lastLine) - } - highlight += fmt.Sprintf("%5d: %s\n", line, thisLine.String()) - highlight += fmt.Sprintf("%s^\n", strings.Repeat(" ", col+5)) - return -} From 366ad30ab684090008c2f61836e68b8fca9eb2b3 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Thu, 22 Mar 2018 09:50:54 -0700 Subject: [PATCH 3/3] Remove references to rkt from shell scripts in cluster/ and hack/. --- cluster/gce/config-default.sh | 2 -- cluster/gce/config-test.sh | 2 -- cluster/gce/gci/mounter/stage-upload.sh | 21 +-------------------- hack/local-up-cluster.sh | 25 ------------------------- 4 files changed, 1 insertion(+), 49 deletions(-) diff --git a/cluster/gce/config-default.sh b/cluster/gce/config-default.sh index a4974265a1d..535afb6bad6 100755 --- a/cluster/gce/config-default.sh +++ b/cluster/gce/config-default.sh @@ -84,8 +84,6 @@ CONTAINER_RUNTIME=${KUBE_CONTAINER_RUNTIME:-docker} CONTAINER_RUNTIME_ENDPOINT=${KUBE_CONTAINER_RUNTIME_ENDPOINT:-} CONTAINER_RUNTIME_NAME=${KUBE_CONTAINER_RUNTIME_NAME:-} LOAD_IMAGE_COMMAND=${KUBE_LOAD_IMAGE_COMMAND:-} -RKT_VERSION=${KUBE_RKT_VERSION:-1.23.0} -RKT_STAGE1_IMAGE=${KUBE_RKT_STAGE1_IMAGE:-coreos.com/rkt/stage1-coreos} # MASTER_EXTRA_METADATA is the extra instance metadata on master instance separated by commas. MASTER_EXTRA_METADATA=${KUBE_MASTER_EXTRA_METADATA:-${KUBE_EXTRA_METADATA:-}} # MASTER_EXTRA_METADATA is the extra instance metadata on node instance separated by commas. diff --git a/cluster/gce/config-test.sh b/cluster/gce/config-test.sh index c90c781ce74..69056063fa4 100755 --- a/cluster/gce/config-test.sh +++ b/cluster/gce/config-test.sh @@ -83,8 +83,6 @@ CONTAINER_RUNTIME_ENDPOINT=${KUBE_CONTAINER_RUNTIME_ENDPOINT:-} CONTAINER_RUNTIME_NAME=${KUBE_CONTAINER_RUNTIME_NAME:-} LOAD_IMAGE_COMMAND=${KUBE_LOAD_IMAGE_COMMAND:-} GCI_DOCKER_VERSION=${KUBE_GCI_DOCKER_VERSION:-} -RKT_VERSION=${KUBE_RKT_VERSION:-1.23.0} -RKT_STAGE1_IMAGE=${KUBE_RKT_STAGE1_IMAGE:-coreos.com/rkt/stage1-coreos} # MASTER_EXTRA_METADATA is the extra instance metadata on master instance separated by commas. MASTER_EXTRA_METADATA=${KUBE_MASTER_EXTRA_METADATA:-${KUBE_EXTRA_METADATA:-}} # MASTER_EXTRA_METADATA is the extra instance metadata on node instance separated by commas. diff --git a/cluster/gce/gci/mounter/stage-upload.sh b/cluster/gce/gci/mounter/stage-upload.sh index 66780da381e..f3359447c39 100755 --- a/cluster/gce/gci/mounter/stage-upload.sh +++ b/cluster/gce/gci/mounter/stage-upload.sh @@ -23,12 +23,10 @@ set -o errexit set -o pipefail set -o nounset -RKT_VERSION="v1.18.0" DOCKER2ACI_VERSION="v0.13.0" MOUNTER_VERSION=$1 DOCKER_IMAGE=docker://$2 MOUNTER_ACI_IMAGE=gci-mounter-${MOUNTER_VERSION}.aci -RKT_GCS_DIR=gs://kubernetes-release/rkt/ MOUNTER_GCS_DIR=gs://kubernetes-release/gci-mounter/ TMPDIR=/tmp @@ -37,7 +35,6 @@ DOWNLOAD_DIR=$(mktemp --tmpdir=${TMPDIR} -d gci-mounter-build.XXXXXXXXXX) # Setup a staging directory STAGING_DIR=$(mktemp --tmpdir=${TMPDIR} -d gci-mounter-staging.XXXXXXXXXX) -RKT_DIR=${STAGING_DIR}/${RKT_VERSION} ACI_DIR=${STAGING_DIR}/gci-mounter CWD=${PWD} @@ -51,20 +48,8 @@ function cleanup { # Delete temporary directories on exit trap cleanup EXIT -mkdir ${RKT_DIR} mkdir ${ACI_DIR} -# Download rkt -cd ${DOWNLOAD_DIR} -echo "Downloading rkt ${RKT_VERSION}" -wget "https://github.com/coreos/rkt/releases/download/${RKT_VERSION}/rkt-${RKT_VERSION}.tar.gz" &> /dev/null -echo "Extracting rkt ${RKT_VERSION}" -tar xzf rkt-${RKT_VERSION}.tar.gz - -# Stage rkt into working directory -cp rkt-${RKT_VERSION}/rkt ${RKT_DIR}/rkt -cp rkt-${RKT_VERSION}/stage1-fly.aci ${RKT_DIR}/ - # Convert docker image to aci and stage it echo "Downloading docker2aci ${DOCKER2ACI_VERSION}" wget "https://github.com/appc/docker2aci/releases/download/${DOCKER2ACI_VERSION}/docker2aci-${DOCKER2ACI_VERSION}.tar.gz" &> /dev/null @@ -74,13 +59,9 @@ ACI_IMAGE=$(${DOWNLOAD_DIR}/docker2aci-${DOCKER2ACI_VERSION}/docker2aci ${DOCKER cp ${ACI_IMAGE} ${ACI_DIR}/${MOUNTER_ACI_IMAGE} # Upload the contents to gcs -echo "Uploading rkt artifacts in ${RKT_DIR} to ${RKT_GCS_DIR}" -gsutil cp -R ${RKT_DIR} ${RKT_GCS_DIR} echo "Uploading gci mounter ACI in ${ACI_DIR} to ${MOUNTER_GCS_DIR}" gsutil cp ${ACI_DIR}/${MOUNTER_ACI_IMAGE} ${MOUNTER_GCS_DIR} echo "Upload completed" -echo "Update rkt, stag1-fly.aci & gci-mounter ACI versions and SHA1 in cluster/gce/gci/configure.sh" -echo "${RKT_VERSION}/rkt sha1: $(sha1sum ${RKT_DIR}/rkt)" -echo "${RKT_VERSION}/stage1-fly.aci sha1: $(sha1sum ${RKT_DIR}/stage1-fly.aci)" +echo "Updated gci-mounter ACI version and SHA1 in cluster/gce/gci/configure.sh" echo "${MOUNTER_ACI_IMAGE} hash: $(sha1sum ${ACI_DIR}/${MOUNTER_ACI_IMAGE})" diff --git a/hack/local-up-cluster.sh b/hack/local-up-cluster.sh index 0d762d491bf..5c301b31a43 100755 --- a/hack/local-up-cluster.sh +++ b/hack/local-up-cluster.sh @@ -204,23 +204,6 @@ else echo "skipped the build." fi -function test_rkt { - if [[ -n "${RKT_PATH}" ]]; then - ${RKT_PATH} list 2> /dev/null 1> /dev/null - if [ "$?" != "0" ]; then - echo "Failed to successfully run 'rkt list', please verify that ${RKT_PATH} is the path of rkt binary." - exit 1 - fi - else - rkt list 2> /dev/null 1> /dev/null - if [ "$?" != "0" ]; then - echo "Failed to successfully run 'rkt list', please verify that rkt is in \$PATH." - exit 1 - fi - fi -} - - # Shut down anyway if there's an error. set +e @@ -245,8 +228,6 @@ LOG_DIR=${LOG_DIR:-"/tmp"} CONTAINER_RUNTIME=${CONTAINER_RUNTIME:-"docker"} CONTAINER_RUNTIME_ENDPOINT=${CONTAINER_RUNTIME_ENDPOINT:-""} IMAGE_SERVICE_ENDPOINT=${IMAGE_SERVICE_ENDPOINT:-""} -RKT_PATH=${RKT_PATH:-""} -RKT_STAGE1_IMAGE=${RKT_STAGE1_IMAGE:-""} CHAOS_CHANCE=${CHAOS_CHANCE:-0.0} CPU_CFS_QUOTA=${CPU_CFS_QUOTA:-true} ENABLE_HOSTPATH_PROVISIONER=${ENABLE_HOSTPATH_PROVISIONER:-"false"} @@ -734,8 +715,6 @@ function start_kubelet { --vmodule="${LOG_SPEC}" \ --chaos-chance="${CHAOS_CHANCE}" \ --container-runtime="${CONTAINER_RUNTIME}" \ - --rkt-path="${RKT_PATH}" \ - --rkt-stage1-image="${RKT_STAGE1_IMAGE}" \ --hostname-override="${HOSTNAME_OVERRIDE}" \ ${cloud_config_arg} \ --address="${KUBELET_HOST}" \ @@ -965,10 +944,6 @@ if [ "${CONTAINER_RUNTIME}" == "docker" ] && ! kube::util::ensure_docker_daemon_ exit 1 fi -if [[ "${CONTAINER_RUNTIME}" == "rkt" ]]; then - test_rkt -fi - if [[ "${START_MODE}" != "kubeletonly" ]]; then test_apiserver_off fi