Merge pull request #61432 from filbranden/killrkt1
Automatic merge from submit-queue (batch tested with PRs 61904, 61565, 61401, 61432, 61772). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Remove rktnetes code **What this PR does / why we need it**: 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. **Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: Fixes #58721 **Special notes for your reviewer**: **Release note**: ```release-note Removed rknetes code, which was deprecated in 1.10. ``` /assign @yujuhong /hold Hold until the end of the freeze.
This commit is contained in:
commit
399b835f54
31
Godeps/Godeps.json
generated
31
Godeps/Godeps.json
generated
@ -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"
|
||||
|
1249
Godeps/LICENSES
generated
1249
Godeps/LICENSES
generated
File diff suppressed because it is too large
Load Diff
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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})"
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -205,23 +205,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
|
||||
|
||||
@ -246,8 +229,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"}
|
||||
@ -735,8 +716,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}" \
|
||||
@ -966,10 +945,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
|
||||
|
@ -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",
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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, "<Warning: Alpha feature> 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, "<Warning: Alpha feature> 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, "<Warning: Alpha feature> 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, "<Warning: Alpha feature> 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).")
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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"],
|
||||
)
|
@ -1,3 +0,0 @@
|
||||
approvers:
|
||||
- euank
|
||||
- yifan-gu
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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"
|
@ -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
|
||||
}
|
@ -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: [<registry>/]<repository>/<image>[:<version]
|
||||
explicitRegistry := (strings.Count(image, "/") == 2)
|
||||
if explicitRegistry {
|
||||
registry = strings.Split(image, "/")[0]
|
||||
}
|
||||
|
||||
authDir := filepath.Join(userConfigDir, "auth.d")
|
||||
if _, err := os.Stat(authDir); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(authDir, 0600); err != nil {
|
||||
glog.Errorf("rkt: Cannot create auth dir: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
config := fmt.Sprintf(dockerAuthTemplate, registry, creds.Username, creds.Password)
|
||||
if err := ioutil.WriteFile(path.Join(authDir, registry+".json"), []byte(config), 0600); err != nil {
|
||||
glog.Errorf("rkt: Cannot write docker auth config file: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ImageStats returns the image stat (total storage bytes).
|
||||
func (r *Runtime) ImageStats() (*kubecontainer.ImageStats, error) {
|
||||
var imageStat kubecontainer.ImageStats
|
||||
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)
|
||||
}
|
||||
|
||||
for _, image := range listResp.Images {
|
||||
imageStat.TotalStorageBytes = imageStat.TotalStorageBytes + uint64(image.Size)
|
||||
}
|
||||
return &imageStat, nil
|
||||
}
|
@ -1,123 +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"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
rktapi "github.com/coreos/rkt/api/v1alpha"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util/format"
|
||||
)
|
||||
|
||||
const (
|
||||
journalTimestampLayout = "2006-01-02 15:04:05 -0700 MST"
|
||||
)
|
||||
|
||||
// processLines write the lines into stdout in the required format.
|
||||
func processLines(lines []string, logOptions *v1.PodLogOptions, stdout, stderr io.Writer) {
|
||||
msgKey := "MESSAGE="
|
||||
|
||||
for _, line := range lines {
|
||||
msgStart := strings.Index(line, msgKey)
|
||||
if msgStart < 0 {
|
||||
glog.Warningf("rkt: Invalid log line %q, missing %q", line, msgKey)
|
||||
continue
|
||||
}
|
||||
|
||||
tss := strings.TrimSpace(line[:msgStart])
|
||||
msg := strings.TrimPrefix(line[msgStart:], msgKey)
|
||||
|
||||
t, err := time.Parse(journalTimestampLayout, tss)
|
||||
if err != nil {
|
||||
glog.Warningf("rkt: Failed to parse the timestamp %q: %v", tss, err)
|
||||
continue
|
||||
}
|
||||
|
||||
var result string
|
||||
if logOptions.Timestamps {
|
||||
result = fmt.Sprintf("%s %s\n", t.Format(time.RFC3339), msg)
|
||||
} else {
|
||||
result = fmt.Sprintf("%s\n", msg)
|
||||
}
|
||||
|
||||
if _, err := io.WriteString(stdout, result); err != nil {
|
||||
glog.Warningf("rkt: Cannot write log line %q to output: %v", result, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetContainerLogs uses rkt's GetLogs API to get the logs of the container.
|
||||
// By default, it returns a snapshot of the container log. Set |follow| to true to
|
||||
// stream the log. Set |follow| to false and specify the number of lines (e.g.
|
||||
// "100" or "all") to tail the log.
|
||||
//
|
||||
// TODO(yifan): This doesn't work with lkvm stage1 yet.
|
||||
func (r *Runtime) GetContainerLogs(pod *v1.Pod, containerID kubecontainer.ContainerID, logOptions *v1.PodLogOptions, stdout, stderr io.Writer) error {
|
||||
id, err := parseContainerID(containerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var since int64
|
||||
if logOptions.SinceSeconds != nil {
|
||||
t := metav1.Now().Add(-time.Duration(*logOptions.SinceSeconds) * time.Second)
|
||||
since = t.Unix()
|
||||
}
|
||||
if logOptions.SinceTime != nil {
|
||||
since = logOptions.SinceTime.Unix()
|
||||
}
|
||||
|
||||
getLogsRequest := &rktapi.GetLogsRequest{
|
||||
PodId: id.uuid,
|
||||
AppName: id.appName,
|
||||
Follow: logOptions.Follow,
|
||||
SinceTime: since,
|
||||
}
|
||||
|
||||
if logOptions.TailLines != nil {
|
||||
getLogsRequest.Lines = int32(*logOptions.TailLines)
|
||||
}
|
||||
|
||||
stream, err := r.apisvc.GetLogs(context.Background(), getLogsRequest)
|
||||
if err != nil {
|
||||
glog.Errorf("rkt: Failed to create log stream for pod %q: %v", format.Pod(pod), err)
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
log, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
glog.Errorf("rkt: Failed to receive log for pod %q: %v", format.Pod(pod), err)
|
||||
return err
|
||||
}
|
||||
processLines(log.Lines, logOptions, stdout, stderr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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{
|
||||
|
@ -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.
|
||||
|
3
vendor/BUILD
vendored
3
vendor/BUILD
vendored
@ -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",
|
||||
|
202
vendor/github.com/appc/spec/LICENSE
generated
vendored
202
vendor/github.com/appc/spec/LICENSE
generated
vendored
@ -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.
|
||||
|
36
vendor/github.com/appc/spec/schema/BUILD
generated
vendored
36
vendor/github.com/appc/spec/schema/BUILD
generated
vendored
@ -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"],
|
||||
)
|
22
vendor/github.com/appc/spec/schema/common/BUILD
generated
vendored
22
vendor/github.com/appc/spec/schema/common/BUILD
generated
vendored
@ -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"],
|
||||
)
|
40
vendor/github.com/appc/spec/schema/common/common.go
generated
vendored
40
vendor/github.com/appc/spec/schema/common/common.go
generated
vendored
@ -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
|
||||
}
|
25
vendor/github.com/appc/spec/schema/doc.go
generated
vendored
25
vendor/github.com/appc/spec/schema/doc.go
generated
vendored
@ -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
|
103
vendor/github.com/appc/spec/schema/image.go
generated
vendored
103
vendor/github.com/appc/spec/schema/image.go
generated
vendored
@ -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)
|
||||
}
|
42
vendor/github.com/appc/spec/schema/kind.go
generated
vendored
42
vendor/github.com/appc/spec/schema/kind.go
generated
vendored
@ -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))
|
||||
}
|
173
vendor/github.com/appc/spec/schema/pod.go
generated
vendored
173
vendor/github.com/appc/spec/schema/pod.go
generated
vendored
@ -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"`
|
||||
}
|
57
vendor/github.com/appc/spec/schema/types/BUILD
generated
vendored
57
vendor/github.com/appc/spec/schema/types/BUILD
generated
vendored
@ -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"],
|
||||
)
|
145
vendor/github.com/appc/spec/schema/types/acidentifier.go
generated
vendored
145
vendor/github.com/appc/spec/schema/types/acidentifier.go
generated
vendored
@ -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
|
||||
}
|
67
vendor/github.com/appc/spec/schema/types/ackind.go
generated
vendored
67
vendor/github.com/appc/spec/schema/types/ackind.go
generated
vendored
@ -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
|
||||
}
|
145
vendor/github.com/appc/spec/schema/types/acname.go
generated
vendored
145
vendor/github.com/appc/spec/schema/types/acname.go
generated
vendored
@ -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
|
||||
}
|
106
vendor/github.com/appc/spec/schema/types/annotations.go
generated
vendored
106
vendor/github.com/appc/spec/schema/types/annotations.go
generated
vendored
@ -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)
|
||||
}
|
95
vendor/github.com/appc/spec/schema/types/app.go
generated
vendored
95
vendor/github.com/appc/spec/schema/types/app.go
generated
vendored
@ -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
|
||||
}
|
60
vendor/github.com/appc/spec/schema/types/date.go
generated
vendored
60
vendor/github.com/appc/spec/schema/types/date.go
generated
vendored
@ -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())
|
||||
}
|
58
vendor/github.com/appc/spec/schema/types/dependencies.go
generated
vendored
58
vendor/github.com/appc/spec/schema/types/dependencies.go
generated
vendored
@ -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
|
||||
}
|
18
vendor/github.com/appc/spec/schema/types/doc.go
generated
vendored
18
vendor/github.com/appc/spec/schema/types/doc.go
generated
vendored
@ -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
|
110
vendor/github.com/appc/spec/schema/types/environment.go
generated
vendored
110
vendor/github.com/appc/spec/schema/types/environment.go
generated
vendored
@ -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)
|
||||
}
|
49
vendor/github.com/appc/spec/schema/types/errors.go
generated
vendored
49
vendor/github.com/appc/spec/schema/types/errors.go
generated
vendored
@ -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)
|
||||
}
|
61
vendor/github.com/appc/spec/schema/types/event_handler.go
generated
vendored
61
vendor/github.com/appc/spec/schema/types/event_handler.go
generated
vendored
@ -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
|
||||
}
|
46
vendor/github.com/appc/spec/schema/types/exec.go
generated
vendored
46
vendor/github.com/appc/spec/schema/types/exec.go
generated
vendored
@ -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
|
||||
}
|
118
vendor/github.com/appc/spec/schema/types/hash.go
generated
vendored
118
vendor/github.com/appc/spec/schema/types/hash.go
generated
vendored
@ -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:
|
||||
// "<type>-<value>"
|
||||
// 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
|
||||
}
|
190
vendor/github.com/appc/spec/schema/types/isolator.go
generated
vendored
190
vendor/github.com/appc/spec/schema/types/isolator.go
generated
vendored
@ -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
|
||||
}
|
529
vendor/github.com/appc/spec/schema/types/isolator_linux_specific.go
generated
vendored
529
vendor/github.com/appc/spec/schema/types/isolator_linux_specific.go
generated
vendored
@ -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
|
||||
}
|
245
vendor/github.com/appc/spec/schema/types/isolator_resources.go
generated
vendored
245
vendor/github.com/appc/spec/schema/types/isolator_resources.go
generated
vendored
@ -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
|
||||
}
|
83
vendor/github.com/appc/spec/schema/types/isolator_unix.go
generated
vendored
83
vendor/github.com/appc/spec/schema/types/isolator_unix.go
generated
vendored
@ -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
|
||||
}
|
206
vendor/github.com/appc/spec/schema/types/labels.go
generated
vendored
206
vendor/github.com/appc/spec/schema/types/labels.go
generated
vendored
@ -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
|
||||
}
|
92
vendor/github.com/appc/spec/schema/types/mountpoint.go
generated
vendored
92
vendor/github.com/appc/spec/schema/types/mountpoint.go
generated
vendored
@ -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
|
||||
}
|
147
vendor/github.com/appc/spec/schema/types/port.go
generated
vendored
147
vendor/github.com/appc/spec/schema/types/port.go
generated
vendored
@ -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
|
||||
}
|
32
vendor/github.com/appc/spec/schema/types/resource/BUILD
generated
vendored
32
vendor/github.com/appc/spec/schema/types/resource/BUILD
generated
vendored
@ -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"],
|
||||
)
|
4
vendor/github.com/appc/spec/schema/types/resource/README.md
generated
vendored
4
vendor/github.com/appc/spec/schema/types/resource/README.md
generated
vendored
@ -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.
|
298
vendor/github.com/appc/spec/schema/types/resource/amount.go
generated
vendored
298
vendor/github.com/appc/spec/schema/types/resource/amount.go
generated
vendored
@ -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
|
||||
}
|
327
vendor/github.com/appc/spec/schema/types/resource/math.go
generated
vendored
327
vendor/github.com/appc/spec/schema/types/resource/math.go
generated
vendored
@ -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
|
||||
}
|
768
vendor/github.com/appc/spec/schema/types/resource/quantity.go
generated
vendored
768
vendor/github.com/appc/spec/schema/types/resource/quantity.go
generated
vendored
@ -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:
|
||||
//
|
||||
// <quantity> ::= <signedNumber><suffix>
|
||||
// (Note that <suffix> may be empty, from the "" case in <decimalSI>.)
|
||||
// <digit> ::= 0 | 1 | ... | 9
|
||||
// <digits> ::= <digit> | <digit><digits>
|
||||
// <number> ::= <digits> | <digits>.<digits> | <digits>. | .<digits>
|
||||
// <sign> ::= "+" | "-"
|
||||
// <signedNumber> ::= <number> | <sign><number>
|
||||
// <suffix> ::= <binarySI> | <decimalExponent> | <decimalSI>
|
||||
// <binarySI> ::= Ki | Mi | Gi | Ti | Pi | Ei
|
||||
// (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)
|
||||
// <decimalSI> ::= m | "" | k | M | G | T | P | E
|
||||
// (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)
|
||||
// <decimalExponent> ::= "e" <signedNumber> | "E" <signedNumber>
|
||||
//
|
||||
// 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}
|
||||
}
|
95
vendor/github.com/appc/spec/schema/types/resource/scale_int.go
generated
vendored
95
vendor/github.com/appc/spec/schema/types/resource/scale_int.go
generated
vendored
@ -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()
|
||||
}
|
198
vendor/github.com/appc/spec/schema/types/resource/suffix.go
generated
vendored
198
vendor/github.com/appc/spec/schema/types/resource/suffix.go
generated
vendored
@ -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
|
||||
}
|
91
vendor/github.com/appc/spec/schema/types/semver.go
generated
vendored
91
vendor/github.com/appc/spec/schema/types/semver.go
generated
vendored
@ -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())
|
||||
}
|
71
vendor/github.com/appc/spec/schema/types/url.go
generated
vendored
71
vendor/github.com/appc/spec/schema/types/url.go
generated
vendored
@ -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())
|
||||
}
|
18
vendor/github.com/appc/spec/schema/types/user_annotations.go
generated
vendored
18
vendor/github.com/appc/spec/schema/types/user_annotations.go
generated
vendored
@ -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
|
18
vendor/github.com/appc/spec/schema/types/user_labels.go
generated
vendored
18
vendor/github.com/appc/spec/schema/types/user_labels.go
generated
vendored
@ -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
|
92
vendor/github.com/appc/spec/schema/types/uuid.go
generated
vendored
92
vendor/github.com/appc/spec/schema/types/uuid.go
generated
vendored
@ -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())
|
||||
}
|
249
vendor/github.com/appc/spec/schema/types/volume.go
generated
vendored
249
vendor/github.com/appc/spec/schema/types/volume.go
generated
vendored
@ -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
|
||||
}
|
||||
}
|
||||
}
|
39
vendor/github.com/appc/spec/schema/version.go
generated
vendored
39
vendor/github.com/appc/spec/schema/version.go
generated
vendored
@ -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
|
||||
}
|
27
vendor/github.com/coreos/go-systemd/unit/BUILD
generated
vendored
27
vendor/github.com/coreos/go-systemd/unit/BUILD
generated
vendored
@ -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"],
|
||||
)
|
276
vendor/github.com/coreos/go-systemd/unit/deserialize.go
generated
vendored
276
vendor/github.com/coreos/go-systemd/unit/deserialize.go
generated
vendored
@ -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 == ';'
|
||||
}
|
116
vendor/github.com/coreos/go-systemd/unit/escape.go
generated
vendored
116
vendor/github.com/coreos/go-systemd/unit/escape.go
generated
vendored
@ -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)
|
||||
}
|
54
vendor/github.com/coreos/go-systemd/unit/option.go
generated
vendored
54
vendor/github.com/coreos/go-systemd/unit/option.go
generated
vendored
@ -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
|
||||
}
|
75
vendor/github.com/coreos/go-systemd/unit/serialize.go
generated
vendored
75
vendor/github.com/coreos/go-systemd/unit/serialize.go
generated
vendored
@ -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)
|
||||
}
|
8
vendor/go4.org/AUTHORS
generated
vendored
8
vendor/go4.org/AUTHORS
generated
vendored
@ -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 <mathieu.lonjaret@gmail.com>
|
||||
Daniel Theophanes <kardianos@gmail.com>
|
||||
Google
|
202
vendor/go4.org/LICENSE
generated
vendored
202
vendor/go4.org/LICENSE
generated
vendored
@ -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.
|
||||
|
22
vendor/go4.org/errorutil/BUILD
generated
vendored
22
vendor/go4.org/errorutil/BUILD
generated
vendored
@ -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"],
|
||||
)
|
58
vendor/go4.org/errorutil/highlight.go
generated
vendored
58
vendor/go4.org/errorutil/highlight.go
generated
vendored
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user