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
90b4662d
Commit
90b4662d
authored
Jan 11, 2016
by
Chao Xu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add services/status path, and let the service controller uses Services.UpdateStatus()
parent
870220e0
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
215 additions
and
17 deletions
+215
-17
v1.json
api/swagger-spec/v1.json
+60
-0
operations.html
docs/api-reference/v1/operations.html
+0
-0
validation.go
pkg/api/validation/validation.go
+7
-0
services.go
pkg/client/unversioned/services.go
+8
-0
services_test.go
pkg/client/unversioned/services_test.go
+45
-0
fake_services.go
pkg/client/unversioned/testclient/fake_services.go
+9
-0
servicecontroller.go
pkg/controller/service/servicecontroller.go
+1
-1
master.go
pkg/master/master.go
+2
-1
etcd.go
pkg/registry/service/etcd/etcd.go
+18
-2
etcd_test.go
pkg/registry/service/etcd/etcd_test.go
+9
-8
strategy.go
pkg/registry/service/strategy.go
+23
-4
strategy_test.go
pkg/registry/service/strategy_test.go
+30
-0
service.go
test/e2e/service.go
+3
-1
No files found.
api/swagger-spec/v1.json
View file @
90b4662d
...
...
@@ -13559,6 +13559,66 @@
]
},
{
"path"
:
"/api/v1/namespaces/{namespace}/services/{name}/status"
,
"description"
:
"API at /api/v1"
,
"operations"
:
[
{
"type"
:
"v1.Service"
,
"method"
:
"PUT"
,
"summary"
:
"replace status of the specified Service"
,
"nickname"
:
"replaceNamespacedServiceStatus"
,
"parameters"
:
[
{
"type"
:
"string"
,
"paramType"
:
"query"
,
"name"
:
"pretty"
,
"description"
:
"If 'true', then the output is pretty printed."
,
"required"
:
false
,
"allowMultiple"
:
false
},
{
"type"
:
"v1.Service"
,
"paramType"
:
"body"
,
"name"
:
"body"
,
"description"
:
""
,
"required"
:
true
,
"allowMultiple"
:
false
},
{
"type"
:
"string"
,
"paramType"
:
"path"
,
"name"
:
"namespace"
,
"description"
:
"object name and auth scope, such as for teams and projects"
,
"required"
:
true
,
"allowMultiple"
:
false
},
{
"type"
:
"string"
,
"paramType"
:
"path"
,
"name"
:
"name"
,
"description"
:
"name of the Service"
,
"required"
:
true
,
"allowMultiple"
:
false
}
],
"responseMessages"
:
[
{
"code"
:
200
,
"message"
:
"OK"
,
"responseModel"
:
"v1.Service"
}
],
"produces"
:
[
"application/json"
,
"application/yaml"
],
"consumes"
:
[
"*/*"
]
}
]
},
{
"path"
:
"/api/v1"
,
"description"
:
"API at /api/v1"
,
"operations"
:
[
...
...
docs/api-reference/v1/operations.html
View file @
90b4662d
This diff is collapsed.
Click to expand it.
pkg/api/validation/validation.go
View file @
90b4662d
...
...
@@ -1603,6 +1603,13 @@ func ValidateServiceUpdate(service, oldService *api.Service) field.ErrorList {
return
allErrs
}
// ValidateServiceStatusUpdate tests if required fields in the Service are set when updating status.
func
ValidateServiceStatusUpdate
(
service
,
oldService
*
api
.
Service
)
field
.
ErrorList
{
allErrs
:=
ValidateObjectMetaUpdate
(
&
service
.
ObjectMeta
,
&
oldService
.
ObjectMeta
,
field
.
NewPath
(
"metadata"
))
allErrs
=
append
(
allErrs
,
ValidateLoadBalancerStatus
(
&
service
.
Status
.
LoadBalancer
,
field
.
NewPath
(
"status"
,
"loadBalancer"
))
...
)
return
allErrs
}
// ValidateReplicationController tests if required fields in the replication controller are set.
func
ValidateReplicationController
(
controller
*
api
.
ReplicationController
)
field
.
ErrorList
{
allErrs
:=
ValidateObjectMeta
(
&
controller
.
ObjectMeta
,
true
,
ValidateReplicationControllerName
,
field
.
NewPath
(
"metadata"
))
...
...
pkg/client/unversioned/services.go
View file @
90b4662d
...
...
@@ -33,6 +33,7 @@ type ServiceInterface interface {
Get
(
name
string
)
(
*
api
.
Service
,
error
)
Create
(
srv
*
api
.
Service
)
(
*
api
.
Service
,
error
)
Update
(
srv
*
api
.
Service
)
(
*
api
.
Service
,
error
)
UpdateStatus
(
srv
*
api
.
Service
)
(
*
api
.
Service
,
error
)
Delete
(
name
string
)
error
Watch
(
opts
api
.
ListOptions
)
(
watch
.
Interface
,
error
)
ProxyGet
(
scheme
,
name
,
port
,
path
string
,
params
map
[
string
]
string
)
ResponseWrapper
...
...
@@ -82,6 +83,13 @@ func (c *services) Update(svc *api.Service) (result *api.Service, err error) {
return
}
// UpdateStatus takes a Service object with the new status and applies it as an update to the existing Service.
func
(
c
*
services
)
UpdateStatus
(
service
*
api
.
Service
)
(
result
*
api
.
Service
,
err
error
)
{
result
=
&
api
.
Service
{}
err
=
c
.
r
.
Put
()
.
Namespace
(
c
.
ns
)
.
Resource
(
"services"
)
.
Name
(
service
.
Name
)
.
SubResource
(
"status"
)
.
Body
(
service
)
.
Do
()
.
Into
(
result
)
return
}
// Delete deletes an existing service.
func
(
c
*
services
)
Delete
(
name
string
)
error
{
return
c
.
r
.
Delete
()
.
Namespace
(
c
.
ns
)
.
Resource
(
"services"
)
.
Name
(
name
)
.
Do
()
.
Error
()
...
...
pkg/client/unversioned/services_test.go
View file @
90b4662d
...
...
@@ -167,6 +167,51 @@ func TestDeleteService(t *testing.T) {
c
.
Validate
(
t
,
nil
,
err
)
}
func
TestUpdateServiceStatus
(
t
*
testing
.
T
)
{
ns
:=
api
.
NamespaceDefault
lbStatus
:=
api
.
LoadBalancerStatus
{
Ingress
:
[]
api
.
LoadBalancerIngress
{
{
IP
:
"127.0.0.1"
},
},
}
requestService
:=
&
api
.
Service
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
,
Namespace
:
ns
,
ResourceVersion
:
"1"
,
},
Status
:
api
.
ServiceStatus
{
LoadBalancer
:
lbStatus
,
},
}
c
:=
&
simple
.
Client
{
Request
:
simple
.
Request
{
Method
:
"PUT"
,
Path
:
testapi
.
Default
.
ResourcePath
(
"services"
,
ns
,
"foo"
)
+
"/status"
,
Query
:
simple
.
BuildQueryValues
(
nil
),
},
Response
:
simple
.
Response
{
StatusCode
:
200
,
Body
:
&
api
.
Service
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
,
Labels
:
map
[
string
]
string
{
"foo"
:
"bar"
,
"name"
:
"baz"
,
},
},
Spec
:
api
.
ServiceSpec
{},
Status
:
api
.
ServiceStatus
{
LoadBalancer
:
lbStatus
,
},
},
},
}
receivedService
,
err
:=
c
.
Setup
(
t
)
.
Services
(
ns
)
.
UpdateStatus
(
requestService
)
defer
c
.
Close
()
c
.
Validate
(
t
,
receivedService
,
err
)
}
func
TestServiceProxyGet
(
t
*
testing
.
T
)
{
body
:=
"OK"
ns
:=
api
.
NamespaceDefault
...
...
pkg/client/unversioned/testclient/fake_services.go
View file @
90b4662d
...
...
@@ -65,6 +65,15 @@ func (c *FakeServices) Update(service *api.Service) (*api.Service, error) {
return
obj
.
(
*
api
.
Service
),
err
}
func
(
c
*
FakeServices
)
UpdateStatus
(
service
*
api
.
Service
)
(
result
*
api
.
Service
,
err
error
)
{
obj
,
err
:=
c
.
Fake
.
Invokes
(
NewUpdateSubresourceAction
(
"services"
,
"status"
,
c
.
Namespace
,
service
),
service
)
if
obj
==
nil
{
return
nil
,
err
}
return
obj
.
(
*
api
.
Service
),
err
}
func
(
c
*
FakeServices
)
Delete
(
name
string
)
error
{
_
,
err
:=
c
.
Fake
.
Invokes
(
NewDeleteAction
(
"services"
,
c
.
Namespace
,
name
),
&
api
.
Service
{})
return
err
...
...
pkg/controller/service/servicecontroller.go
View file @
90b4662d
...
...
@@ -343,7 +343,7 @@ func (s *ServiceController) createLoadBalancerIfNeeded(namespacedName types.Name
func
(
s
*
ServiceController
)
persistUpdate
(
service
*
api
.
Service
)
error
{
var
err
error
for
i
:=
0
;
i
<
clientRetryCount
;
i
++
{
_
,
err
=
s
.
kubeClient
.
Services
(
service
.
Namespace
)
.
Update
(
service
)
_
,
err
=
s
.
kubeClient
.
Services
(
service
.
Namespace
)
.
Update
Status
(
service
)
if
err
==
nil
{
return
nil
}
...
...
pkg/master/master.go
View file @
90b4662d
...
...
@@ -292,7 +292,7 @@ func (m *Master) initV1ResourcesStorage(c *Config) {
m
.
ProxyTransport
,
)
serviceStorage
:=
serviceetcd
.
NewREST
(
dbClient
(
"services"
),
storageDecorator
)
serviceStorage
,
serviceStatusStorage
:=
serviceetcd
.
NewREST
(
dbClient
(
"services"
),
storageDecorator
)
m
.
serviceRegistry
=
service
.
NewRegistry
(
serviceStorage
)
var
serviceClusterIPRegistry
service
.
RangeRegistry
...
...
@@ -336,6 +336,7 @@ func (m *Master) initV1ResourcesStorage(c *Config) {
"replicationControllers"
:
controllerStorage
,
"replicationControllers/status"
:
controllerStatusStorage
,
"services"
:
service
.
NewStorage
(
m
.
serviceRegistry
,
m
.
endpointRegistry
,
serviceClusterIPAllocator
,
serviceNodePortAllocator
,
m
.
ProxyTransport
),
"services/status"
:
serviceStatusStorage
,
"endpoints"
:
endpointsStorage
,
"nodes"
:
nodeStorage
,
"nodes/status"
:
nodeStatusStorage
,
...
...
pkg/registry/service/etcd/etcd.go
View file @
90b4662d
...
...
@@ -32,7 +32,7 @@ type REST struct {
}
// NewREST returns a RESTStorage object that will work against services.
func
NewREST
(
s
storage
.
Interface
,
storageDecorator
generic
.
StorageDecorator
)
*
REST
{
func
NewREST
(
s
storage
.
Interface
,
storageDecorator
generic
.
StorageDecorator
)
(
*
REST
,
*
StatusREST
)
{
prefix
:=
"/services/specs"
newListFunc
:=
func
()
runtime
.
Object
{
return
&
api
.
ServiceList
{}
}
...
...
@@ -61,5 +61,21 @@ func NewREST(s storage.Interface, storageDecorator generic.StorageDecorator) *RE
Storage
:
storageInterface
,
}
return
&
REST
{
store
}
statusStore
:=
*
store
statusStore
.
UpdateStrategy
=
service
.
StatusStrategy
return
&
REST
{
store
},
&
StatusREST
{
store
:
&
statusStore
}
}
// StatusREST implements the REST endpoint for changing the status of a service.
type
StatusREST
struct
{
store
*
etcdgeneric
.
Etcd
}
func
(
r
*
StatusREST
)
New
()
runtime
.
Object
{
return
&
api
.
Service
{}
}
// Update alters the status subset of an object.
func
(
r
*
StatusREST
)
Update
(
ctx
api
.
Context
,
obj
runtime
.
Object
)
(
runtime
.
Object
,
bool
,
error
)
{
return
r
.
store
.
Update
(
ctx
,
obj
)
}
pkg/registry/service/etcd/etcd_test.go
View file @
90b4662d
...
...
@@ -29,9 +29,10 @@ import (
"k8s.io/kubernetes/pkg/util/intstr"
)
func
newStorage
(
t
*
testing
.
T
)
(
*
REST
,
*
etcdtesting
.
EtcdTestServer
)
{
func
newStorage
(
t
*
testing
.
T
)
(
*
REST
,
*
StatusREST
,
*
etcdtesting
.
EtcdTestServer
)
{
etcdStorage
,
server
:=
registrytest
.
NewEtcdStorage
(
t
,
""
)
return
NewREST
(
etcdStorage
,
generic
.
UndecoratedStorage
),
server
serviceStorage
,
statusStorage
:=
NewREST
(
etcdStorage
,
generic
.
UndecoratedStorage
)
return
serviceStorage
,
statusStorage
,
server
}
func
validService
()
*
api
.
Service
{
...
...
@@ -55,7 +56,7 @@ func validService() *api.Service {
}
func
TestCreate
(
t
*
testing
.
T
)
{
storage
,
server
:=
newStorage
(
t
)
storage
,
_
,
server
:=
newStorage
(
t
)
defer
server
.
Terminate
(
t
)
test
:=
registrytest
.
New
(
t
,
storage
.
Etcd
)
validService
:=
validService
()
...
...
@@ -85,7 +86,7 @@ func TestCreate(t *testing.T) {
}
func
TestUpdate
(
t
*
testing
.
T
)
{
storage
,
server
:=
newStorage
(
t
)
storage
,
_
,
server
:=
newStorage
(
t
)
defer
server
.
Terminate
(
t
)
test
:=
registrytest
.
New
(
t
,
storage
.
Etcd
)
.
AllowCreateOnUpdate
()
test
.
TestUpdate
(
...
...
@@ -110,28 +111,28 @@ func TestUpdate(t *testing.T) {
}
func
TestDelete
(
t
*
testing
.
T
)
{
storage
,
server
:=
newStorage
(
t
)
storage
,
_
,
server
:=
newStorage
(
t
)
defer
server
.
Terminate
(
t
)
test
:=
registrytest
.
New
(
t
,
storage
.
Etcd
)
.
AllowCreateOnUpdate
()
test
.
TestDelete
(
validService
())
}
func
TestGet
(
t
*
testing
.
T
)
{
storage
,
server
:=
newStorage
(
t
)
storage
,
_
,
server
:=
newStorage
(
t
)
defer
server
.
Terminate
(
t
)
test
:=
registrytest
.
New
(
t
,
storage
.
Etcd
)
.
AllowCreateOnUpdate
()
test
.
TestGet
(
validService
())
}
func
TestList
(
t
*
testing
.
T
)
{
storage
,
server
:=
newStorage
(
t
)
storage
,
_
,
server
:=
newStorage
(
t
)
defer
server
.
Terminate
(
t
)
test
:=
registrytest
.
New
(
t
,
storage
.
Etcd
)
.
AllowCreateOnUpdate
()
test
.
TestList
(
validService
())
}
func
TestWatch
(
t
*
testing
.
T
)
{
storage
,
server
:=
newStorage
(
t
)
storage
,
_
,
server
:=
newStorage
(
t
)
defer
server
.
Terminate
(
t
)
test
:=
registrytest
.
New
(
t
,
storage
.
Etcd
)
test
.
TestWatch
(
...
...
pkg/registry/service/strategy.go
View file @
90b4662d
...
...
@@ -51,10 +51,9 @@ func (svcStrategy) PrepareForCreate(obj runtime.Object) {
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func
(
svcStrategy
)
PrepareForUpdate
(
obj
,
old
runtime
.
Object
)
{
// TODO: once service has a status sub-resource we can enable this.
//newService := obj.(*api.Service)
//oldService := old.(*api.Service)
//newService.Status = oldService.Status
newService
:=
obj
.
(
*
api
.
Service
)
oldService
:=
old
.
(
*
api
.
Service
)
newService
.
Status
=
oldService
.
Status
}
// Validate validates a new service.
...
...
@@ -118,3 +117,23 @@ func MatchServices(label labels.Selector, field fields.Selector) generic.Matcher
func
ServiceToSelectableFields
(
service
*
api
.
Service
)
fields
.
Set
{
return
generic
.
ObjectMetaFieldsSet
(
service
.
ObjectMeta
,
true
)
}
type
serviceStatusStrategy
struct
{
svcStrategy
}
// StatusStrategy is the default logic invoked when updating service status.
var
StatusStrategy
=
serviceStatusStrategy
{
Strategy
}
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
func
(
serviceStatusStrategy
)
PrepareForUpdate
(
obj
,
old
runtime
.
Object
)
{
newService
:=
obj
.
(
*
api
.
Service
)
oldService
:=
old
.
(
*
api
.
Service
)
// status changes are not allowed to update spec
newService
.
Spec
=
oldService
.
Spec
}
// ValidateUpdate is the default update validation for an end user updating status
func
(
serviceStatusStrategy
)
ValidateUpdate
(
ctx
api
.
Context
,
obj
,
old
runtime
.
Object
)
field
.
ErrorList
{
return
validation
.
ValidateServiceStatusUpdate
(
obj
.
(
*
api
.
Service
),
old
.
(
*
api
.
Service
))
}
pkg/registry/service/strategy_test.go
View file @
90b4662d
...
...
@@ -217,3 +217,33 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
nil
,
)
}
func
TestServiceStatusStrategy
(
t
*
testing
.
T
)
{
ctx
:=
api
.
NewDefaultContext
()
if
!
StatusStrategy
.
NamespaceScoped
()
{
t
.
Errorf
(
"Service must be namespace scoped"
)
}
oldService
:=
makeValidService
()
newService
:=
makeValidService
()
oldService
.
ResourceVersion
=
"4"
newService
.
ResourceVersion
=
"4"
newService
.
Spec
.
SessionAffinity
=
"ClientIP"
newService
.
Status
=
api
.
ServiceStatus
{
LoadBalancer
:
api
.
LoadBalancerStatus
{
Ingress
:
[]
api
.
LoadBalancerIngress
{
{
IP
:
"127.0.0.2"
},
},
},
}
StatusStrategy
.
PrepareForUpdate
(
&
newService
,
&
oldService
)
if
newService
.
Status
.
LoadBalancer
.
Ingress
[
0
]
.
IP
!=
"127.0.0.2"
{
t
.
Errorf
(
"Service status updates should allow change of status fields"
)
}
if
newService
.
Spec
.
SessionAffinity
!=
"None"
{
t
.
Errorf
(
"PrepareForUpdate should have preserved old spec"
)
}
errs
:=
StatusStrategy
.
ValidateUpdate
(
ctx
,
&
newService
,
&
oldService
)
if
len
(
errs
)
!=
0
{
t
.
Errorf
(
"Unexpected error %v"
,
errs
)
}
}
test/e2e/service.go
View file @
90b4662d
...
...
@@ -603,7 +603,9 @@ var _ = Describe("Services", func() {
})
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
if
len
(
service
.
Status
.
LoadBalancer
.
Ingress
)
!=
0
{
// Updating the service type shouldn't change the Status immediately. The status should be
// updated after waitForLoadBalancerDestroy.
if
len
(
service
.
Status
.
LoadBalancer
.
Ingress
)
==
0
{
Failf
(
"got unexpected len(Status.LoadBalancer.Ingress) for NodePort service: %v"
,
service
)
}
if
service
.
Spec
.
Type
!=
api
.
ServiceTypeClusterIP
{
...
...
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