Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
H
helm3
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
helm3
Commits
25c77feb
Commit
25c77feb
authored
Aug 26, 2016
by
Matt Butcher
Committed by
GitHub
Aug 26, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1097 from technosophos/feat/1001-k8s-apiversion
feat(tiller): verify apiVersions before install
parents
2547bf4b
557db8c6
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
92 additions
and
7 deletions
+92
-7
environment.go
cmd/tiller/environment/environment.go
+2
-2
hooks.go
cmd/tiller/hooks.go
+23
-2
hooks_test.go
cmd/tiller/hooks_test.go
+22
-2
release_server.go
cmd/tiller/release_server.go
+31
-1
release_server_test.go
cmd/tiller/release_server_test.go
+14
-0
No files found.
cmd/tiller/environment/environment.go
View file @
25c77feb
...
@@ -23,7 +23,6 @@ These dependencies are expressed as interfaces so that alternate implementations
...
@@ -23,7 +23,6 @@ These dependencies are expressed as interfaces so that alternate implementations
package
environment
package
environment
import
(
import
(
"errors"
"io"
"io"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/chartutil"
...
@@ -33,6 +32,7 @@ import (
...
@@ -33,6 +32,7 @@ import (
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/storage/driver"
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
)
)
// TillerNamespace is the namespace tiller is running in.
// TillerNamespace is the namespace tiller is running in.
...
@@ -150,7 +150,7 @@ type PrintingKubeClient struct {
...
@@ -150,7 +150,7 @@ type PrintingKubeClient struct {
// The printing client does not have access to a Kubernetes client at all. So it
// The printing client does not have access to a Kubernetes client at all. So it
// will always return an error if the client is accessed.
// will always return an error if the client is accessed.
func
(
p
*
PrintingKubeClient
)
APIClient
()
(
unversioned
.
Interface
,
error
)
{
func
(
p
*
PrintingKubeClient
)
APIClient
()
(
unversioned
.
Interface
,
error
)
{
return
nil
,
errors
.
New
(
"no API client found"
)
return
testclient
.
NewSimpleFake
(),
nil
}
}
// Create prints the values of what would be created with a real KubeClient.
// Create prints the values of what would be created with a real KubeClient.
...
...
cmd/tiller/hooks.go
View file @
25c77feb
...
@@ -48,6 +48,7 @@ var events = map[string]release.Hook_Event{
...
@@ -48,6 +48,7 @@ var events = map[string]release.Hook_Event{
}
}
type
simpleHead
struct
{
type
simpleHead
struct
{
Version
string
`json:"apiVersion"`
Kind
string
`json:"kind,omitempty"`
Kind
string
`json:"kind,omitempty"`
Metadata
*
struct
{
Metadata
*
struct
{
Name
string
`json:"name"`
Name
string
`json:"name"`
...
@@ -55,7 +56,22 @@ type simpleHead struct {
...
@@ -55,7 +56,22 @@ type simpleHead struct {
}
`json:"metadata,omitempty"`
}
`json:"metadata,omitempty"`
}
}
// sortHooks takes a map of filename/YAML contents and sorts them into hook types.
type
versionSet
map
[
string
]
struct
{}
func
newVersionSet
(
apiVersions
...
string
)
versionSet
{
vs
:=
versionSet
{}
for
_
,
v
:=
range
apiVersions
{
vs
[
v
]
=
struct
{}{}
}
return
vs
}
func
(
v
versionSet
)
Has
(
apiVersion
string
)
bool
{
_
,
ok
:=
v
[
apiVersion
]
return
ok
}
// sortManifests takes a map of filename/YAML contents and sorts them into hook types.
//
//
// The resulting hooks struct will be populated with all of the generated hooks.
// The resulting hooks struct will be populated with all of the generated hooks.
// Any file that does not declare one of the hook types will be placed in the
// Any file that does not declare one of the hook types will be placed in the
...
@@ -64,6 +80,7 @@ type simpleHead struct {
...
@@ -64,6 +80,7 @@ type simpleHead struct {
// To determine hook type, this looks for a YAML structure like this:
// To determine hook type, this looks for a YAML structure like this:
//
//
// kind: SomeKind
// kind: SomeKind
// apiVersion: v1
// metadata:
// metadata:
// annotations:
// annotations:
// helm.sh/hook: pre-install
// helm.sh/hook: pre-install
...
@@ -75,7 +92,7 @@ type simpleHead struct {
...
@@ -75,7 +92,7 @@ type simpleHead struct {
//
//
// Files that do not parse into the expected format are simply placed into a map and
// Files that do not parse into the expected format are simply placed into a map and
// returned.
// returned.
func
sort
Hooks
(
files
map
[
string
]
string
)
([]
*
release
.
Hook
,
map
[
string
]
string
,
error
)
{
func
sort
Manifests
(
files
map
[
string
]
string
,
apis
versionSet
)
([]
*
release
.
Hook
,
map
[
string
]
string
,
error
)
{
hs
:=
[]
*
release
.
Hook
{}
hs
:=
[]
*
release
.
Hook
{}
generic
:=
map
[
string
]
string
{}
generic
:=
map
[
string
]
string
{}
...
@@ -99,6 +116,10 @@ func sortHooks(files map[string]string) ([]*release.Hook, map[string]string, err
...
@@ -99,6 +116,10 @@ func sortHooks(files map[string]string) ([]*release.Hook, map[string]string, err
return
hs
,
generic
,
e
return
hs
,
generic
,
e
}
}
if
sh
.
Version
!=
""
&&
!
apis
.
Has
(
sh
.
Version
)
{
return
hs
,
generic
,
fmt
.
Errorf
(
"apiVersion %q in %s is not available"
,
sh
.
Version
,
n
)
}
if
sh
.
Metadata
==
nil
||
sh
.
Metadata
.
Annotations
==
nil
||
len
(
sh
.
Metadata
.
Annotations
)
==
0
{
if
sh
.
Metadata
==
nil
||
sh
.
Metadata
.
Annotations
==
nil
||
len
(
sh
.
Metadata
.
Annotations
)
==
0
{
generic
[
n
]
=
c
generic
[
n
]
=
c
continue
continue
...
...
cmd/tiller/hooks_test.go
View file @
25c77feb
...
@@ -22,7 +22,7 @@ import (
...
@@ -22,7 +22,7 @@ import (
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/release"
)
)
func
TestSort
Hook
s
(
t
*
testing
.
T
)
{
func
TestSort
Manifest
s
(
t
*
testing
.
T
)
{
data
:=
[]
struct
{
data
:=
[]
struct
{
name
string
name
string
...
@@ -52,6 +52,7 @@ metadata:
...
@@ -52,6 +52,7 @@ metadata:
kind
:
"ReplicaSet"
,
kind
:
"ReplicaSet"
,
hooks
:
[]
release
.
Hook_Event
{
release
.
Hook_POST_INSTALL
},
hooks
:
[]
release
.
Hook_Event
{
release
.
Hook_POST_INSTALL
},
manifest
:
`kind: ReplicaSet
manifest
:
`kind: ReplicaSet
apiVersion: v1beta1
metadata:
metadata:
name: second
name: second
annotations:
annotations:
...
@@ -63,6 +64,7 @@ metadata:
...
@@ -63,6 +64,7 @@ metadata:
kind
:
"ReplicaSet"
,
kind
:
"ReplicaSet"
,
hooks
:
[]
release
.
Hook_Event
{},
hooks
:
[]
release
.
Hook_Event
{},
manifest
:
`kind: ReplicaSet
manifest
:
`kind: ReplicaSet
apiVersion: v1beta1
metadata:
metadata:
name: third
name: third
annotations:
annotations:
...
@@ -74,6 +76,7 @@ metadata:
...
@@ -74,6 +76,7 @@ metadata:
kind
:
"Pod"
,
kind
:
"Pod"
,
hooks
:
[]
release
.
Hook_Event
{},
hooks
:
[]
release
.
Hook_Event
{},
manifest
:
`kind: Pod
manifest
:
`kind: Pod
apiVersion: v1
metadata:
metadata:
name: fourth
name: fourth
annotations:
annotations:
...
@@ -85,6 +88,7 @@ metadata:
...
@@ -85,6 +88,7 @@ metadata:
kind
:
"ReplicaSet"
,
kind
:
"ReplicaSet"
,
hooks
:
[]
release
.
Hook_Event
{
release
.
Hook_POST_DELETE
,
release
.
Hook_POST_INSTALL
},
hooks
:
[]
release
.
Hook_Event
{
release
.
Hook_POST_DELETE
,
release
.
Hook_POST_INSTALL
},
manifest
:
`kind: ReplicaSet
manifest
:
`kind: ReplicaSet
apiVersion: v1beta1
metadata:
metadata:
name: fifth
name: fifth
annotations:
annotations:
...
@@ -112,7 +116,7 @@ metadata:
...
@@ -112,7 +116,7 @@ metadata:
manifests
[
o
.
path
]
=
o
.
manifest
manifests
[
o
.
path
]
=
o
.
manifest
}
}
hs
,
generic
,
err
:=
sort
Hooks
(
manifests
)
hs
,
generic
,
err
:=
sort
Manifests
(
manifests
,
newVersionSet
(
"v1"
,
"v1beta1"
)
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"Unexpected error: %s"
,
err
)
t
.
Fatalf
(
"Unexpected error: %s"
,
err
)
}
}
...
@@ -153,3 +157,19 @@ metadata:
...
@@ -153,3 +157,19 @@ metadata:
}
}
}
}
func
TestVersionSet
(
t
*
testing
.
T
)
{
vs
:=
newVersionSet
(
"v1"
,
"v1beta1"
,
"extensions/alpha5"
,
"batch/v1"
)
if
l
:=
len
(
vs
);
l
!=
4
{
t
.
Errorf
(
"Expected 4, got %d"
,
l
)
}
if
!
vs
.
Has
(
"extensions/alpha5"
)
{
t
.
Error
(
"No match for alpha5"
)
}
if
vs
.
Has
(
"nosuch/extension"
)
{
t
.
Error
(
"Found nonexistent extension"
)
}
}
cmd/tiller/release_server.go
View file @
25c77feb
...
@@ -35,6 +35,7 @@ import (
...
@@ -35,6 +35,7 @@ import (
"k8s.io/helm/pkg/proto/hapi/services"
"k8s.io/helm/pkg/proto/hapi/services"
"k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/timeconv"
"k8s.io/helm/pkg/timeconv"
"k8s.io/kubernetes/pkg/api/unversioned"
)
)
var
srv
*
releaseServer
var
srv
*
releaseServer
...
@@ -411,6 +412,31 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
...
@@ -411,6 +412,31 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
return
rel
,
nil
return
rel
,
nil
}
}
func
(
s
*
releaseServer
)
getVersionSet
()
(
versionSet
,
error
)
{
defVersions
:=
newVersionSet
(
"v1"
)
cli
,
err
:=
s
.
env
.
KubeClient
.
APIClient
()
if
err
!=
nil
{
log
.
Printf
(
"API Client for Kubernetes is missing: %s."
,
err
)
return
defVersions
,
err
}
groups
,
err
:=
cli
.
Discovery
()
.
ServerGroups
()
if
err
!=
nil
{
return
defVersions
,
err
}
// FIXME: The Kubernetes test fixture for cli appears to always return nil
// for calls to Discovery().ServerGroups(). So in this case, we return
// the default API list. This is also a safe value to return in any other
// odd-ball case.
if
groups
==
nil
{
return
defVersions
,
nil
}
versions
:=
unversioned
.
ExtractGroupVersions
(
groups
)
return
newVersionSet
(
versions
...
),
nil
}
func
(
s
*
releaseServer
)
renderResources
(
ch
*
chart
.
Chart
,
values
chartutil
.
Values
)
([]
*
release
.
Hook
,
*
bytes
.
Buffer
,
error
)
{
func
(
s
*
releaseServer
)
renderResources
(
ch
*
chart
.
Chart
,
values
chartutil
.
Values
)
([]
*
release
.
Hook
,
*
bytes
.
Buffer
,
error
)
{
renderer
:=
s
.
engine
(
ch
)
renderer
:=
s
.
engine
(
ch
)
files
,
err
:=
renderer
.
Render
(
ch
,
values
)
files
,
err
:=
renderer
.
Render
(
ch
,
values
)
...
@@ -421,7 +447,11 @@ func (s *releaseServer) renderResources(ch *chart.Chart, values chartutil.Values
...
@@ -421,7 +447,11 @@ func (s *releaseServer) renderResources(ch *chart.Chart, values chartutil.Values
// Sort hooks, manifests, and partials. Only hooks and manifests are returned,
// Sort hooks, manifests, and partials. Only hooks and manifests are returned,
// as partials are not used after renderer.Render. Empty manifests are also
// as partials are not used after renderer.Render. Empty manifests are also
// removed here.
// removed here.
hooks
,
manifests
,
err
:=
sortHooks
(
files
)
vs
,
err
:=
s
.
getVersionSet
()
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"Could not get apiVersions from Kubernetes: %s"
,
err
)
}
hooks
,
manifests
,
err
:=
sortManifests
(
files
,
vs
)
if
err
!=
nil
{
if
err
!=
nil
{
// By catching parse errors here, we can prevent bogus releases from going
// By catching parse errors here, we can prevent bogus releases from going
// to Kubernetes.
// to Kubernetes.
...
...
cmd/tiller/release_server_test.go
View file @
25c77feb
...
@@ -112,6 +112,20 @@ func namedReleaseStub(name string, status release.Status_Code) *release.Release
...
@@ -112,6 +112,20 @@ func namedReleaseStub(name string, status release.Status_Code) *release.Release
}
}
}
}
func
TestGetVersionSet
(
t
*
testing
.
T
)
{
rs
:=
rsFixture
()
vs
,
err
:=
rs
.
getVersionSet
()
if
err
!=
nil
{
t
.
Error
(
err
)
}
if
!
vs
.
Has
(
"v1"
)
{
t
.
Errorf
(
"Expected supported versions to at least include v1."
)
}
if
vs
.
Has
(
"nosuchversion/v1"
)
{
t
.
Error
(
"Non-existent version is reported found."
)
}
}
func
TestUniqName
(
t
*
testing
.
T
)
{
func
TestUniqName
(
t
*
testing
.
T
)
{
rs
:=
rsFixture
()
rs
:=
rsFixture
()
...
...
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