Commit 011d35a4 authored by Dr. Stefan Schimanski's avatar Dr. Stefan Schimanski Committed by Dr. Stefan Schimanski

bump(github.com/appc/spec): fc380db5fc13c6dd71a5b0bf2af0d182865d1b1d

parent bc6fdd92
......@@ -115,18 +115,23 @@
},
{
"ImportPath": "github.com/appc/spec/schema",
"Comment": "v0.8.1-6-gab50d12",
"Rev": "ab50d12e88f57788bf84b83fef2be236eb1fcc0b"
"Comment": "v0.8.9-17-gfc380db",
"Rev": "fc380db5fc13c6dd71a5b0bf2af0d182865d1b1d"
},
{
"ImportPath": "github.com/appc/spec/schema/common",
"Comment": "v0.8.1-6-gab50d12",
"Rev": "ab50d12e88f57788bf84b83fef2be236eb1fcc0b"
"Comment": "v0.8.9-17-gfc380db",
"Rev": "fc380db5fc13c6dd71a5b0bf2af0d182865d1b1d"
},
{
"ImportPath": "github.com/appc/spec/schema/types",
"Comment": "v0.8.1-6-gab50d12",
"Rev": "ab50d12e88f57788bf84b83fef2be236eb1fcc0b"
"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",
......
......@@ -28,13 +28,15 @@ import (
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"`
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
......@@ -135,9 +137,12 @@ func (al AppList) Get(name types.ACName) *RuntimeApp {
// 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"`
Volume types.ACName `json:"volume"`
Path string `json:"path"`
AppVolume *types.Volume `json:"appVolume,omitempty"`
}
func (r Mount) assertValid() error {
......
......@@ -22,16 +22,18 @@ import (
)
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"`
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
......@@ -86,5 +88,8 @@ func (a *App) assertValid() error {
if err := a.Environment.assertValid(); err != nil {
return err
}
if err := a.Isolators.assertValid(); err != nil {
return err
}
return nil
}
......@@ -16,10 +16,19 @@ 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() {
......@@ -40,6 +49,33 @@ func AddIsolatorName(n ACIdentifier, ns map[ACIdentifier]struct{}) {
// 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
......@@ -52,6 +88,22 @@ func (is *Isolators) GetByName(name ACIdentifier) *Isolator {
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.
......@@ -69,8 +121,17 @@ func (is *Isolators) Unrecognized() Isolators {
// 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
......
......@@ -19,7 +19,7 @@ import (
"errors"
"fmt"
"k8s.io/apimachinery/pkg/api/resource"
"github.com/appc/spec/schema/types/resource"
)
var (
......@@ -85,6 +85,15 @@ 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
}
......
// 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
}
......@@ -21,7 +21,7 @@ import (
)
var ValidOSArch = map[string][]string{
"linux": {"amd64", "i386", "aarch64", "aarch64_be", "armv6l", "armv7l", "armv7b"},
"linux": {"amd64", "i386", "aarch64", "aarch64_be", "armv6l", "armv7l", "armv7b", "ppc64", "ppc64le", "s390x"},
"freebsd": {"amd64", "i386", "arm"},
"darwin": {"x86_64", "i386"},
}
......@@ -35,6 +35,17 @@ type Label struct {
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 {
......@@ -132,3 +143,64 @@ func LabelsFromMap(labelsMap map[ACIdentifier]string) (Labels, error) {
}
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
}
......@@ -23,6 +23,7 @@ import (
"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"`
......
......@@ -18,12 +18,15 @@ 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"`
......@@ -32,9 +35,14 @@ type Port struct {
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
......
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.
/*
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
}
/*
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
}
/*
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()
}
/*
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
}
// 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
// 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
......@@ -40,8 +40,9 @@ type Volume struct {
// currently used only by "host"
// TODO(jonboulle): factor out?
Source string `json:"source,omitempty"`
ReadOnly *bool `json:"readOnly,omitempty"`
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"`
......@@ -128,6 +129,10 @@ func (v Volume) String() string {
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 {
......@@ -149,10 +154,8 @@ func (v Volume) String() string {
// VolumeFromString takes a command line volume parameter and returns a volume
//
// Example volume parameters:
// database,kind=host,source=/tmp,readOnly=true
// database,kind=host,source=/tmp,readOnly=true,recursive=true
func VolumeFromString(vp string) (*Volume, error) {
var vol Volume
vp = "name=" + vp
vpQuery, err := common.MakeQueryString(vp)
if err != nil {
......@@ -163,7 +166,12 @@ func VolumeFromString(vp string) (*Volume, error) {
if err != nil {
return nil, err
}
for key, val := range v {
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)
......@@ -186,6 +194,12 @@ func VolumeFromString(vp string) (*Volume, error) {
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":
......@@ -207,8 +221,7 @@ func VolumeFromString(vp string) (*Volume, error) {
maybeSetDefaults(&vol)
err = vol.assertValid()
if err != nil {
if err := vol.assertValid(); err != nil {
return nil, err
}
......
......@@ -22,7 +22,7 @@ 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.1+git"
version string = "0.8.9+git"
)
var (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment