Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
39d03948
Commit
39d03948
authored
Sep 25, 2014
by
Brendan Burns
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add resource fit predicates.
parent
88bf01b0
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
472 additions
and
2 deletions
+472
-2
types.go
pkg/api/types.go
+14
-0
types.go
pkg/api/v1beta1/types.go
+13
-0
types.go
pkg/api/v1beta2/types.go
+13
-0
types.go
pkg/api/v1beta3/types.go
+14
-2
doc.go
pkg/resources/doc.go
+18
-0
resources.go
pkg/resources/resources.go
+75
-0
resources_test.go
pkg/resources/resources_test.go
+169
-0
predicates.go
pkg/scheduler/predicates.go
+54
-0
predicates_test.go
pkg/scheduler/predicates_test.go
+102
-0
No files found.
pkg/api/types.go
View file @
39d03948
...
@@ -423,12 +423,26 @@ type EndpointsList struct {
...
@@ -423,12 +423,26 @@ type EndpointsList struct {
func
(
*
EndpointsList
)
IsAnAPIObject
()
{}
func
(
*
EndpointsList
)
IsAnAPIObject
()
{}
// NodeResources represents resources on a Kubernetes system node
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
type
NodeResources
struct
{
// Capacity represents the available resources.
Capacity
ResourceList
`json:"capacity,omitempty" yaml:"capacity,omitempty"`
}
type
ResourceName
string
// TODO Replace this with a more complete "Quantity" struct
type
ResourceList
map
[
ResourceName
]
util
.
IntOrString
// Minion is a worker node in Kubernetenes.
// Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID.
// The name of the minion according to etcd is in JSONBase.ID.
type
Minion
struct
{
type
Minion
struct
{
JSONBase
`json:",inline" yaml:",inline"`
JSONBase
`json:",inline" yaml:",inline"`
// Queried from cloud provider, if available.
// Queried from cloud provider, if available.
HostIP
string
`json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
HostIP
string
`json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
// Resources available on the node
NodeResources
NodeResources
`json:"resources,omitempty" yaml:"resources,omitempty"`
}
}
func
(
*
Minion
)
IsAnAPIObject
()
{}
func
(
*
Minion
)
IsAnAPIObject
()
{}
...
...
pkg/api/v1beta1/types.go
View file @
39d03948
...
@@ -436,12 +436,25 @@ type EndpointsList struct {
...
@@ -436,12 +436,25 @@ type EndpointsList struct {
func
(
*
EndpointsList
)
IsAnAPIObject
()
{}
func
(
*
EndpointsList
)
IsAnAPIObject
()
{}
// NodeResources represents resources on a Kubernetes system node
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
type
NodeResources
struct
{
// Capacity represents the available resources.
Capacity
ResourceList
`json:"capacity,omitempty" yaml:"capacity,omitempty"`
}
type
ResourceName
string
type
ResourceList
map
[
ResourceName
]
util
.
IntOrString
// Minion is a worker node in Kubernetenes.
// Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID.
// The name of the minion according to etcd is in JSONBase.ID.
type
Minion
struct
{
type
Minion
struct
{
JSONBase
`json:",inline" yaml:",inline"`
JSONBase
`json:",inline" yaml:",inline"`
// Queried from cloud provider, if available.
// Queried from cloud provider, if available.
HostIP
string
`json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
HostIP
string
`json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
// Resources available on the node
NodeResources
NodeResources
`json:"resources,omitempty" yaml:"resources,omitempty"`
}
}
func
(
*
Minion
)
IsAnAPIObject
()
{}
func
(
*
Minion
)
IsAnAPIObject
()
{}
...
...
pkg/api/v1beta2/types.go
View file @
39d03948
...
@@ -433,12 +433,25 @@ type EndpointsList struct {
...
@@ -433,12 +433,25 @@ type EndpointsList struct {
func
(
*
EndpointsList
)
IsAnAPIObject
()
{}
func
(
*
EndpointsList
)
IsAnAPIObject
()
{}
// NodeResources represents resources on a Kubernetes system node
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
type
NodeResources
struct
{
// Capacity represents the available resources.
Capacity
ResourceList
`json:"capacity,omitempty" yaml:"capacity,omitempty"`
}
type
ResourceName
string
type
ResourceList
map
[
ResourceName
]
util
.
IntOrString
// Minion is a worker node in Kubernetenes.
// Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID.
// The name of the minion according to etcd is in JSONBase.ID.
type
Minion
struct
{
type
Minion
struct
{
JSONBase
`json:",inline" yaml:",inline"`
JSONBase
`json:",inline" yaml:",inline"`
// Queried from cloud provider, if available.
// Queried from cloud provider, if available.
HostIP
string
`json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
HostIP
string
`json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
// Resources available on the node
NodeResources
NodeResources
`json:"resources,omitempty" yaml:"resources,omitempty"`
}
}
func
(
*
Minion
)
IsAnAPIObject
()
{}
func
(
*
Minion
)
IsAnAPIObject
()
{}
...
...
pkg/api/v1beta3/types.go
View file @
39d03948
...
@@ -550,10 +550,19 @@ type NodeSpec struct {
...
@@ -550,10 +550,19 @@ type NodeSpec struct {
// NodeStatus is information about the current status of a node.
// NodeStatus is information about the current status of a node.
type
NodeStatus
struct
{
type
NodeStatus
struct
{
// Queried from cloud provider, if available.
HostIP
string
`json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
}
}
// NodeResources represents resources on a Kubernetes system node
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
type
NodeResources
struct
{
// Capacity represents the available resources.
Capacity
ResourceList
`json:"capacity,omitempty" yaml:"capacity,omitempty"`
}
type
ResourceName
string
type
ResourceList
map
[
ResourceName
]
util
.
IntOrString
// Node is a worker node in Kubernetenes.
// Node is a worker node in Kubernetenes.
// The name of the node according to etcd is in JSONBase.ID.
// The name of the node according to etcd is in JSONBase.ID.
type
Node
struct
{
type
Node
struct
{
...
@@ -565,6 +574,9 @@ type Node struct {
...
@@ -565,6 +574,9 @@ type Node struct {
// Status describes the current status of a Node
// Status describes the current status of a Node
Status
NodeStatus
`json:"status,omitempty" yaml:"status,omitempty"`
Status
NodeStatus
`json:"status,omitempty" yaml:"status,omitempty"`
// NodeResources describe the resoruces available on the node.
NodeResources
NodeResources
`json:"resources,omitempty" yaml:"resources,omitempty"`
}
}
// NodeList is a list of minions.
// NodeList is a list of minions.
...
...
pkg/resources/doc.go
0 → 100644
View file @
39d03948
/*
Copyright 2014 Google Inc. 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 resources has constants and utilities for dealing with resources
package
resources
pkg/resources/resources.go
0 → 100644
View file @
39d03948
/*
Copyright 2014 Google Inc. 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
resources
import
(
"strconv"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/golang/glog"
)
const
(
CPU
api
.
ResourceName
=
"cpu"
Memory
api
.
ResourceName
=
"memory"
)
// TODO: None of these currently handle SI units
func
GetFloatResource
(
resources
api
.
ResourceList
,
name
api
.
ResourceName
,
def
float64
)
float64
{
value
,
found
:=
resources
[
name
]
if
!
found
{
return
def
}
if
value
.
Kind
==
util
.
IntstrInt
{
return
float64
(
value
.
IntVal
)
}
result
,
err
:=
strconv
.
ParseFloat
(
value
.
StrVal
,
64
)
if
err
!=
nil
{
glog
.
Errorf
(
"parsing failed for %s: %s"
,
name
,
value
.
StrVal
)
return
def
}
return
result
}
func
GetIntegerResource
(
resources
api
.
ResourceList
,
name
api
.
ResourceName
,
def
int
)
int
{
value
,
found
:=
resources
[
name
]
if
!
found
{
return
def
}
if
value
.
Kind
==
util
.
IntstrInt
{
return
value
.
IntVal
}
result
,
err
:=
strconv
.
Atoi
(
value
.
StrVal
)
if
err
!=
nil
{
glog
.
Errorf
(
"parsing failed for %s: %s"
,
name
,
value
.
StrVal
)
return
def
}
return
result
}
func
GetStringResource
(
resources
api
.
ResourceList
,
name
api
.
ResourceName
,
def
string
)
string
{
value
,
found
:=
resources
[
name
]
if
!
found
{
return
def
}
if
value
.
Kind
==
util
.
IntstrInt
{
return
strconv
.
Itoa
(
value
.
IntVal
)
}
return
value
.
StrVal
}
pkg/resources/resources_test.go
0 → 100644
View file @
39d03948
/*
Copyright 2014 Google Inc. 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
resources
import
(
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
func
TestGetInteger
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
res
api
.
ResourceList
name
api
.
ResourceName
expected
int
def
int
test
string
}{
{
res
:
api
.
ResourceList
{},
name
:
CPU
,
expected
:
1
,
def
:
1
,
test
:
"nothing present"
,
},
{
res
:
api
.
ResourceList
{
CPU
:
util
.
NewIntOrStringFromInt
(
2
),
},
name
:
CPU
,
expected
:
2
,
def
:
1
,
test
:
"present"
,
},
{
res
:
api
.
ResourceList
{
Memory
:
util
.
NewIntOrStringFromInt
(
2
),
},
name
:
CPU
,
expected
:
1
,
def
:
1
,
test
:
"not-present"
,
},
{
res
:
api
.
ResourceList
{
CPU
:
util
.
NewIntOrStringFromString
(
"2"
),
},
name
:
CPU
,
expected
:
2
,
def
:
1
,
test
:
"present-string"
,
},
{
res
:
api
.
ResourceList
{
CPU
:
util
.
NewIntOrStringFromString
(
"foo"
),
},
name
:
CPU
,
expected
:
1
,
def
:
1
,
test
:
"present-invalid"
,
},
}
for
_
,
test
:=
range
tests
{
val
:=
GetIntegerResource
(
test
.
res
,
test
.
name
,
test
.
def
)
if
val
!=
test
.
expected
{
t
.
Errorf
(
"%s: expected: %d found %d"
,
test
.
expected
,
val
)
}
}
}
func
TestGetFloat
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
res
api
.
ResourceList
name
api
.
ResourceName
expected
float64
def
float64
test
string
}{
{
res
:
api
.
ResourceList
{},
name
:
CPU
,
expected
:
1.5
,
def
:
1.5
,
test
:
"nothing present"
,
},
{
res
:
api
.
ResourceList
{
CPU
:
util
.
NewIntOrStringFromInt
(
2
),
},
name
:
CPU
,
expected
:
2.0
,
def
:
1.5
,
test
:
"present"
,
},
{
res
:
api
.
ResourceList
{
CPU
:
util
.
NewIntOrStringFromString
(
"2.5"
),
},
name
:
CPU
,
expected
:
2.5
,
def
:
1
,
test
:
"present-string"
,
},
{
res
:
api
.
ResourceList
{
CPU
:
util
.
NewIntOrStringFromString
(
"foo"
),
},
name
:
CPU
,
expected
:
1
,
def
:
1
,
test
:
"present-invalid"
,
},
}
for
_
,
test
:=
range
tests
{
val
:=
GetFloatResource
(
test
.
res
,
test
.
name
,
test
.
def
)
if
val
!=
test
.
expected
{
t
.
Errorf
(
"%s: expected: %d found %d"
,
test
.
expected
,
val
)
}
}
}
func
TestGetString
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
res
api
.
ResourceList
name
api
.
ResourceName
expected
string
def
string
test
string
}{
{
res
:
api
.
ResourceList
{},
name
:
CPU
,
expected
:
"foo"
,
def
:
"foo"
,
test
:
"nothing present"
,
},
{
res
:
api
.
ResourceList
{
CPU
:
util
.
NewIntOrStringFromString
(
"bar"
),
},
name
:
CPU
,
expected
:
"bar"
,
def
:
"foo"
,
test
:
"present"
,
},
}
for
_
,
test
:=
range
tests
{
val
:=
GetStringResource
(
test
.
res
,
test
.
name
,
test
.
def
)
if
val
!=
test
.
expected
{
t
.
Errorf
(
"%s: expected: %d found %d"
,
test
.
expected
,
val
)
}
}
}
pkg/scheduler/predicates.go
View file @
39d03948
...
@@ -19,8 +19,62 @@ package scheduler
...
@@ -19,8 +19,62 @@ package scheduler
import
(
import
(
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
"github.com/golang/glog"
)
)
type
NodeInfo
interface
{
GetNodeInfo
(
nodeName
string
)
(
api
.
Minion
,
error
)
}
type
ResourceFit
struct
{
info
NodeInfo
}
type
resourceRequest
struct
{
milliCPU
int
memory
int
}
func
getResourceRequest
(
pod
*
api
.
Pod
)
resourceRequest
{
result
:=
resourceRequest
{}
for
ix
:=
range
pod
.
DesiredState
.
Manifest
.
Containers
{
result
.
memory
+=
pod
.
DesiredState
.
Manifest
.
Containers
[
ix
]
.
Memory
result
.
milliCPU
+=
pod
.
DesiredState
.
Manifest
.
Containers
[
ix
]
.
CPU
}
return
result
}
// PodFitsResources calculates fit based on requested, rather than used resources
func
(
r
*
ResourceFit
)
PodFitsResources
(
pod
api
.
Pod
,
existingPods
[]
api
.
Pod
,
node
string
)
(
bool
,
error
)
{
podRequest
:=
getResourceRequest
(
&
pod
)
if
podRequest
.
milliCPU
==
0
&&
podRequest
.
memory
==
0
{
// no resources requested always fits.
return
true
,
nil
}
info
,
err
:=
r
.
info
.
GetNodeInfo
(
node
)
if
err
!=
nil
{
return
false
,
err
}
milliCPURequested
:=
0
memoryRequested
:=
0
for
ix
:=
range
existingPods
{
existingRequest
:=
getResourceRequest
(
&
existingPods
[
ix
])
milliCPURequested
+=
existingRequest
.
milliCPU
memoryRequested
+=
existingRequest
.
memory
}
// TODO: convert to general purpose resource matching, when pods ask for resources
totalMilliCPU
:=
int
(
resources
.
GetFloatResource
(
info
.
NodeResources
.
Capacity
,
resources
.
CPU
,
0
)
*
1000
)
totalMemory
:=
resources
.
GetIntegerResource
(
info
.
NodeResources
.
Capacity
,
resources
.
Memory
,
0
)
fitsCPU
:=
totalMilliCPU
==
0
||
(
totalMilliCPU
-
milliCPURequested
)
>=
podRequest
.
milliCPU
fitsMemory
:=
totalMemory
==
0
||
(
totalMemory
-
memoryRequested
)
>=
podRequest
.
memory
glog
.
V
(
3
)
.
Infof
(
"Calculated fit: cpu: %s, memory %s"
,
fitsCPU
,
fitsMemory
)
return
fitsCPU
&&
fitsMemory
,
nil
}
func
PodFitsPorts
(
pod
api
.
Pod
,
existingPods
[]
api
.
Pod
,
node
string
)
(
bool
,
error
)
{
func
PodFitsPorts
(
pod
api
.
Pod
,
existingPods
[]
api
.
Pod
,
node
string
)
(
bool
,
error
)
{
for
_
,
scheduledPod
:=
range
existingPods
{
for
_
,
scheduledPod
:=
range
existingPods
{
for
_
,
container
:=
range
pod
.
DesiredState
.
Manifest
.
Containers
{
for
_
,
container
:=
range
pod
.
DesiredState
.
Manifest
.
Containers
{
...
...
pkg/scheduler/predicates_test.go
View file @
39d03948
...
@@ -20,8 +20,110 @@ import (
...
@@ -20,8 +20,110 @@ import (
"testing"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
)
type
FakeNodeInfo
api
.
Minion
func
(
n
FakeNodeInfo
)
GetNodeInfo
(
nodeName
string
)
(
api
.
Minion
,
error
)
{
return
api
.
Minion
(
n
),
nil
}
func
makeResources
(
milliCPU
int
,
memory
int
)
api
.
NodeResources
{
return
api
.
NodeResources
{
Capacity
:
api
.
ResourceList
{
resources
.
CPU
:
util
.
IntOrString
{
IntVal
:
milliCPU
,
Kind
:
util
.
IntstrInt
,
},
resources
.
Memory
:
util
.
IntOrString
{
IntVal
:
memory
,
Kind
:
util
.
IntstrInt
,
},
},
}
}
func
newResourcePod
(
usage
...
resourceRequest
)
api
.
Pod
{
containers
:=
[]
api
.
Container
{}
for
_
,
req
:=
range
usage
{
containers
=
append
(
containers
,
api
.
Container
{
Memory
:
req
.
memory
,
CPU
:
req
.
milliCPU
,
})
}
return
api
.
Pod
{
DesiredState
:
api
.
PodState
{
Manifest
:
api
.
ContainerManifest
{
Containers
:
containers
,
},
},
}
}
func
TestPodFitsResources
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
pod
api
.
Pod
existingPods
[]
api
.
Pod
fits
bool
test
string
}{
{
pod
:
api
.
Pod
{},
existingPods
:
[]
api
.
Pod
{
newResourcePod
(
resourceRequest
{
milliCPU
:
10
,
memory
:
20
}),
},
fits
:
true
,
test
:
"no resources requested always fits"
,
},
{
pod
:
newResourcePod
(
resourceRequest
{
milliCPU
:
1
,
memory
:
1
}),
existingPods
:
[]
api
.
Pod
{
newResourcePod
(
resourceRequest
{
milliCPU
:
10
,
memory
:
20
}),
},
fits
:
false
,
test
:
"too many resources fails"
,
},
{
pod
:
newResourcePod
(
resourceRequest
{
milliCPU
:
1
,
memory
:
1
}),
existingPods
:
[]
api
.
Pod
{
newResourcePod
(
resourceRequest
{
milliCPU
:
5
,
memory
:
5
}),
},
fits
:
true
,
test
:
"both resources fit"
,
},
{
pod
:
newResourcePod
(
resourceRequest
{
milliCPU
:
1
,
memory
:
2
}),
existingPods
:
[]
api
.
Pod
{
newResourcePod
(
resourceRequest
{
milliCPU
:
5
,
memory
:
19
}),
},
fits
:
false
,
test
:
"one resources fits"
,
},
{
pod
:
newResourcePod
(
resourceRequest
{
milliCPU
:
5
,
memory
:
1
}),
existingPods
:
[]
api
.
Pod
{
newResourcePod
(
resourceRequest
{
milliCPU
:
5
,
memory
:
19
}),
},
fits
:
true
,
test
:
"equal edge case"
,
},
}
for
_
,
test
:=
range
tests
{
node
:=
api
.
Minion
{
NodeResources
:
makeResources
(
10
,
20
)}
fit
:=
ResourceFit
{
FakeNodeInfo
(
node
)}
fits
,
err
:=
fit
.
PodFitsResources
(
test
.
pod
,
test
.
existingPods
,
"machine"
)
if
err
!=
nil
{
t
.
Errorf
(
"unexpected error: %v"
,
err
)
}
if
fits
!=
test
.
fits
{
t
.
Errorf
(
"%s: expected: %v got %v"
,
test
.
test
,
test
.
fits
,
fits
)
}
}
}
func
TestPodFitsPorts
(
t
*
testing
.
T
)
{
func
TestPodFitsPorts
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
tests
:=
[]
struct
{
pod
api
.
Pod
pod
api
.
Pod
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment