Fix issues when specifying resources/scales during updating/creation process (#970)
This commit is contained in:
@@ -361,23 +361,23 @@ func (deploy *NewDeploy) getResources(env *crd.Environment, fn *crd.Function) ap
|
||||
resources.Limits = make(map[apiv1.ResourceName]resource.Quantity)
|
||||
}
|
||||
// Only override the once specified at function, rest default to values from env.
|
||||
_, ok := fn.Spec.Resources.Requests[apiv1.ResourceCPU]
|
||||
if ok {
|
||||
val, ok := fn.Spec.Resources.Requests[apiv1.ResourceCPU]
|
||||
if ok && !val.IsZero() {
|
||||
resources.Requests[apiv1.ResourceCPU] = fn.Spec.Resources.Requests[apiv1.ResourceCPU]
|
||||
}
|
||||
|
||||
_, ok = fn.Spec.Resources.Requests[apiv1.ResourceMemory]
|
||||
if ok {
|
||||
val, ok = fn.Spec.Resources.Requests[apiv1.ResourceMemory]
|
||||
if ok && !val.IsZero() {
|
||||
resources.Requests[apiv1.ResourceMemory] = fn.Spec.Resources.Requests[apiv1.ResourceMemory]
|
||||
}
|
||||
|
||||
_, ok = fn.Spec.Resources.Limits[apiv1.ResourceCPU]
|
||||
if ok {
|
||||
val, ok = fn.Spec.Resources.Limits[apiv1.ResourceCPU]
|
||||
if ok && !val.IsZero() {
|
||||
resources.Limits[apiv1.ResourceCPU] = fn.Spec.Resources.Limits[apiv1.ResourceCPU]
|
||||
}
|
||||
|
||||
_, ok = fn.Spec.Resources.Limits[apiv1.ResourceMemory]
|
||||
if ok {
|
||||
val, ok = fn.Spec.Resources.Limits[apiv1.ResourceMemory]
|
||||
if ok && !val.IsZero() {
|
||||
resources.Limits[apiv1.ResourceMemory] = fn.Spec.Resources.Limits[apiv1.ResourceMemory]
|
||||
}
|
||||
|
||||
|
||||
@@ -218,6 +218,10 @@ func envUpdate(c *cli.Context) error {
|
||||
|
||||
env.Spec.AllowAccessToExternalNetwork = envExternalNetwork
|
||||
|
||||
if c.IsSet("mincpu") || c.IsSet("maxcpu") || c.IsSet("minmemory") || c.IsSet("maxmemory") || c.IsSet("minscale") || c.IsSet("maxscale") {
|
||||
log.Fatal("Updating resource limits/requests for existing environments is currently unsupported; re-create the environment instead.")
|
||||
}
|
||||
|
||||
_, err = client.EnvironmentUpdate(env)
|
||||
util.CheckErr(err, "update environment")
|
||||
|
||||
@@ -295,6 +299,7 @@ func getResourceReq(c *cli.Context, resources v1.ResourceRequirements) v1.Resour
|
||||
}
|
||||
|
||||
var limitResources map[v1.ResourceName]resource.Quantity
|
||||
|
||||
if len(resources.Limits) == 0 {
|
||||
limitResources = make(map[v1.ResourceName]resource.Quantity)
|
||||
} else {
|
||||
@@ -319,9 +324,28 @@ func getResourceReq(c *cli.Context, resources v1.ResourceRequirements) v1.Resour
|
||||
limitResources[v1.ResourceMemory] = memLimit
|
||||
}
|
||||
|
||||
limitCPU := limitResources[v1.ResourceCPU]
|
||||
requestCPU := requestResources[v1.ResourceCPU]
|
||||
|
||||
if limitCPU.IsZero() && !requestCPU.IsZero() {
|
||||
limitResources[v1.ResourceCPU] = requestCPU
|
||||
} else if limitCPU.Cmp(requestCPU) < 0 {
|
||||
log.Fatal(fmt.Sprintf("MinCPU (%v) cannot be greater than MaxCPU (%v)", requestCPU.String(), limitCPU.String()))
|
||||
}
|
||||
|
||||
limitMem := limitResources[v1.ResourceMemory]
|
||||
requestMem := requestResources[v1.ResourceMemory]
|
||||
|
||||
if limitMem.IsZero() && !requestMem.IsZero() {
|
||||
limitResources[v1.ResourceMemory] = requestMem
|
||||
} else if limitMem.Cmp(requestMem) < 0 {
|
||||
log.Fatal(fmt.Sprintf("MinMemory (%v) cannot be greater than MaxMemory (%v)", requestMem.String(), limitMem.String()))
|
||||
}
|
||||
|
||||
resources = v1.ResourceRequirements{
|
||||
Requests: requestResources,
|
||||
Limits: limitResources,
|
||||
}
|
||||
|
||||
return resources
|
||||
}
|
||||
|
||||
+98
-85
@@ -41,6 +41,11 @@ import (
|
||||
"github.com/fission/fission/fission/util"
|
||||
)
|
||||
|
||||
const (
|
||||
DEFAULT_MIN_SCALE = 1
|
||||
DEFAULT_TARGET_CPU_PERCENTAGE = 80
|
||||
)
|
||||
|
||||
func printPodLogs(c *cli.Context) error {
|
||||
fnName := c.String("name")
|
||||
if len(fnName) == 0 {
|
||||
@@ -69,40 +74,91 @@ func printPodLogs(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getInvokeStrategy(minScale int, maxScale int, executorType string, targetcpu int) fission.InvokeStrategy {
|
||||
func getInvokeStrategy(c *cli.Context, existingInvokeStrategy *fission.InvokeStrategy) (strategy *fission.InvokeStrategy, err error) {
|
||||
|
||||
if maxScale == 0 {
|
||||
maxScale = 1
|
||||
}
|
||||
var fnExecutor, newFnExecutor fission.ExecutorType
|
||||
|
||||
if minScale > maxScale {
|
||||
log.Fatal("Maxscale must be higher than or equal to minscale")
|
||||
}
|
||||
|
||||
var fnExecutor fission.ExecutorType
|
||||
switch executorType {
|
||||
switch c.String("executortype") {
|
||||
case "":
|
||||
fnExecutor = fission.ExecutorTypePoolmgr
|
||||
fallthrough
|
||||
case fission.ExecutorTypePoolmgr:
|
||||
fnExecutor = fission.ExecutorTypePoolmgr
|
||||
newFnExecutor = fission.ExecutorTypePoolmgr
|
||||
case fission.ExecutorTypeNewdeploy:
|
||||
fnExecutor = fission.ExecutorTypeNewdeploy
|
||||
newFnExecutor = fission.ExecutorTypeNewdeploy
|
||||
default:
|
||||
log.Fatal("Executor type must be one of 'poolmgr' or 'newdeploy', defaults to 'poolmgr'")
|
||||
return nil, errors.New("Executor type must be one of 'poolmgr' or 'newdeploy', defaults to 'poolmgr'")
|
||||
}
|
||||
|
||||
// Right now a simple single case strategy implementation
|
||||
// This will potentially get more sophisticated once we have more strategies in place
|
||||
strategy := fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fnExecutor,
|
||||
MinScale: minScale,
|
||||
MaxScale: maxScale,
|
||||
TargetCPUPercent: targetcpu,
|
||||
},
|
||||
if existingInvokeStrategy != nil {
|
||||
fnExecutor = existingInvokeStrategy.ExecutionStrategy.ExecutorType
|
||||
|
||||
// override the executor type if user specified a new executor type
|
||||
if c.IsSet("executortype") {
|
||||
fnExecutor = newFnExecutor
|
||||
}
|
||||
} else {
|
||||
fnExecutor = newFnExecutor
|
||||
}
|
||||
return strategy
|
||||
|
||||
if fnExecutor == fission.ExecutorTypePoolmgr {
|
||||
if c.IsSet("targetcpu") || c.IsSet("minscale") || c.IsSet("maxscale") {
|
||||
log.Fatal("To set target CPU or min/max scale for function, please specify \"--executortype newdeploy\"")
|
||||
}
|
||||
|
||||
if c.IsSet("mincpu") || c.IsSet("maxcpu") || c.IsSet("minmemory") || c.IsSet("maxmemory") {
|
||||
log.Warn("To limit CPU/Memory for function with executor type \"poolmgr\", please specify resources limits when creating environment")
|
||||
}
|
||||
strategy = &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypePoolmgr,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// set default value
|
||||
targetCPU := DEFAULT_TARGET_CPU_PERCENTAGE
|
||||
minScale := DEFAULT_MIN_SCALE
|
||||
maxScale := minScale
|
||||
|
||||
if existingInvokeStrategy != nil && existingInvokeStrategy.ExecutionStrategy.ExecutorType == fission.ExecutorTypeNewdeploy {
|
||||
minScale = existingInvokeStrategy.ExecutionStrategy.MinScale
|
||||
maxScale = existingInvokeStrategy.ExecutionStrategy.MaxScale
|
||||
targetCPU = existingInvokeStrategy.ExecutionStrategy.TargetCPUPercent
|
||||
}
|
||||
|
||||
if c.IsSet("targetcpu") {
|
||||
targetCPU = getTargetCPU(c)
|
||||
}
|
||||
|
||||
if c.IsSet("minscale") {
|
||||
minScale = c.Int("minscale")
|
||||
}
|
||||
|
||||
if c.IsSet("maxscale") {
|
||||
maxScale = c.Int("maxscale")
|
||||
if maxScale <= 0 {
|
||||
return nil, errors.New("Maxscale must be greater than 0")
|
||||
}
|
||||
}
|
||||
|
||||
if minScale > maxScale {
|
||||
return nil, errors.New(fmt.Sprintf("Minscale provided: %v can not be greater than maxscale value %v", minScale, maxScale))
|
||||
}
|
||||
|
||||
// Right now a simple single case strategy implementation
|
||||
// This will potentially get more sophisticated once we have more strategies in place
|
||||
strategy = &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fnExecutor,
|
||||
MinScale: minScale,
|
||||
MaxScale: maxScale,
|
||||
TargetCPUPercent: targetCPU,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return strategy, nil
|
||||
}
|
||||
|
||||
func getTargetCPU(c *cli.Context) int {
|
||||
@@ -113,7 +169,7 @@ func getTargetCPU(c *cli.Context) int {
|
||||
log.Fatal("TargetCPU must be a value between 1 - 100")
|
||||
}
|
||||
} else {
|
||||
targetCPU = 80
|
||||
targetCPU = DEFAULT_TARGET_CPU_PERCENTAGE
|
||||
}
|
||||
return targetCPU
|
||||
}
|
||||
@@ -150,12 +206,17 @@ func fnCreate(c *cli.Context) error {
|
||||
entrypoint := c.String("entrypoint")
|
||||
pkgName := c.String("pkg")
|
||||
|
||||
var pkgMetadata *metav1.ObjectMeta
|
||||
var envName string
|
||||
|
||||
secretName := c.String("secret")
|
||||
cfgMapName := c.String("configmap")
|
||||
|
||||
invokeStrategy, err := getInvokeStrategy(c, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
resourceReq := getResourceReq(c, apiv1.ResourceRequirements{})
|
||||
|
||||
var pkgMetadata *metav1.ObjectMeta
|
||||
var envName string
|
||||
if len(pkgName) > 0 {
|
||||
// use existing package
|
||||
pkg, err := client.PackageGet(&metav1.ObjectMeta{
|
||||
@@ -209,13 +270,6 @@ func fnCreate(c *cli.Context) error {
|
||||
fmt.Printf("package '%v' created\n", pkgMetadata.Name)
|
||||
}
|
||||
|
||||
invokeStrategy := getInvokeStrategy(c.Int("minscale"), c.Int("maxscale"), c.String("executortype"), getTargetCPU(c))
|
||||
resourceReq := getResourceReq(c, apiv1.ResourceRequirements{})
|
||||
if (c.IsSet("mincpu") || c.IsSet("maxcpu") || c.IsSet("minmemory") || c.IsSet("maxmemory")) &&
|
||||
invokeStrategy.ExecutionStrategy.ExecutorType == fission.ExecutorTypePoolmgr {
|
||||
log.Warn("CPU/Memory specified for function with pool manager executor will be ignored in favor of resources specified at environment")
|
||||
}
|
||||
|
||||
var secrets []fission.SecretReference
|
||||
var cfgmaps []fission.ConfigMapReference
|
||||
|
||||
@@ -274,7 +328,7 @@ func fnCreate(c *cli.Context) error {
|
||||
Secrets: secrets,
|
||||
ConfigMaps: cfgmaps,
|
||||
Resources: resourceReq,
|
||||
InvokeStrategy: invokeStrategy,
|
||||
InvokeStrategy: *invokeStrategy,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -486,6 +540,13 @@ func fnUpdate(c *cli.Context) error {
|
||||
pkgName = function.Spec.Package.PackageRef.Name
|
||||
}
|
||||
|
||||
strategy, err := getInvokeStrategy(c, &function.Spec.InvokeStrategy)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
function.Spec.InvokeStrategy = *strategy
|
||||
function.Spec.Resources = getResourceReq(c, function.Spec.Resources)
|
||||
|
||||
pkg, err := client.PackageGet(&metav1.ObjectMeta{
|
||||
Namespace: fnNamespace,
|
||||
Name: pkgName,
|
||||
@@ -534,54 +595,6 @@ func fnUpdate(c *cli.Context) error {
|
||||
function.Spec.Environment.Namespace = pkg.Spec.Environment.Namespace
|
||||
}
|
||||
|
||||
function.Spec.Resources = getResourceReq(c, function.Spec.Resources)
|
||||
|
||||
if c.IsSet("targetcpu") {
|
||||
function.Spec.InvokeStrategy.ExecutionStrategy.TargetCPUPercent = getTargetCPU(c)
|
||||
}
|
||||
|
||||
if c.IsSet("minscale") {
|
||||
minscale := c.Int("minscale")
|
||||
maxscale := c.Int("maxscale")
|
||||
if c.IsSet("maxscale") && minscale > c.Int("maxscale") {
|
||||
log.Fatal(fmt.Sprintf("Minscale's value %v can not be greater than maxscale value %v", minscale, maxscale))
|
||||
}
|
||||
if function.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType != fission.ExecutorTypePoolmgr &&
|
||||
minscale > function.Spec.InvokeStrategy.ExecutionStrategy.MaxScale {
|
||||
log.Fatal(fmt.Sprintf("Minscale provided: %v can not be greater than maxscale of existing function: %v", minscale,
|
||||
function.Spec.InvokeStrategy.ExecutionStrategy.MaxScale))
|
||||
}
|
||||
function.Spec.InvokeStrategy.ExecutionStrategy.MinScale = minscale
|
||||
}
|
||||
|
||||
if c.IsSet("maxscale") {
|
||||
maxscale := c.Int("maxscale")
|
||||
if maxscale < function.Spec.InvokeStrategy.ExecutionStrategy.MinScale {
|
||||
log.Fatal(fmt.Sprintf("Function's minscale: %v can not be greater than maxscale provided: %v",
|
||||
function.Spec.InvokeStrategy.ExecutionStrategy.MinScale, maxscale))
|
||||
}
|
||||
function.Spec.InvokeStrategy.ExecutionStrategy.MaxScale = maxscale
|
||||
}
|
||||
|
||||
if c.IsSet("executortype") {
|
||||
var fnExecutor fission.ExecutorType
|
||||
switch c.String("executortype") {
|
||||
case "":
|
||||
fnExecutor = fission.ExecutorTypePoolmgr
|
||||
case fission.ExecutorTypePoolmgr:
|
||||
fnExecutor = fission.ExecutorTypePoolmgr
|
||||
case fission.ExecutorTypeNewdeploy:
|
||||
fnExecutor = fission.ExecutorTypeNewdeploy
|
||||
default:
|
||||
log.Fatal("Executor type must be one of 'poolmgr' or 'newdeploy', defaults to 'poolmgr'")
|
||||
}
|
||||
if (c.IsSet("mincpu") || c.IsSet("maxcpu") || c.IsSet("minmemory") || c.IsSet("maxmemory")) &&
|
||||
fnExecutor == fission.ExecutorTypePoolmgr {
|
||||
log.Warn("CPU/Memory specified for function with pool manager executor will be ignored in favor of resources specified at environment")
|
||||
}
|
||||
function.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType = fnExecutor
|
||||
}
|
||||
|
||||
_, err = client.FunctionUpdate(function)
|
||||
util.CheckErr(err, "update function")
|
||||
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/fission/fission"
|
||||
)
|
||||
|
||||
func TestGetInvokeStrategy(t *testing.T) {
|
||||
cases := []struct {
|
||||
testArgs map[string]string
|
||||
existingInvokeStrategy *fission.InvokeStrategy
|
||||
expectedResult *fission.InvokeStrategy
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
// case: use default executor poolmgr
|
||||
testArgs: map[string]string{},
|
||||
existingInvokeStrategy: nil,
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypePoolmgr,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: executor type set to poolmgr
|
||||
testArgs: map[string]string{"executortype": fission.ExecutorTypePoolmgr},
|
||||
existingInvokeStrategy: nil,
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypePoolmgr,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: executor type set to newdeploy
|
||||
testArgs: map[string]string{"executortype": fission.ExecutorTypeNewdeploy},
|
||||
existingInvokeStrategy: nil,
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: DEFAULT_MIN_SCALE,
|
||||
MaxScale: DEFAULT_MIN_SCALE,
|
||||
TargetCPUPercent: DEFAULT_TARGET_CPU_PERCENTAGE,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: executor type change from poolmgr to newdeploy
|
||||
testArgs: map[string]string{"executortype": fission.ExecutorTypeNewdeploy},
|
||||
existingInvokeStrategy: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypePoolmgr,
|
||||
},
|
||||
},
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: DEFAULT_MIN_SCALE,
|
||||
MaxScale: DEFAULT_MIN_SCALE,
|
||||
TargetCPUPercent: DEFAULT_TARGET_CPU_PERCENTAGE,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: executor type change from newdeploy to poolmgr
|
||||
testArgs: map[string]string{"executortype": fission.ExecutorTypePoolmgr},
|
||||
existingInvokeStrategy: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: DEFAULT_MIN_SCALE,
|
||||
MaxScale: DEFAULT_MIN_SCALE,
|
||||
TargetCPUPercent: DEFAULT_TARGET_CPU_PERCENTAGE,
|
||||
},
|
||||
},
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypePoolmgr,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: minscale < maxscale
|
||||
testArgs: map[string]string{
|
||||
"executortype": fission.ExecutorTypeNewdeploy,
|
||||
"minscale": "2",
|
||||
"maxscale": "3",
|
||||
},
|
||||
existingInvokeStrategy: nil,
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: 2,
|
||||
MaxScale: 3,
|
||||
TargetCPUPercent: DEFAULT_TARGET_CPU_PERCENTAGE,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: minscale > maxscale
|
||||
testArgs: map[string]string{
|
||||
"executortype": fission.ExecutorTypeNewdeploy,
|
||||
"minscale": "5",
|
||||
"maxscale": "3",
|
||||
},
|
||||
existingInvokeStrategy: nil,
|
||||
expectedResult: nil,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
// case: maxscale not specified
|
||||
testArgs: map[string]string{
|
||||
"executortype": fission.ExecutorTypeNewdeploy,
|
||||
"minscale": "5",
|
||||
},
|
||||
existingInvokeStrategy: nil,
|
||||
expectedResult: nil,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
// case: minscale not specified
|
||||
testArgs: map[string]string{
|
||||
"executortype": fission.ExecutorTypeNewdeploy,
|
||||
"maxscale": "3",
|
||||
},
|
||||
existingInvokeStrategy: nil,
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: DEFAULT_MIN_SCALE,
|
||||
MaxScale: 3,
|
||||
TargetCPUPercent: DEFAULT_TARGET_CPU_PERCENTAGE,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: maxscale set to 0
|
||||
testArgs: map[string]string{
|
||||
"executortype": fission.ExecutorTypeNewdeploy,
|
||||
"maxscale": "0",
|
||||
},
|
||||
existingInvokeStrategy: nil,
|
||||
expectedResult: nil,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
// case: maxscale set to 9 when existing is 5
|
||||
testArgs: map[string]string{
|
||||
"executortype": fission.ExecutorTypeNewdeploy,
|
||||
"maxscale": "9",
|
||||
},
|
||||
existingInvokeStrategy: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: 2,
|
||||
MaxScale: 5,
|
||||
TargetCPUPercent: DEFAULT_TARGET_CPU_PERCENTAGE,
|
||||
},
|
||||
},
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: 2,
|
||||
MaxScale: 9,
|
||||
TargetCPUPercent: DEFAULT_TARGET_CPU_PERCENTAGE,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: change nothing for existing strategy
|
||||
testArgs: map[string]string{
|
||||
"executortype": fission.ExecutorTypeNewdeploy,
|
||||
},
|
||||
existingInvokeStrategy: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: 2,
|
||||
MaxScale: 5,
|
||||
TargetCPUPercent: DEFAULT_TARGET_CPU_PERCENTAGE,
|
||||
},
|
||||
},
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: 2,
|
||||
MaxScale: 5,
|
||||
TargetCPUPercent: DEFAULT_TARGET_CPU_PERCENTAGE,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: set target cpu percentage
|
||||
testArgs: map[string]string{
|
||||
"executortype": fission.ExecutorTypeNewdeploy,
|
||||
"targetcpu": "50",
|
||||
},
|
||||
existingInvokeStrategy: nil,
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: DEFAULT_MIN_SCALE,
|
||||
MaxScale: DEFAULT_MIN_SCALE,
|
||||
TargetCPUPercent: 50,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
// case: change target cpu percentage
|
||||
testArgs: map[string]string{
|
||||
"executortype": fission.ExecutorTypeNewdeploy,
|
||||
"targetcpu": "20",
|
||||
},
|
||||
existingInvokeStrategy: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: 2,
|
||||
MaxScale: 5,
|
||||
TargetCPUPercent: 88,
|
||||
},
|
||||
},
|
||||
expectedResult: &fission.InvokeStrategy{
|
||||
StrategyType: fission.StrategyTypeExecution,
|
||||
ExecutionStrategy: fission.ExecutionStrategy{
|
||||
ExecutorType: fission.ExecutorTypeNewdeploy,
|
||||
MinScale: 2,
|
||||
MaxScale: 5,
|
||||
TargetCPUPercent: 20,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
fmt.Printf("=== Test Case %v ===\n", i)
|
||||
|
||||
app := newCliApp()
|
||||
set := flag.NewFlagSet("test-cmd", 0)
|
||||
ctx := cli.NewContext(app, set, nil)
|
||||
|
||||
for k, v := range c.testArgs {
|
||||
set.String(k, v, "")
|
||||
ctx.Set(k, v)
|
||||
}
|
||||
|
||||
strategy, err := getInvokeStrategy(ctx, c.existingInvokeStrategy)
|
||||
if c.expectError {
|
||||
assert.NotNil(t, err)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
} else {
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, strategy.Validate(), fmt.Sprintf("Failed at test case %v", i))
|
||||
assert.Equal(t, *c.expectedResult, *strategy)
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -27,12 +27,12 @@ var (
|
||||
)
|
||||
|
||||
func Fatal(msg interface{}) {
|
||||
os.Stderr.WriteString(fmt.Sprintf("%v\n", msg))
|
||||
os.Stderr.WriteString(fmt.Sprintf("Fatal error: %v\n", msg))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func Warn(msg interface{}) {
|
||||
os.Stderr.WriteString(fmt.Sprintf("[WARNING] %v\n", msg))
|
||||
os.Stderr.WriteString(fmt.Sprintf("Warning: %v\n", msg))
|
||||
}
|
||||
|
||||
func Info(msg interface{}) {
|
||||
|
||||
+13
-9
@@ -38,6 +38,10 @@ func cliHook(c *cli.Context) error {
|
||||
}
|
||||
|
||||
func main() {
|
||||
newCliApp().Run(os.Args)
|
||||
}
|
||||
|
||||
func newCliApp() *cli.App {
|
||||
app := cli.NewApp()
|
||||
app.Name = "fission"
|
||||
app.Usage = "Serverless functions for Kubernetes"
|
||||
@@ -74,13 +78,13 @@ func main() {
|
||||
htUrlFlag := cli.StringFlag{Name: "url", Usage: "URL pattern (See gorilla/mux supported patterns)"}
|
||||
|
||||
// Resource & scale related flags (Used in env and function)
|
||||
minCpu := cli.StringFlag{Name: "mincpu", Usage: "Minimum CPU to be assigned to pod (In millicore, minimum 1)"}
|
||||
maxCpu := cli.StringFlag{Name: "maxcpu", Usage: "Maximum CPU to be assigned to pod (In millicore, minimum 1)"}
|
||||
minMem := cli.StringFlag{Name: "minmemory", Usage: "Minimum memory to be assigned to pod (In megabyte)"}
|
||||
maxMem := cli.StringFlag{Name: "maxmemory", Usage: "Maximum memory to be assigned to pod (In megabyte)"}
|
||||
minScale := cli.StringFlag{Name: "minscale", Usage: "Minimum number of pods (Uses resource inputs to configure HPA)"}
|
||||
maxScale := cli.StringFlag{Name: "maxscale", Usage: "Maximum number of pods (Uses resource inputs to configure HPA)"}
|
||||
targetcpu := cli.IntFlag{Name: "targetcpu", Value: 80, Usage: "Target average CPU usage percentage across pods for scaling"}
|
||||
minCpu := cli.IntFlag{Name: "mincpu", Usage: "Minimum CPU to be assigned to pod (In millicore, minimum 1)"}
|
||||
maxCpu := cli.IntFlag{Name: "maxcpu", Usage: "Maximum CPU to be assigned to pod (In millicore, minimum 1)"}
|
||||
minMem := cli.IntFlag{Name: "minmemory", Usage: "Minimum memory to be assigned to pod (In megabyte)"}
|
||||
maxMem := cli.IntFlag{Name: "maxmemory", Usage: "Maximum memory to be assigned to pod (In megabyte)"}
|
||||
minScale := cli.IntFlag{Name: "minscale", Usage: "Minimum number of pods (Uses resource inputs to configure HPA)"}
|
||||
maxScale := cli.IntFlag{Name: "maxscale", Usage: "Maximum number of pods (Uses resource inputs to configure HPA)"}
|
||||
targetcpu := cli.IntFlag{Name: "targetcpu", Usage: "Target average CPU usage percentage across pods for scaling"}
|
||||
|
||||
// functions
|
||||
fnNameFlag := cli.StringFlag{Name: "name", Usage: "function name"}
|
||||
@@ -102,7 +106,7 @@ func main() {
|
||||
fnCfgMapFlag := cli.StringFlag{Name: "configmap", Usage: "function access to configmap, should be present in the same namespace as the function"}
|
||||
fnLogCountFlag := cli.StringFlag{Name: "recordcount", Usage: "the n most recent log records"}
|
||||
fnForceFlag := cli.BoolFlag{Name: "force", Usage: "Force update a package even if it is used by one or more functions"}
|
||||
fnExecutorTypeFlag := cli.StringFlag{Name: "executortype", Usage: "Executor type for execution; one of 'poolmgr', 'newdeploy' defaults to 'poolmgr'"}
|
||||
fnExecutorTypeFlag := cli.StringFlag{Name: "executortype", Value: fission.ExecutorTypePoolmgr, Usage: "Executor type for execution; one of 'poolmgr', 'newdeploy' defaults to 'poolmgr'"}
|
||||
|
||||
fnSubcommands := []cli.Command{
|
||||
{Name: "create", Usage: "Create new function (and optionally, an HTTP route to it)", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag, fnEnvNameFlag, envNamespaceFlag, specSaveFlag, fnCodeFlag, fnSrcArchiveFlag, fnDeployArchiveFlag, fnEntryPointFlag, fnBuildCmdFlag, fnPkgNameFlag, htUrlFlag, htMethodFlag, minCpu, maxCpu, minMem, maxMem, minScale, maxScale, fnExecutorTypeFlag, targetcpu, fnCfgMapFlag, fnSecretFlag}, Action: fnCreate},
|
||||
@@ -309,7 +313,7 @@ func main() {
|
||||
}
|
||||
app.Before = cliHook
|
||||
app.CommandNotFound = handleCommandNotFound
|
||||
app.Run(os.Args)
|
||||
return app
|
||||
}
|
||||
|
||||
func handleCommandNotFound(ctx *cli.Context, subCommand string) {
|
||||
|
||||
@@ -329,16 +329,22 @@ func (es ExecutionStrategy) Validate() error {
|
||||
result = multierror.Append(result, MakeValidationErr(ErrorUnsupportedType, "ExecutionStrategy.ExecutorType", es.ExecutorType, "not a valid executor type"))
|
||||
}
|
||||
|
||||
if es.MinScale < 0 {
|
||||
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "ExecutionStrategy.MinScale", es.MinScale, "minimum scale must be greater or equal to 0"))
|
||||
}
|
||||
if es.ExecutorType == ExecutorTypeNewdeploy {
|
||||
if es.MinScale < 0 {
|
||||
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "ExecutionStrategy.MinScale", es.MinScale, "minimum scale must be greater or equal to 0"))
|
||||
}
|
||||
|
||||
if es.MaxScale < es.MinScale {
|
||||
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "ExecutionStrategy.MaxScale", es.MaxScale, "maximum scale must be greater or equal to minimum scale"))
|
||||
}
|
||||
if es.MaxScale <= 0 {
|
||||
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "ExecutionStrategy.MaxScale", es.MaxScale, "maximum scale must be greater than 0"))
|
||||
}
|
||||
|
||||
if es.TargetCPUPercent <= 0 || es.TargetCPUPercent > 100 {
|
||||
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "ExecutionStrategy.TargetCPUPercent", es.TargetCPUPercent, "TargetCPUPercent must be a value between 1 - 100"))
|
||||
if es.MaxScale < es.MinScale {
|
||||
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "ExecutionStrategy.MaxScale", es.MaxScale, "maximum scale must be greater or equal to minimum scale"))
|
||||
}
|
||||
|
||||
if es.TargetCPUPercent <= 0 || es.TargetCPUPercent > 100 {
|
||||
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "ExecutionStrategy.TargetCPUPercent", es.TargetCPUPercent, "TargetCPUPercent must be a value between 1 - 100"))
|
||||
}
|
||||
}
|
||||
|
||||
return result.ErrorOrNil()
|
||||
|
||||
Reference in New Issue
Block a user