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
ae2d6c50
Commit
ae2d6c50
authored
Aug 10, 2016
by
fibonacci1729
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into feat/storage-memory
parents
9d3a1ed2
ae4ff5cd
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
45 changed files
with
990 additions
and
237 deletions
+990
-237
.gitignore
.gitignore
+4
-3
tiller.proto
_proto/hapi/services/tiller.proto
+3
-0
helm.go
cmd/helm/helm.go
+4
-3
init.go
cmd/helm/init.go
+30
-33
inspect.go
cmd/helm/inspect.go
+4
-5
inspect_test.go
cmd/helm/inspect_test.go
+13
-0
install.go
cmd/helm/install.go
+32
-3
install_test.go
cmd/helm/install_test.go
+86
-2
lint.go
cmd/helm/lint.go
+11
-1
serve.go
cmd/helm/serve.go
+19
-7
Chart.yaml
cmd/helm/testdata/testcharts/novals/Chart.yaml
+6
-0
README.md
cmd/helm/testdata/testcharts/novals/README.md
+13
-0
alpine-pod.yaml
...helm/testdata/testcharts/novals/templates/alpine-pod.yaml
+26
-0
upgrade.go
cmd/helm/upgrade.go
+11
-8
upgrade_test.go
cmd/helm/upgrade_test.go
+6
-2
environment.go
cmd/tiller/environment/environment.go
+15
-0
environment_test.go
cmd/tiller/environment/environment_test.go
+3
-0
release_server.go
cmd/tiller/release_server.go
+104
-52
release_server_test.go
cmd/tiller/release_server_test.go
+112
-2
architecture.md
docs/architecture.md
+2
-3
charts.md
docs/charts.md
+5
-0
developers.md
docs/developers.md
+24
-4
glide.lock
glide.lock
+78
-76
glide.yaml
glide.yaml
+12
-2
create.go
pkg/chartutil/create.go
+17
-1
files.go
pkg/chartutil/files.go
+12
-7
files_test.go
pkg/chartutil/files_test.go
+2
-2
load.go
pkg/chartutil/load.go
+5
-0
load_test.go
pkg/chartutil/load_test.go
+3
-2
frobnitz-1.2.3.tgz
pkg/chartutil/testdata/frobnitz-1.2.3.tgz
+0
-0
.helmignore
pkg/chartutil/testdata/frobnitz/.helmignore
+1
-0
mariner-4.3.2.tgz
pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz
+0
-0
me.txt
pkg/chartutil/testdata/frobnitz/ignore/me.txt
+0
-0
genfrob.sh
pkg/chartutil/testdata/genfrob.sh
+1
-1
albatross-0.1.0.tgz
pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz
+0
-0
install.go
pkg/client/install.go
+3
-9
engine.go
pkg/engine/engine.go
+26
-1
engine_test.go
pkg/engine/engine_test.go
+31
-1
option.go
pkg/helm/option.go
+15
-2
rules.go
pkg/ignore/rules.go
+3
-2
client.go
pkg/kube/client.go
+156
-0
client_test.go
pkg/kube/client_test.go
+90
-0
tunnel.go
pkg/kube/tunnel.go
+1
-1
tiller.pb.go
pkg/proto/hapi/services/tiller.pb.go
+0
-0
repo.go
pkg/repo/repo.go
+1
-2
No files found.
.gitignore
View file @
ae2d6c50
.DS_Store
.coverage/
.vimrc
_dist/
_proto/*.pb.go
bin/
rootfs/tiller
vendor/
_proto/*.pb.go
.vimrc
.DS_Store
_proto/hapi/services/tiller.proto
View file @
ae2d6c50
...
...
@@ -162,6 +162,9 @@ message UpdateReleaseRequest {
hapi.chart.Config
values
=
3
;
// dry_run, if true, will run through the release logic, but neither create
bool
dry_run
=
4
;
// DisableHooks causes the server to skip running any hooks for the upgrade.
bool
disable_hooks
=
5
;
}
// UpdateReleaseResponse is the response to an update request.
...
...
cmd/helm/helm.go
View file @
ae2d6c50
...
...
@@ -84,12 +84,13 @@ func newRootCmd(out io.Writer) *cobra.Command {
cmd
.
AddCommand
(
newCreateCmd
(
out
),
newDeleteCmd
(
nil
,
out
),
newGetCmd
(
nil
,
out
),
newInitCmd
(
out
),
newInspectCmd
(
nil
,
out
),
newInstallCmd
(
nil
,
out
),
newListCmd
(
nil
,
out
),
newStatusCmd
(
nil
,
out
),
newInstallCmd
(
nil
,
out
),
newDeleteCmd
(
nil
,
out
),
newInspectCmd
(
nil
,
out
),
newUpgradeCmd
(
nil
,
out
),
)
return
cmd
...
...
cmd/helm/init.go
View file @
ae2d6c50
...
...
@@ -19,6 +19,7 @@ package main
import
(
"errors"
"fmt"
"io"
"os"
"github.com/spf13/cobra"
...
...
@@ -32,58 +33,54 @@ Kubernetes Cluster and sets up local configuration in $HELM_HOME (default: ~/.he
`
var
(
tillerImg
string
clientOnly
bool
defaultRepository
=
"kubernetes-charts"
defaultRepositoryURL
=
"http://storage.googleapis.com/kubernetes-charts"
)
func
init
()
{
f
:=
initCmd
.
Flags
()
f
.
StringVarP
(
&
tillerImg
,
"tiller-image"
,
"i"
,
""
,
"override tiller image"
)
f
.
BoolVarP
(
&
clientOnly
,
"client-only"
,
"c"
,
false
,
"If set does not install tiller"
)
RootCommand
.
AddCommand
(
initCmd
)
type
initCmd
struct
{
image
string
clientOnly
bool
out
io
.
Writer
}
var
initCmd
=
&
cobra
.
Command
{
Use
:
"init"
,
Short
:
"initialize Helm on both client and server"
,
Long
:
initDesc
,
RunE
:
runInit
,
func
newInitCmd
(
out
io
.
Writer
)
*
cobra
.
Command
{
i
:=
&
initCmd
{
out
:
out
,
}
cmd
:=
&
cobra
.
Command
{
Use
:
"init"
,
Short
:
"initialize Helm on both client and server"
,
Long
:
initDesc
,
RunE
:
func
(
cmd
*
cobra
.
Command
,
args
[]
string
)
error
{
if
len
(
args
)
!=
0
{
return
errors
.
New
(
"This command does not accept arguments"
)
}
return
i
.
run
()
},
}
cmd
.
Flags
()
.
StringVarP
(
&
i
.
image
,
"tiller-image"
,
"i"
,
""
,
"override tiller image"
)
cmd
.
Flags
()
.
BoolVarP
(
&
i
.
clientOnly
,
"client-only"
,
"c"
,
false
,
"If set does not install tiller"
)
return
cmd
}
// runInit initializes local config and installs tiller to Kubernetes Cluster
func
runInit
(
cmd
*
cobra
.
Command
,
args
[]
string
)
error
{
if
len
(
args
)
!=
0
{
return
errors
.
New
(
"This command does not accept arguments.
\n
"
)
}
func
(
i
*
initCmd
)
run
()
error
{
if
err
:=
ensureHome
();
err
!=
nil
{
return
err
}
if
!
clientOnly
{
if
err
:=
installTiller
(
);
err
!=
nil
{
return
err
if
!
i
.
clientOnly
{
if
err
:=
client
.
Install
(
tillerNamespace
,
i
.
image
,
flagDebug
);
err
!=
nil
{
return
fmt
.
Errorf
(
"error installing: %s"
,
err
)
}
fmt
.
Fprintln
(
i
.
out
,
"
\n
Tiller (the helm server side component) has been installed into your Kubernetes Cluster."
)
}
else
{
fmt
.
Println
(
"Not installing tiller due to 'client-only' flag having been set"
)
fmt
.
Fprintln
(
i
.
out
,
"Not installing tiller due to 'client-only' flag having been set"
)
}
fmt
.
Println
(
"Happy Helming!"
)
return
nil
}
func
installTiller
()
error
{
if
err
:=
client
.
Install
(
tillerNamespace
,
tillerImg
,
flagDebug
);
err
!=
nil
{
return
fmt
.
Errorf
(
"error installing: %s"
,
err
)
}
fmt
.
Println
(
"
\n
Tiller (the helm server side component) has been installed into your Kubernetes Cluster."
)
fmt
.
Fprintln
(
i
.
out
,
"Happy Helming!"
)
return
nil
}
// requireHome checks to see if $HELM_HOME exists, and returns an error if it does not.
func
requireHome
()
error
{
dirs
:=
[]
string
{
homePath
(),
repositoryDirectory
(),
cacheDirectory
(),
localRepoDirectory
()}
for
_
,
d
:=
range
dirs
{
...
...
cmd/helm/inspect.go
View file @
ae2d6c50
...
...
@@ -130,11 +130,10 @@ func (i *inspectCmd) run() error {
fmt
.
Fprintln
(
i
.
out
,
string
(
cf
))
}
if
i
.
output
==
both
{
fmt
.
Fprintln
(
i
.
out
,
"---"
)
}
if
i
.
output
==
valuesOnly
||
i
.
output
==
both
{
if
(
i
.
output
==
valuesOnly
||
i
.
output
==
both
)
&&
chrt
.
Values
!=
nil
{
if
i
.
output
==
both
{
fmt
.
Fprintln
(
i
.
out
,
"---"
)
}
fmt
.
Fprintln
(
i
.
out
,
chrt
.
Values
.
Raw
)
}
...
...
cmd/helm/inspect_test.go
View file @
ae2d6c50
...
...
@@ -61,4 +61,17 @@ func TestInspect(t *testing.T) {
t
.
Errorf
(
"Expected
\n
%q
\n
Got
\n
%q
\n
"
,
expect
[
i
],
got
)
}
}
// Regression tests for missing values. See issue #1024.
b
.
Reset
()
insp
=
&
inspectCmd
{
chartpath
:
"testdata/testcharts/novals"
,
output
:
"values"
,
out
:
b
,
}
insp
.
run
()
if
b
.
Len
()
!=
0
{
t
.
Errorf
(
"expected empty values buffer, got %q"
,
b
.
String
())
}
}
cmd/helm/install.go
View file @
ae2d6c50
...
...
@@ -17,6 +17,7 @@ limitations under the License.
package
main
import
(
"bytes"
"fmt"
"io"
"io/ioutil"
...
...
@@ -24,6 +25,9 @@ import (
"path/filepath"
"strings"
"text/template"
"github.com/Masterminds/sprig"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
...
...
@@ -59,10 +63,11 @@ type installCmd struct {
chartPath
string
dryRun
bool
disableHooks
bool
re
useName
bool
re
place
bool
out
io
.
Writer
client
helm
.
Interface
values
*
values
nameTemplate
string
}
func
newInstallCmd
(
c
helm
.
Interface
,
out
io
.
Writer
)
*
cobra
.
Command
{
...
...
@@ -98,8 +103,9 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
f
.
StringVar
(
&
inst
.
namespace
,
"namespace"
,
"default"
,
"the namespace to install the release into"
)
f
.
BoolVar
(
&
inst
.
dryRun
,
"dry-run"
,
false
,
"simulate an install"
)
f
.
BoolVar
(
&
inst
.
disableHooks
,
"no-hooks"
,
false
,
"prevent hooks from running during install"
)
f
.
BoolVar
(
&
inst
.
re
useName
,
"reuse-name"
,
false
,
"force Tiller to
re-use the given name, even if that name is already used. This is unsafe in production"
)
f
.
BoolVar
(
&
inst
.
re
place
,
"replace"
,
false
,
"
re-use the given name, even if that name is already used. This is unsafe in production"
)
f
.
Var
(
inst
.
values
,
"set"
,
"set values on the command line. Separate values with commas: key1=val1,key2=val2"
)
f
.
StringVar
(
&
inst
.
nameTemplate
,
"name-template"
,
""
,
"specify template used to name the release"
)
return
cmd
}
...
...
@@ -113,13 +119,23 @@ func (i *installCmd) run() error {
return
err
}
// If template is specified, try to run the template.
if
i
.
nameTemplate
!=
""
{
i
.
name
,
err
=
generateName
(
i
.
nameTemplate
)
if
err
!=
nil
{
return
err
}
// Print the final name so the user knows what the final name of the release is.
fmt
.
Printf
(
"final name: %s
\n
"
,
i
.
name
)
}
res
,
err
:=
i
.
client
.
InstallRelease
(
i
.
chartPath
,
i
.
namespace
,
helm
.
ValueOverrides
(
rawVals
),
helm
.
ReleaseName
(
i
.
name
),
helm
.
InstallDryRun
(
i
.
dryRun
),
helm
.
InstallReuseName
(
i
.
re
useNam
e
),
helm
.
InstallReuseName
(
i
.
re
plac
e
),
helm
.
InstallDisableHooks
(
i
.
disableHooks
))
if
err
!=
nil
{
return
prettyError
(
err
)
...
...
@@ -249,3 +265,16 @@ func locateChartPath(name string) (string, error) {
return
name
,
fmt
.
Errorf
(
"file %q not found"
,
origname
)
}
func
generateName
(
nameTemplate
string
)
(
string
,
error
)
{
t
,
err
:=
template
.
New
(
"name-template"
)
.
Funcs
(
sprig
.
TxtFuncMap
())
.
Parse
(
nameTemplate
)
if
err
!=
nil
{
return
""
,
err
}
var
b
bytes
.
Buffer
err
=
t
.
Execute
(
&
b
,
nil
)
if
err
!=
nil
{
return
""
,
err
}
return
b
.
String
(),
nil
}
cmd/helm/install_test.go
View file @
ae2d6c50
...
...
@@ -19,6 +19,7 @@ package main
import
(
"fmt"
"io"
"regexp"
"strings"
"testing"
...
...
@@ -59,12 +60,20 @@ func TestInstall(t *testing.T) {
},
// Install, re-use name
{
name
:
"install and re
use nam
e"
,
name
:
"install and re
place releas
e"
,
args
:
[]
string
{
"testdata/testcharts/alpine"
},
flags
:
strings
.
Split
(
"--name aeneas --re
use-nam
e"
,
" "
),
flags
:
strings
.
Split
(
"--name aeneas --re
plac
e"
,
" "
),
expected
:
"aeneas"
,
resp
:
releaseMock
(
&
releaseOptions
{
name
:
"aeneas"
}),
},
// Install, using the name-template
{
name
:
"install with name-template"
,
args
:
[]
string
{
"testdata/testcharts/alpine"
},
flags
:
[]
string
{
"--name-template"
,
"{{upper
\"
foobar
\"
}}"
},
expected
:
"FOOBAR"
,
resp
:
releaseMock
(
&
releaseOptions
{
name
:
"FOOBAR"
}),
},
}
runReleaseCases
(
t
,
tests
,
func
(
c
*
fakeReleaseClient
,
out
io
.
Writer
)
*
cobra
.
Command
{
...
...
@@ -113,3 +122,78 @@ sailor: sinbad
t
.
Errorf
(
"Expected String() to be
\n
%s
\n
Got
\n
%s
\n
"
,
y
,
out
)
}
}
type
nameTemplateTestCase
struct
{
tpl
string
expected
string
expectedErrorStr
string
}
func
TestNameTemplate
(
t
*
testing
.
T
)
{
testCases
:=
[]
nameTemplateTestCase
{
// Just a straight up nop please
{
tpl
:
"foobar"
,
expected
:
"foobar"
,
expectedErrorStr
:
""
,
},
// Random numbers at the end for fun & profit
{
tpl
:
"foobar-{{randNumeric 6}}"
,
expected
:
"foobar-[0-9]{6}$"
,
expectedErrorStr
:
""
,
},
// Random numbers in the middle for fun & profit
{
tpl
:
"foobar-{{randNumeric 4}}-baz"
,
expected
:
"foobar-[0-9]{4}-baz$"
,
expectedErrorStr
:
""
,
},
// No such function
{
tpl
:
"foobar-{{randInt}}"
,
expected
:
""
,
expectedErrorStr
:
"function
\"
randInt
\"
not defined"
,
},
// Invalid template
{
tpl
:
"foobar-{{"
,
expected
:
""
,
expectedErrorStr
:
"unexpected unclosed action"
,
},
}
for
_
,
tc
:=
range
testCases
{
n
,
err
:=
generateName
(
tc
.
tpl
)
if
err
!=
nil
{
if
tc
.
expectedErrorStr
==
""
{
t
.
Errorf
(
"Was not expecting error, but got: %v"
,
err
)
continue
}
re
,
compErr
:=
regexp
.
Compile
(
tc
.
expectedErrorStr
)
if
compErr
!=
nil
{
t
.
Errorf
(
"Expected error string failed to compile: %v"
,
compErr
)
continue
}
if
!
re
.
MatchString
(
err
.
Error
())
{
t
.
Errorf
(
"Error didn't match for %s expected %s but got %v"
,
tc
.
tpl
,
tc
.
expectedErrorStr
,
err
)
continue
}
}
if
err
==
nil
&&
tc
.
expectedErrorStr
!=
""
{
t
.
Errorf
(
"Was expecting error %s but didn't get an error back"
,
tc
.
expectedErrorStr
)
}
if
tc
.
expected
!=
""
{
re
,
err
:=
regexp
.
Compile
(
tc
.
expected
)
if
err
!=
nil
{
t
.
Errorf
(
"Expected string failed to compile: %v"
,
err
)
continue
}
if
!
re
.
MatchString
(
n
)
{
t
.
Errorf
(
"Returned name didn't match for %s expected %s but got %s"
,
tc
.
tpl
,
tc
.
expected
,
n
)
}
}
}
}
cmd/helm/lint.go
View file @
ae2d6c50
...
...
@@ -47,7 +47,10 @@ var lintCommand = &cobra.Command{
RunE
:
lintCmd
,
}
var
flagStrict
bool
func
init
()
{
lintCommand
.
Flags
()
.
BoolVarP
(
&
flagStrict
,
"strict"
,
""
,
false
,
"fail on lint warnings"
)
RootCommand
.
AddCommand
(
lintCommand
)
}
...
...
@@ -59,6 +62,13 @@ func lintCmd(cmd *cobra.Command, args []string) error {
paths
=
args
}
var
lowestTolerance
int
if
flagStrict
{
lowestTolerance
=
support
.
WarningSev
}
else
{
lowestTolerance
=
support
.
ErrorSev
}
var
total
int
var
failures
int
for
_
,
path
:=
range
paths
{
...
...
@@ -77,7 +87,7 @@ func lintCmd(cmd *cobra.Command, args []string) error {
}
total
=
total
+
1
if
linter
.
HighestSeverity
>=
support
.
ErrorSev
{
if
linter
.
HighestSeverity
>=
lowestTolerance
{
failures
=
failures
+
1
}
}
...
...
cmd/helm/serve.go
View file @
ae2d6c50
...
...
@@ -17,17 +17,19 @@ limitations under the License.
package
main
import
(
"os"
"path/filepath"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/repo"
)
var
serveDesc
=
`This command starts a local chart repository server that serves the charts saved in your $HELM_HOME/local/ directory.`
//TODO: add repoPath flag to be passed in in case you want
// to serve charts from a different local dir
var
serveDesc
=
`This command starts a local chart repository server that serves charts from a local directory.`
var
repoPath
string
func
init
()
{
serveCmd
.
Flags
()
.
StringVar
(
&
repoPath
,
"repo-path"
,
localRepoDirectory
(),
"The local directory path from which to serve charts."
)
RootCommand
.
AddCommand
(
serveCmd
)
}
...
...
@@ -35,9 +37,19 @@ var serveCmd = &cobra.Command{
Use
:
"serve"
,
Short
:
"start a local http web server"
,
Long
:
serveDesc
,
Run
:
serve
,
Run
E
:
serve
,
}
func
serve
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
repo
.
StartLocalRepo
(
localRepoDirectory
())
func
serve
(
cmd
*
cobra
.
Command
,
args
[]
string
)
error
{
repoPath
,
err
:=
filepath
.
Abs
(
repoPath
)
if
err
!=
nil
{
return
err
}
if
_
,
err
:=
os
.
Stat
(
repoPath
);
os
.
IsNotExist
(
err
)
{
return
err
}
repo
.
StartLocalRepo
(
repoPath
)
return
nil
}
cmd/helm/testdata/testcharts/novals/Chart.yaml
0 → 100644
View file @
ae2d6c50
description
:
Deploy a basic Alpine Linux pod
home
:
https://k8s.io/helm
name
:
novals
sources
:
-
https://github.com/kubernetes/helm
version
:
0.2.0
cmd/helm/testdata/testcharts/novals/README.md
0 → 100644
View file @
ae2d6c50
#Alpine: A simple Helm chart
Run a single pod of Alpine Linux.
This example was generated using the command
`helm create alpine`
.
The
`templates/`
directory contains a very simple pod resource with a
couple of parameters.
The
`values.yaml`
file contains the default values for the
`alpine-pod.yaml`
template.
You can install this example using
`helm install docs/examples/alpine`
.
cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml
0 → 100644
View file @
ae2d6c50
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
"
{{.Release.Name}}-{{.Values.Name}}"
labels
:
# The "heritage" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool
# is responsible for.
heritage
:
{{
.Release.Service | quote
}}
# The "release" convention makes it easy to tie a release to all of the
# Kubernetes resources that were created as part of that release.
release
:
{{
.Release.Name | quote
}}
# This makes it easy to audit chart usage.
chart
:
"
{{.Chart.Name}}-{{.Chart.Version}}"
annotations
:
"
helm.sh/created"
:
{{
.Release.Time.Seconds | quote
}}
spec
:
# This shows how to use a simple value. This will look for a passed-in value
# called restartPolicy. If it is not found, it will use the default value.
# {{default "Never" .restartPolicy}} is a slightly optimized version of the
# more conventional syntax: {{.restartPolicy | default "Never"}}
restartPolicy
:
{{
default "Never" .Values.restartPolicy
}}
containers
:
-
name
:
waiter
image
:
"
alpine:3.3"
command
:
[
"
/bin/sleep"
,
"
9000"
]
cmd/helm/upgrade.go
View file @
ae2d6c50
...
...
@@ -34,12 +34,13 @@ argument can be a relative path to a packaged or unpackaged chart.
`
type
upgradeCmd
struct
{
release
string
chart
string
out
io
.
Writer
client
helm
.
Interface
dryRun
bool
valuesFile
string
release
string
chart
string
out
io
.
Writer
client
helm
.
Interface
dryRun
bool
disableHooks
bool
valuesFile
string
}
func
newUpgradeCmd
(
client
helm
.
Interface
,
out
io
.
Writer
)
*
cobra
.
Command
{
...
...
@@ -70,6 +71,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
f
:=
cmd
.
Flags
()
f
.
StringVarP
(
&
upgrade
.
valuesFile
,
"values"
,
"f"
,
""
,
"path to a values YAML file"
)
f
.
BoolVar
(
&
upgrade
.
dryRun
,
"dry-run"
,
false
,
"simulate an upgrade"
)
f
.
BoolVar
(
&
upgrade
.
disableHooks
,
"disable-hooks"
,
false
,
"disable pre/post upgrade hooks"
)
return
cmd
}
...
...
@@ -88,12 +90,13 @@ func (u *upgradeCmd) run() error {
}
}
_
,
err
=
u
.
client
.
UpdateRelease
(
u
.
release
,
chartPath
,
helm
.
UpdateValueOverrides
(
rawVals
),
helm
.
UpgradeDryRun
(
u
.
dryRun
))
_
,
err
=
u
.
client
.
UpdateRelease
(
u
.
release
,
chartPath
,
helm
.
UpdateValueOverrides
(
rawVals
),
helm
.
UpgradeDryRun
(
u
.
dryRun
)
,
helm
.
UpgradeDisableHooks
(
u
.
disableHooks
)
)
if
err
!=
nil
{
return
prettyError
(
err
)
}
fmt
.
Fprintf
(
u
.
out
,
"It's not you. It's me
\n
Your upgrade looks valid but this command is still under active development.
\n
Hang tight.
\n
"
)
success
:=
u
.
release
+
" has been upgraded. Happy Helming!
\n
"
fmt
.
Fprintf
(
u
.
out
,
success
)
return
nil
...
...
cmd/helm/upgrade_test.go
View file @
ae2d6c50
...
...
@@ -52,18 +52,22 @@ func TestUpgradeCmd(t *testing.T) {
Description
:
"A Helm chart for Kubernetes"
,
Version
:
"0.1.2"
,
}
chartPath
,
err
=
chartutil
.
Create
(
cfile
,
tmpChart
)
if
err
!=
nil
{
t
.
Errorf
(
"Error creating chart: %v"
,
err
)
}
ch
,
_
=
chartutil
.
Load
(
chartPath
)
ch
,
err
=
chartutil
.
Load
(
chartPath
)
if
err
!=
nil
{
t
.
Errorf
(
"Error loading updated chart: %v"
,
err
)
}
tests
:=
[]
releaseCase
{
{
name
:
"upgrade a release"
,
args
:
[]
string
{
"funny-bunny"
,
chartPath
},
resp
:
releaseMock
(
&
releaseOptions
{
name
:
"funny-bunny"
,
version
:
2
,
chart
:
ch
}),
expected
:
"
It's not you. It's me
\n
Your upgrade looks valid but this command is still under active development.
\n
Hang tight.
\n
"
,
expected
:
"
funny-bunny has been upgraded. Happy Helming!
\n
"
,
},
}
...
...
cmd/tiller/environment/environment.go
View file @
ae2d6c50
...
...
@@ -117,6 +117,15 @@ type KubeClient interface {
// For all other kinds, it means the kind was created or modified without
// error.
WatchUntilReady
(
namespace
string
,
reader
io
.
Reader
)
error
// Update updates one or more resources or creates the resource
// if it doesn't exist
//
// namespace must contain a valid existing namespace
//
// reader must contain a YAML stream (one or more YAML documents separated
// by "\n---\n").
Update
(
namespace
string
,
originalReader
,
modifiedReader
io
.
Reader
)
error
}
// PrintingKubeClient implements KubeClient, but simply prints the reader to
...
...
@@ -145,6 +154,12 @@ func (p *PrintingKubeClient) WatchUntilReady(ns string, r io.Reader) error {
return
err
}
// Update implements KubeClient Update.
func
(
p
*
PrintingKubeClient
)
Update
(
ns
string
,
currentReader
,
modifiedReader
io
.
Reader
)
error
{
_
,
err
:=
io
.
Copy
(
p
.
Out
,
modifiedReader
)
return
err
}
// Environment provides the context for executing a client request.
//
// All services in a context are concurrency safe.
...
...
cmd/tiller/environment/environment_test.go
View file @
ae2d6c50
...
...
@@ -87,6 +87,9 @@ func (k *mockKubeClient) Create(ns string, r io.Reader) error {
func
(
k
*
mockKubeClient
)
Delete
(
ns
string
,
r
io
.
Reader
)
error
{
return
nil
}
func
(
k
*
mockKubeClient
)
Update
(
ns
string
,
currentReader
,
modifiedReader
io
.
Reader
)
error
{
return
nil
}
func
(
k
*
mockKubeClient
)
WatchUntilReady
(
ns
string
,
r
io
.
Reader
)
error
{
return
nil
}
...
...
cmd/tiller/release_server.go
View file @
ae2d6c50
...
...
@@ -24,7 +24,6 @@ import (
"regexp"
"sort"
"github.com/Masterminds/semver"
"github.com/ghodss/yaml"
"github.com/technosophos/moniker"
ctx
"golang.org/x/net/context"
...
...
@@ -171,65 +170,107 @@ func (s *releaseServer) GetReleaseContent(c ctx.Context, req *services.GetReleas
}
func
(
s
*
releaseServer
)
UpdateRelease
(
c
ctx
.
Context
,
req
*
services
.
UpdateReleaseRequest
)
(
*
services
.
UpdateReleaseResponse
,
error
)
{
rel
,
err
:=
s
.
prepareUpdate
(
req
)
currentRelease
,
updatedRelease
,
err
:=
s
.
prepareUpdate
(
req
)
if
err
!=
nil
{
return
nil
,
err
}
// TODO: perform update
res
,
err
:=
s
.
performUpdate
(
currentRelease
,
updatedRelease
,
req
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
:=
s
.
env
.
Releases
.
Update
(
updatedRelease
);
err
!=
nil
{
return
nil
,
err
}
return
res
,
nil
}
func
(
s
*
releaseServer
)
performUpdate
(
originalRelease
,
updatedRelease
*
release
.
Release
,
req
*
services
.
UpdateReleaseRequest
)
(
*
services
.
UpdateReleaseResponse
,
error
)
{
res
:=
&
services
.
UpdateReleaseResponse
{
Release
:
updatedRelease
}
if
req
.
DryRun
{
log
.
Printf
(
"Dry run for %s"
,
updatedRelease
.
Name
)
return
res
,
nil
}
// pre-ugrade hooks
if
!
req
.
DisableHooks
{
if
err
:=
s
.
execHook
(
updatedRelease
.
Hooks
,
updatedRelease
.
Name
,
updatedRelease
.
Namespace
,
preUpgrade
);
err
!=
nil
{
return
res
,
err
}
}
kubeCli
:=
s
.
env
.
KubeClient
original
:=
bytes
.
NewBufferString
(
originalRelease
.
Manifest
)
modified
:=
bytes
.
NewBufferString
(
updatedRelease
.
Manifest
)
if
err
:=
kubeCli
.
Update
(
updatedRelease
.
Namespace
,
original
,
modified
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Update of %s failed: %s"
,
updatedRelease
.
Name
,
err
)
}
// post-upgrade hooks
if
!
req
.
DisableHooks
{
if
err
:=
s
.
execHook
(
updatedRelease
.
Hooks
,
updatedRelease
.
Name
,
updatedRelease
.
Namespace
,
postUpgrade
);
err
!=
nil
{
return
res
,
err
}
}
return
&
services
.
UpdateReleaseResponse
{
Release
:
rel
},
nil
updatedRelease
.
Info
.
Status
.
Code
=
release
.
Status_DEPLOYED
return
res
,
nil
}
// prepareUpdate builds a release for an update operation.
func
(
s
*
releaseServer
)
prepareUpdate
(
req
*
services
.
UpdateReleaseRequest
)
(
*
release
.
Release
,
error
)
{
// prepareUpdate builds a
n updated
release for an update operation.
func
(
s
*
releaseServer
)
prepareUpdate
(
req
*
services
.
UpdateReleaseRequest
)
(
*
release
.
Release
,
*
release
.
Release
,
error
)
{
if
req
.
Name
==
""
{
return
nil
,
errMissingRelease
return
nil
,
nil
,
errMissingRelease
}
if
req
.
Chart
==
nil
{
return
nil
,
errMissingChart
return
nil
,
nil
,
errMissingChart
}
// finds the non-deleted release with the given name
rel
,
err
:=
s
.
env
.
Releases
.
Get
(
req
.
Name
)
currentRelease
,
err
:=
s
.
env
.
Releases
.
Get
(
req
.
Name
)
if
err
!=
nil
{
return
nil
,
err
return
nil
,
nil
,
err
}
//validate chart name is same as previous release
givenChart
:=
req
.
Chart
.
Metadata
.
Name
releasedChart
:=
rel
.
Chart
.
Metadata
.
Name
if
givenChart
!=
releasedChart
{
return
nil
,
fmt
.
Errorf
(
"Given chart, %s, does not match chart originally released, %s"
,
givenChart
,
releasedChart
)
ts
:=
timeconv
.
Now
()
options
:=
chartutil
.
ReleaseOptions
{
Name
:
req
.
Name
,
Time
:
ts
,
Namespace
:
currentRelease
.
Namespace
,
}
// validate new chart version is higher than old
givenChartVersion
:=
req
.
Chart
.
Metadata
.
Version
releasedChartVersion
:=
rel
.
Chart
.
Metadata
.
Version
c
,
err
:=
semver
.
NewConstraint
(
"> "
+
releasedChartVersion
)
valuesToRender
,
err
:=
chartutil
.
ToRenderValues
(
req
.
Chart
,
req
.
Values
,
options
)
if
err
!=
nil
{
return
nil
,
err
return
nil
,
nil
,
err
}
v
,
err
:=
semver
.
NewVersion
(
givenChartVersion
)
hooks
,
manifestDoc
,
err
:=
s
.
renderResources
(
req
.
Chart
,
valuesToRender
)
if
err
!=
nil
{
return
nil
,
err
}
if
a
:=
c
.
Check
(
v
);
!
a
{
return
nil
,
fmt
.
Errorf
(
"Given chart (%s-%v) must be a higher version than released chart (%s-%v)"
,
givenChart
,
givenChartVersion
,
releasedChart
,
releasedChartVersion
)
return
nil
,
nil
,
err
}
// Store an updated release.
updatedRelease
:=
&
release
.
Release
{
Name
:
req
.
Name
,
Chart
:
req
.
Chart
,
Config
:
req
.
Values
,
Version
:
rel
.
Version
+
1
,
Name
:
req
.
Name
,
Namespace
:
currentRelease
.
Namespace
,
Chart
:
req
.
Chart
,
Config
:
req
.
Values
,
Info
:
&
release
.
Info
{
FirstDeployed
:
currentRelease
.
Info
.
FirstDeployed
,
LastDeployed
:
ts
,
Status
:
&
release
.
Status
{
Code
:
release
.
Status_UNKNOWN
},
},
Version
:
currentRelease
.
Version
+
1
,
Manifest
:
manifestDoc
.
String
(),
Hooks
:
hooks
,
}
return
updatedRelease
,
nil
return
currentRelease
,
updatedRelease
,
nil
}
func
(
s
*
releaseServer
)
uniqName
(
start
string
,
reuse
bool
)
(
string
,
error
)
{
...
...
@@ -240,10 +281,12 @@ func (s *releaseServer) uniqName(start string, reuse bool) (string, error) {
if
start
!=
""
{
if
rel
,
err
:=
s
.
env
.
Releases
.
Get
(
start
);
err
==
driver
.
ErrReleaseNotFound
{
return
start
,
nil
}
else
if
reuse
&&
rel
.
Info
.
Status
.
Code
==
release
.
Status_DELETED
{
}
else
if
st
:=
rel
.
Info
.
Status
.
Code
;
reuse
&&
(
st
==
release
.
Status_DELETED
||
st
==
release
.
Status_FAILED
)
{
// Allowe re-use of names if the previous release is marked deleted.
log
.
Printf
(
"reusing name %q"
,
start
)
return
start
,
nil
}
else
if
reuse
{
return
""
,
errors
.
New
(
"cannot re-use a name that is still in use"
)
}
return
""
,
fmt
.
Errorf
(
"a release named %q already exists"
,
start
)
...
...
@@ -306,12 +349,36 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
return
nil
,
err
}
renderer
:=
s
.
engine
(
req
.
Chart
)
files
,
err
:=
renderer
.
Render
(
req
.
Chart
,
valuesToRender
)
hooks
,
manifestDoc
,
err
:=
s
.
renderResources
(
req
.
Chart
,
valuesToRender
)
if
err
!=
nil
{
return
nil
,
err
}
// Store a release.
rel
:=
&
release
.
Release
{
Name
:
name
,
Namespace
:
req
.
Namespace
,
Chart
:
req
.
Chart
,
Config
:
req
.
Values
,
Info
:
&
release
.
Info
{
FirstDeployed
:
ts
,
LastDeployed
:
ts
,
Status
:
&
release
.
Status
{
Code
:
release
.
Status_UNKNOWN
},
},
Manifest
:
manifestDoc
.
String
(),
Hooks
:
hooks
,
Version
:
1
,
}
return
rel
,
nil
}
func
(
s
*
releaseServer
)
renderResources
(
ch
*
chart
.
Chart
,
values
chartutil
.
Values
)
([]
*
release
.
Hook
,
*
bytes
.
Buffer
,
error
)
{
renderer
:=
s
.
engine
(
ch
)
files
,
err
:=
renderer
.
Render
(
ch
,
values
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
// Sort hooks, manifests, and partials. Only hooks and manifests are returned,
// as partials are not used after renderer.Render. Empty manifests are also
// removed here.
...
...
@@ -319,7 +386,7 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
if
err
!=
nil
{
// By catching parse errors here, we can prevent bogus releases from going
// to Kubernetes.
return
nil
,
err
return
nil
,
nil
,
err
}
// Aggregate all valid manifests into one big doc.
...
...
@@ -329,22 +396,7 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
b
.
WriteString
(
file
)
}
// Store a release.
rel
:=
&
release
.
Release
{
Name
:
name
,
Namespace
:
req
.
Namespace
,
Chart
:
req
.
Chart
,
Config
:
req
.
Values
,
Info
:
&
release
.
Info
{
FirstDeployed
:
ts
,
LastDeployed
:
ts
,
Status
:
&
release
.
Status
{
Code
:
release
.
Status_UNKNOWN
},
},
Manifest
:
b
.
String
(),
Hooks
:
hooks
,
Version
:
1
,
}
return
rel
,
nil
return
hooks
,
b
,
nil
}
// validateYAML checks to see if YAML is well-formed.
...
...
cmd/tiller/release_server_test.go
View file @
ae2d6c50
...
...
@@ -45,6 +45,16 @@ data:
name: value
`
var
manifestWithUpgradeHooks
=
`apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
annotations:
"helm.sh/hook": post-upgrade,pre-upgrade
data:
name: value
`
func
rsFixture
()
*
releaseServer
{
return
&
releaseServer
{
env
:
mockEnvironment
(),
...
...
@@ -80,8 +90,9 @@ func releaseStub() *release.Release {
LastDeployed
:
&
date
,
Status
:
&
release
.
Status
{
Code
:
release
.
Status_DEPLOYED
},
},
Chart
:
chartStub
(),
Config
:
&
chart
.
Config
{
Raw
:
`name = "value"`
},
Chart
:
chartStub
(),
Config
:
&
chart
.
Config
{
Raw
:
`name = "value"`
},
Version
:
1
,
Hooks
:
[]
*
release
.
Hook
{
{
Name
:
"test-cm"
,
...
...
@@ -290,6 +301,105 @@ func TestInstallReleaseReuseName(t *testing.T) {
}
}
func
TestUpdateRelease
(
t
*
testing
.
T
)
{
c
:=
context
.
Background
()
rs
:=
rsFixture
()
rel
:=
releaseStub
()
rs
.
env
.
Releases
.
Create
(
rel
)
req
:=
&
services
.
UpdateReleaseRequest
{
Name
:
rel
.
Name
,
Chart
:
&
chart
.
Chart
{
Metadata
:
&
chart
.
Metadata
{
Name
:
"hello"
},
Templates
:
[]
*
chart
.
Template
{
{
Name
:
"hello"
,
Data
:
[]
byte
(
"hello: world"
)},
{
Name
:
"hooks"
,
Data
:
[]
byte
(
manifestWithUpgradeHooks
)},
},
},
}
res
,
err
:=
rs
.
UpdateRelease
(
c
,
req
)
if
err
!=
nil
{
t
.
Errorf
(
"Failed updated: %s"
,
err
)
}
if
res
.
Release
.
Name
==
""
{
t
.
Errorf
(
"Expected release name."
)
}
if
res
.
Release
.
Name
!=
rel
.
Name
{
t
.
Errorf
(
"Updated release name does not match previous release name. Expected %s, got %s"
,
rel
.
Name
,
res
.
Release
.
Name
)
}
if
res
.
Release
.
Namespace
!=
rel
.
Namespace
{
t
.
Errorf
(
"Expected release namespace '%s', got '%s'."
,
rel
.
Namespace
,
res
.
Release
.
Namespace
)
}
updated
,
err
:=
rs
.
env
.
Releases
.
Get
(
res
.
Release
.
Name
)
if
err
!=
nil
{
t
.
Errorf
(
"Expected release for %s (%v)."
,
res
.
Release
.
Name
,
rs
.
env
.
Releases
)
}
if
len
(
updated
.
Hooks
)
!=
1
{
t
.
Fatalf
(
"Expected 1 hook, got %d"
,
len
(
updated
.
Hooks
))
}
if
updated
.
Hooks
[
0
]
.
Manifest
!=
manifestWithUpgradeHooks
{
t
.
Errorf
(
"Unexpected manifest: %v"
,
updated
.
Hooks
[
0
]
.
Manifest
)
}
if
updated
.
Hooks
[
0
]
.
Events
[
0
]
!=
release
.
Hook_POST_UPGRADE
{
t
.
Errorf
(
"Expected event 0 to be post upgrade"
)
}
if
updated
.
Hooks
[
0
]
.
Events
[
1
]
!=
release
.
Hook_PRE_UPGRADE
{
t
.
Errorf
(
"Expected event 0 to be pre upgrade"
)
}
if
len
(
res
.
Release
.
Manifest
)
==
0
{
t
.
Errorf
(
"No manifest returned: %v"
,
res
.
Release
)
}
if
len
(
updated
.
Manifest
)
==
0
{
t
.
Errorf
(
"Expected manifest in %v"
,
res
)
}
if
!
strings
.
Contains
(
updated
.
Manifest
,
"---
\n
# Source: hello/hello
\n
hello: world"
)
{
t
.
Errorf
(
"unexpected output: %s"
,
rel
.
Manifest
)
}
if
res
.
Release
.
Version
!=
2
{
t
.
Errorf
(
"Expected release version to be %v, got %v"
,
2
,
res
.
Release
.
Version
)
}
}
func
TestUpdateReleaseNoHooks
(
t
*
testing
.
T
)
{
c
:=
context
.
Background
()
rs
:=
rsFixture
()
rel
:=
releaseStub
()
rs
.
env
.
Releases
.
Create
(
rel
)
req
:=
&
services
.
UpdateReleaseRequest
{
Name
:
rel
.
Name
,
DisableHooks
:
true
,
Chart
:
&
chart
.
Chart
{
Metadata
:
&
chart
.
Metadata
{
Name
:
"hello"
},
Templates
:
[]
*
chart
.
Template
{
{
Name
:
"hello"
,
Data
:
[]
byte
(
"hello: world"
)},
{
Name
:
"hooks"
,
Data
:
[]
byte
(
manifestWithUpgradeHooks
)},
},
},
}
res
,
err
:=
rs
.
UpdateRelease
(
c
,
req
)
if
err
!=
nil
{
t
.
Errorf
(
"Failed updated: %s"
,
err
)
}
if
hl
:=
res
.
Release
.
Hooks
[
0
]
.
LastRun
;
hl
!=
nil
{
t
.
Errorf
(
"Expected that no hooks were run. Got %d"
,
hl
)
}
}
func
TestUninstallRelease
(
t
*
testing
.
T
)
{
c
:=
context
.
Background
()
rs
:=
rsFixture
()
...
...
docs/architecture.md
View file @
ae2d6c50
...
...
@@ -75,9 +75,8 @@ The Go files generated from the `proto` definitions are stored in
Docker images are built by cross-compiling Linux binaries and then
building a Docker image from the files in
`rootfs`
.
The
`scripts/`
directory contains a number of utility scripts, including
`local-cluster.sh`
, which can start a full Kubernetes instance inside of
a Docker container.
The
`scripts/`
directory contains a number of utility scripts. Most of these
are used by the CI/CD pipeline.
Go dependencies are managed with
[
Glide
](
https://github.com/Masterminds/glide
)
and stored in the
...
...
docs/charts.md
View file @
ae2d6c50
...
...
@@ -202,6 +202,11 @@ sensitive_.
-
`Chart`
: The contents of the
`Chart.yaml`
. Thus, the chart version is
obtainable as
`Chart.Version`
and the maintainers are in
`Chart.Maintainers`
.
-
`Files`
: A map-like object containing all non-special files in the chart. This
will not give you access to templates, but will give you access to additional
files that are present. Files can be accessed using
`{{index .Files "file.name"}}`
or using the
`{{.Files.Get name}}`
or
`{{.Files.GetString name}}`
functions. Note that
file data is returned as a
`[]byte`
unless
`{{.Files.GetString}}`
is used.
**NOTE:**
Any unknown Chart.yaml fields will be dropped. They will not
be accessible inside of the
`Chart`
object. Thus, Chart.yaml cannot be
...
...
docs/developers.md
View file @
ae2d6c50
...
...
@@ -66,11 +66,31 @@ GCR registry.
## Running a Local Cluster
You can run tests locally using the
`scripts/local-cluster.sh`
script to
start Kubernetes inside of a Docker container. For OS X, you will need
to be running
`docker-machine`
.
For development, we highly recommend using the
[
Kubernetes Minikube
](
https://github.com/kubernetes/minikube
)
developer-oriented distribution. Once this is installed, you can use
`helm init`
to install into the cluster.
Tiller should run on any >= 1.2 Kubernetes cluster with beta extensions.
For developing on Tiller, it is sometimes more expedient to run Tiller locally
instead of packaging it into an image and running it in-cluster. You can do
this by telling the Helm client to us a local instance.
```
console
$
make build
$
bin/tiller
```
And to configure the Helm client, use the
`--host`
flag or export the
`HELM_HOST`
environment variable:
```
console
$
export
HELM_HOST
=
localhost:44134
$
helm
install
foo
```
(Note that you do not need to use
`helm init`
when you are running Tiller directly)
Tiller should run on any >= 1.3 Kubernetes cluster.
## Contribution Guidelines
...
...
glide.lock
View file @
ae2d6c50
hash:
141ef5b9c491c91b026ab4007e48502c9a6df9f173c40e1406233dd44f065190
updated: 2016-07-
05T16:51:52.631048739
-07:00
hash:
d3f3df18316dca3703f5d073e8f9b1e6bfdb27e8d7fc9c5d742afeddebb022db
updated: 2016-07-
30T23:52:42.581826208
-07:00
imports:
- name: github.com/aokoli/goutils
version: 9c37978a95bd5c709a15883b6242714ea6709e64
- name: github.com/asaskevich/govalidator
version:
df81827fdd59d8b4fb93d8910b286ab7a3919520
version:
7664702784775e51966f0885f5cd27435916517b
- name: github.com/beorn7/perks
version: 3ac7bf7a47d159a033b107610db8a1b6575507a4
subpackages:
...
...
@@ -133,7 +133,7 @@ imports:
- ptypes/any
- ptypes/timestamp
- name: github.com/google/cadvisor
version:
4dbefc9b671b81257973a33211fb12370c1a526e
version:
c2ea32971ae033041f0fb0f309b1dee94fd1d55f
subpackages:
- api
- cache/memory
...
...
@@ -267,15 +267,15 @@ imports:
- name: google.golang.org/appengine
version: 12d5545dc1cfa6047a286d5e853841b6471f4c19
subpackages:
- urlfetch
- internal
- internal/urlfetch
- internal/app_identity
- internal/modules
- internal/base
- internal/datastore
- internal/log
- internal/modules
- internal/remote_api
- urlfetch
- internal/urlfetch
- name: google.golang.org/cloud
version: eb47ba841d53d93506cfbfbc03927daf9cc48f88
subpackages:
...
...
@@ -297,40 +297,67 @@ imports:
- name: gopkg.in/yaml.v2
version: a83829b6f1293c91addabc89d0571c246397bbf4
- name: k8s.io/kubernetes
version:
283137936a498aed572ee22af6774b6fb6e9fd94
version:
e7f022c926583ed8e755a52f23abc4cf8b532d12
subpackages:
- pkg/api
- pkg/api/meta
- pkg/api/error
- pkg/client/restclient
- pkg/client/unversioned
- pkg/apis/batch
- pkg/client/unversioned/clientcmd
- pkg/client/unversioned/fake
- pkg/client/unversioned/portforward
- pkg/client/unversioned/remotecommand
- pkg/kubectl
- pkg/kubectl/cmd/util
- pkg/kubectl/resource
- pkg/labels
- pkg/runtime
- pkg/watch
- pkg/api/errors
- pkg/client/unversioned/testclient
- pkg/api/meta/metatypes
- pkg/api/resource
- pkg/api/unversioned
- pkg/auth/user
- pkg/conversion
- pkg/fields
- pkg/runtime
- pkg/runtime/serializer
- pkg/types
- pkg/util
- pkg/util/intstr
- pkg/util/rand
- pkg/util/sets
- pkg/api/install
- pkg/apimachinery/registered
- pkg/apis/apps
- pkg/apis/apps/install
- pkg/apis/authentication.k8s.io/install
- pkg/apis/authorization/install
- pkg/apis/autoscaling
- pkg/apis/autoscaling/install
- pkg/apis/batch/install
- pkg/apis/batch/v2alpha1
- pkg/apis/componentconfig/install
- pkg/apis/extensions
- pkg/apis/extensions/install
- pkg/apis/policy
- pkg/apis/policy/install
- pkg/apis/rbac
- pkg/apis/rbac/install
- pkg/client/typed/discovery
- pkg/util/net
- pkg/util/wait
- pkg/version
- plugin/pkg/client/auth
- pkg/util/validation
- pkg/util/validation/field
- pkg/client/unversioned/auth
- pkg/client/unversioned/clientcmd/api
- pkg/client/unversioned/clientcmd/api/latest
- pkg/util/errors
- pkg/util/homedir
- pkg/util/validation
- pkg/util/validation/field
- pkg/kubelet/server/portforward
- pkg/util/httpstream
- pkg/util/runtime
...
...
@@ -339,42 +366,53 @@ imports:
- pkg/util/httpstream/spdy
- federation/apis/federation
- federation/client/clientset_generated/federation_internalclientset
- pkg/api/service
- pkg/api/annotations
- pkg/api/util
- pkg/api/v1
- pkg/api/validation
- pkg/apimachinery
- pkg/apimachinery/registered
- pkg/apis/apps
- pkg/apis/autoscaling
- pkg/apis/batch
- pkg/apis/extensions
- pkg/apis/policy
- pkg/apis/rbac
- pkg/client/typed/discovery
- pkg/apis/batch/v1
- pkg/client/clientset_generated/internalclientset
- pkg/client/unversioned/adapters/internalclientset
- pkg/credentialprovider
- pkg/fieldpath
- pkg/kubelet/qos/util
- pkg/util/deployment
- pkg/util/integer
- pkg/util/jsonpath
- pkg/util/slice
- pkg/api/service
- pkg/apimachinery
- pkg/controller
- pkg/kubectl
- pkg/registry/thirdpartyresourcedata
- pkg/runtime/serializer/json
- pkg/util/flag
- pkg/util/strategicpatch
- pkg/watch
- pkg/util/yaml
- pkg/api/testapi
- third_party/forked/reflect
- pkg/conversion/queryparams
- pkg/util/json
- pkg/api/testapi
- third_party/forked/reflect
- pkg/runtime/serializer/protobuf
- pkg/runtime/serializer/recognizer
- pkg/runtime/serializer/versioning
- pkg/util/wait
- pkg/api/v1
- pkg/watch/versioned
- pkg/apis/apps/v1alpha1
- pkg/apis/authentication.k8s.io
- pkg/apis/authentication.k8s.io/v1beta1
- pkg/apis/authorization
- pkg/apis/authorization/v1beta1
- pkg/apis/autoscaling/v1
- pkg/apis/componentconfig
- pkg/apis/componentconfig/v1alpha1
- pkg/apis/extensions/v1beta1
- pkg/apis/policy/v1alpha1
- pkg/apis/rbac/v1alpha1
- pkg/client/metrics
- pkg/runtime/serializer/streaming
- pkg/util/crypto
- pkg/util/flowcontrol
- pkg/util/net
- pkg/version
- pkg/watch/versioned
- plugin/pkg/client/auth/gcp
- plugin/pkg/client/auth/oidc
- pkg/client/unversioned/clientcmd/api/v1
- pkg/httplog
- pkg/util/wsstream
...
...
@@ -382,71 +420,35 @@ imports:
- federation/apis/federation/install
- federation/client/clientset_generated/federation_internalclientset/typed/core/unversioned
- federation/client/clientset_generated/federation_internalclientset/typed/federation/unversioned
- pkg/util/
net/set
s
- pkg/util/
parser
s
- pkg/api/endpoints
- pkg/api/pod
- pkg/api/unversioned/validation
- pkg/api/util
- pkg/capabilities
- pkg/api/install
- pkg/apis/apps/install
- pkg/apis/authentication.k8s.io/install
- pkg/apis/authorization/install
- pkg/apis/autoscaling/install
- pkg/apis/batch/install
- pkg/apis/batch/v2alpha1
- pkg/apis/componentconfig/install
- pkg/apis/extensions/install
- pkg/apis/policy/install
- pkg/apis/rbac/install
- plugin/pkg/client/auth
- pkg/client/clientset_generated/internalclientset
- pkg/client/clientset_generated/internalclientset/typed/autoscaling/unversioned
- pkg/client/clientset_generated/internalclientset/typed/batch/unversioned
- pkg/client/clientset_generated/internalclientset/typed/core/unversioned
- pkg/client/clientset_generated/internalclientset/typed/extensions/unversioned
- pkg/client/clientset_generated/internalclientset/typed/rbac/unversioned
- pkg/util/labels
- pkg/util/pod
- pkg/util/replicaset
- third_party/golang/template
- pkg/util/net/sets
- pkg/client/cache
- pkg/client/record
- pkg/controller/framework
- pkg/util/hash
- pkg/util/integer
- pkg/api/annotations
- pkg/apis/batch/v1
- pkg/credentialprovider
- pkg/fieldpath
- pkg/kubelet/qos/util
- pkg/util/deployment
- pkg/util/jsonpath
- pkg/util/slice
- pkg/api/rest
- pkg/apis/extensions/v1beta1
- pkg/apis/extensions/validation
- pkg/registry/generic
- pkg/util/framer
- third_party/forked/json
- pkg/util/parsers
- pkg/kubelet/qos
- pkg/master/ports
- federation/apis/federation/v1beta1
- pkg/apis/apps/v1alpha1
- pkg/apis/authentication.k8s.io
- pkg/apis/authentication.k8s.io/v1beta1
- pkg/apis/authorization
- pkg/apis/authorization/v1beta1
- pkg/apis/autoscaling/v1
- pkg/apis/componentconfig
- pkg/apis/componentconfig/v1alpha1
- pkg/apis/policy/v1alpha1
- pkg/apis/rbac/v1alpha1
- plugin/pkg/client/auth/gcp
- plugin/pkg/client/auth/oidc
- pkg/client/clientset_generated/internalclientset/typed/autoscaling/unversioned
- pkg/client/clientset_generated/internalclientset/typed/rbac/unversioned
- pkg/util/labels
- pkg/util/pod
- pkg/util/replicaset
- third_party/golang/template
- pkg/security/podsecuritypolicy/util
- pkg/storage
- pkg/kubelet/qos
- pkg/master/ports
- name: speter.net/go/exp/math/dec/inf
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
repo: https://github.com/go-inf/inf.git
...
...
glide.yaml
View file @
ae2d6c50
...
...
@@ -22,22 +22,32 @@ import:
-
package
:
google.golang.org/grpc
version
:
dec33edc378cf4971a2741cfd86ed70a644d6ba3
-
package
:
k8s.io/kubernetes
version
:
v1.3.0
version
:
~1.3
subpackages
:
-
pkg/api
-
pkg/api/meta
-
pkg/api/error
-
pkg/api/unversioned
-
pkg/apimachinery/registered
-
pkg/client/restclient
-
pkg/client/unversioned
-
pkg/apis/batch
-
pkg/client/unversioned/clientcmd
-
pkg/client/unversioned/fake
-
pkg/client/unversioned/portforward
-
pkg/client/unversioned/remotecommand
-
pkg/kubectl
-
pkg/kubectl/cmd/util
-
pkg/kubectl/resource
-
pkg/labels
-
pkg/runtime
-
pkg/watch
-
pkg/util/strategicpatch
-
pkg/util/yaml
-
package
:
github.com/gosuri/uitable
-
package
:
speter.net/go/exp/math/dec/inf
version
:
^0.9.0
repo
:
https://github.com/go-inf/inf.git
vcs
:
git
-
package
:
github.com/asaskevich/govalidator
-
package
:
github.com/satori/go.uuid
version
:
^4.0.0
pkg/chartutil/create.go
View file @
ae2d6c50
...
...
@@ -48,7 +48,23 @@ const defaultIgnore = `# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
.git
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
`
// Create creates a new chart in a directory.
...
...
pkg/chartutil/files.go
View file @
ae2d6c50
...
...
@@ -32,11 +32,14 @@ func NewFiles(from []*any.Any) Files {
return
files
}
// Get a file by path.
// GetBytes gets a file by path.
//
// The returned data is raw. In a template context, this is identical to calling
// {{index .Files $path}}.
//
// This is intended to be accessed from within a template, so a missed key returns
// an empty []byte.
func
(
f
Files
)
Get
(
name
string
)
[]
byte
{
func
(
f
Files
)
Get
Bytes
(
name
string
)
[]
byte
{
v
,
ok
:=
f
[
name
]
if
!
ok
{
return
[]
byte
{}
...
...
@@ -44,10 +47,12 @@ func (f Files) Get(name string) []byte {
return
v
}
// GetString returns a string representation of the given file.
// Get returns a string representation of the given file.
//
// Fetch the contents of a file as a string. It is designed to be called in a
// template.
//
// This is a convenience for the otherwise cumbersome template logic
// for '{{.Files.Get "foo" | printf "%s"}}'.
func
(
f
Files
)
GetString
(
name
string
)
string
{
return
string
(
f
.
Get
(
name
))
// {{.Files.Get "foo"}}
func
(
f
Files
)
Get
(
name
string
)
string
{
return
string
(
f
.
GetBytes
(
name
))
}
pkg/chartutil/files_test.go
View file @
ae2d6c50
...
...
@@ -43,10 +43,10 @@ func TestNewFiles(t *testing.T) {
}
for
i
,
f
:=
range
cases
{
if
got
:=
string
(
files
.
Get
(
f
.
path
));
got
!=
f
.
data
{
if
got
:=
string
(
files
.
Get
Bytes
(
f
.
path
));
got
!=
f
.
data
{
t
.
Errorf
(
"%d: expected %q, got %q"
,
i
,
f
.
data
,
got
)
}
if
got
:=
files
.
Get
String
(
f
.
path
);
got
!=
f
.
data
{
if
got
:=
files
.
Get
(
f
.
path
);
got
!=
f
.
data
{
t
.
Errorf
(
"%d: expected %q, got %q"
,
i
,
f
.
data
,
got
)
}
}
...
...
pkg/chartutil/load.go
View file @
ae2d6c50
...
...
@@ -218,6 +218,11 @@ func LoadDir(dir string) (*chart.Chart, error) {
return
err
}
if
fi
.
IsDir
()
{
// Directory-based ignore rules should involve skipping the entire
// contents of that directory.
if
rules
.
Ignore
(
n
,
fi
)
{
return
filepath
.
SkipDir
}
return
nil
}
...
...
pkg/chartutil/load_test.go
View file @
ae2d6c50
...
...
@@ -49,8 +49,9 @@ func verifyChart(t *testing.T, c *chart.Chart) {
t
.
Errorf
(
"Expected 1 template, got %d"
,
len
(
c
.
Templates
))
}
if
len
(
c
.
Files
)
!=
5
{
t
.
Errorf
(
"Expected 5 extra files, got %d"
,
len
(
c
.
Files
))
numfiles
:=
6
if
len
(
c
.
Files
)
!=
numfiles
{
t
.
Errorf
(
"Expected %d extra files, got %d"
,
numfiles
,
len
(
c
.
Files
))
for
_
,
n
:=
range
c
.
Files
{
t
.
Logf
(
"
\t
%s"
,
n
.
TypeUrl
)
}
...
...
pkg/chartutil/testdata/frobnitz-1.2.3.tgz
View file @
ae2d6c50
No preview for this file type
pkg/chartutil/testdata/frobnitz/.helmignore
0 → 100644
View file @
ae2d6c50
ignore/
pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz
View file @
ae2d6c50
No preview for this file type
pkg/chartutil/testdata/frobnitz/ignore/me.txt
0 → 100644
View file @
ae2d6c50
pkg/chartutil/testdata/genfrob.sh
View file @
ae2d6c50
...
...
@@ -9,4 +9,4 @@ tar -zcvf frobnitz/charts/mariner-4.3.2.tgz mariner
# Pack the frobnitz chart.
echo
"Packing frobnitz"
tar
-zcvf
frobnitz-1.2.3.tgz frobnitz
tar
-
-exclude
=
ignore/
*
-
zcvf
frobnitz-1.2.3.tgz frobnitz
pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz
View file @
ae2d6c50
No preview for this file type
pkg/client/install.go
View file @
ae2d6c50
...
...
@@ -66,19 +66,13 @@ func Install(namespace, image string, verbose bool) error {
// InstallYAML is the installation YAML for DM.
const
InstallYAML
=
`
---
apiVersion:
v
1
kind:
ReplicationController
apiVersion:
extensions/v1beta
1
kind:
Deployment
metadata:
labels:
app: helm
name: tiller
name: tiller-rc
name: tiller-deploy
namespace: {{ .Namespace }}
spec:
replicas: 1
selector:
app: helm
name: tiller
template:
metadata:
labels:
...
...
pkg/engine/engine.go
View file @
ae2d6c50
...
...
@@ -88,6 +88,28 @@ type renderable struct {
vals
chartutil
.
Values
}
// alterFuncMap takes the Engine's FuncMap and adds context-specific functions.
//
// The resulting FuncMap is only valid for the passed-in template.
func
(
e
*
Engine
)
alterFuncMap
(
t
*
template
.
Template
)
template
.
FuncMap
{
// Clone the func map because we are adding context-specific functions.
var
funcMap
template
.
FuncMap
=
map
[
string
]
interface
{}{}
for
k
,
v
:=
range
e
.
FuncMap
{
funcMap
[
k
]
=
v
}
// Add the 'include' function here so we can close over t.
funcMap
[
"include"
]
=
func
(
name
string
,
data
interface
{})
string
{
buf
:=
bytes
.
NewBuffer
(
nil
)
if
err
:=
t
.
ExecuteTemplate
(
buf
,
name
,
data
);
err
!=
nil
{
buf
.
WriteString
(
err
.
Error
())
}
return
buf
.
String
()
}
return
funcMap
}
// render takes a map of templates/values and renders them.
func
(
e
*
Engine
)
render
(
tpls
map
[
string
]
renderable
)
(
map
[
string
]
string
,
error
)
{
// Basically, what we do here is start with an empty parent template and then
...
...
@@ -105,10 +127,13 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
// but will still emit <no value> for others. We mitigate that later.
t
.
Option
(
"missingkey=zero"
)
}
funcMap
:=
e
.
alterFuncMap
(
t
)
files
:=
[]
string
{}
for
fname
,
r
:=
range
tpls
{
log
.
Printf
(
"Preparing template %s"
,
fname
)
t
=
t
.
New
(
fname
)
.
Funcs
(
e
.
F
uncMap
)
t
=
t
.
New
(
fname
)
.
Funcs
(
f
uncMap
)
if
_
,
err
:=
t
.
Parse
(
r
.
tpl
);
err
!=
nil
{
return
map
[
string
]
string
{},
fmt
.
Errorf
(
"parse error in %q: %s"
,
fname
,
err
)
}
...
...
pkg/engine/engine_test.go
View file @
ae2d6c50
...
...
@@ -312,7 +312,7 @@ func TestRenderBuiltinValues(t *testing.T) {
Metadata
:
&
chart
.
Metadata
{
Name
:
"Latium"
},
Templates
:
[]
*
chart
.
Template
{
{
Name
:
"Lavinia"
,
Data
:
[]
byte
(
`{{.Template.Name}}{{.Chart.Name}}{{.Release.Name}}`
)},
{
Name
:
"From"
,
Data
:
[]
byte
(
`{{.Files.author | printf "%s"}} {{.Files.Get
String
"book/title.txt"}}`
)},
{
Name
:
"From"
,
Data
:
[]
byte
(
`{{.Files.author | printf "%s"}} {{.Files.Get "book/title.txt"}}`
)},
},
Values
:
&
chart
.
Config
{
Raw
:
``
},
Dependencies
:
[]
*
chart
.
Chart
{},
...
...
@@ -358,3 +358,33 @@ func TestRenderBuiltinValues(t *testing.T) {
}
}
func
TestAlterFuncMap
(
t
*
testing
.
T
)
{
c
:=
&
chart
.
Chart
{
Metadata
:
&
chart
.
Metadata
{
Name
:
"conrad"
},
Templates
:
[]
*
chart
.
Template
{
{
Name
:
"quote"
,
Data
:
[]
byte
(
`{{include "conrad/_partial" . | indent 2}} dead.`
)},
{
Name
:
"_partial"
,
Data
:
[]
byte
(
`{{.Release.Name}} - he`
)},
},
Values
:
&
chart
.
Config
{
Raw
:
``
},
Dependencies
:
[]
*
chart
.
Chart
{},
}
v
:=
chartutil
.
Values
{
"Values"
:
&
chart
.
Config
{
Raw
:
""
},
"Chart"
:
c
.
Metadata
,
"Release"
:
chartutil
.
Values
{
"Name"
:
"Mistah Kurtz"
,
},
}
out
,
err
:=
New
()
.
Render
(
c
,
v
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
expect
:=
" Mistah Kurtz - he dead."
if
got
:=
out
[
"conrad/quote"
];
got
!=
expect
{
t
.
Errorf
(
"Expected %q, got %q (%v)"
,
expect
,
got
,
out
)
}
}
pkg/helm/option.go
View file @
ae2d6c50
...
...
@@ -143,6 +143,13 @@ func DeleteDryRun(dry bool) DeleteOption {
}
}
// UpgradeDisableHooks will disable hooks for an upgrade operation.
func
UpgradeDisableHooks
(
disable
bool
)
UpdateOption
{
return
func
(
opts
*
options
)
{
opts
.
disableHooks
=
disable
}
}
// UpgradeDryRun will (if true) execute an upgrade as a dry run.
func
UpgradeDryRun
(
dry
bool
)
UpdateOption
{
return
func
(
opts
*
options
)
{
...
...
@@ -237,9 +244,15 @@ func (o *options) rpcDeleteRelease(rlsName string, rlc rls.ReleaseServiceClient,
// Executes tiller.UpdateRelease RPC.
func
(
o
*
options
)
rpcUpdateRelease
(
rlsName
string
,
chr
*
cpb
.
Chart
,
rlc
rls
.
ReleaseServiceClient
,
opts
...
UpdateOption
)
(
*
rls
.
UpdateReleaseResponse
,
error
)
{
//TODO: handle dryRun
for
_
,
opt
:=
range
opts
{
opt
(
o
)
}
o
.
updateReq
.
Chart
=
chr
o
.
updateReq
.
DryRun
=
o
.
dryRun
o
.
updateReq
.
Name
=
rlsName
return
rlc
.
UpdateRelease
(
context
.
TODO
(),
&
rls
.
UpdateReleaseRequest
{
Name
:
rlsName
,
Chart
:
chr
}
)
return
rlc
.
UpdateRelease
(
context
.
TODO
(),
&
o
.
updateReq
)
}
// Executes tiller.GetReleaseStatus RPC.
...
...
pkg/ignore/rules.go
View file @
ae2d6c50
...
...
@@ -65,7 +65,6 @@ func Parse(file io.Reader) (*Rules, error) {
if
err
:=
s
.
Err
();
err
!=
nil
{
return
r
,
err
}
return
r
,
nil
}
...
...
@@ -97,8 +96,10 @@ func (r *Rules) Ignore(path string, fi os.FileInfo) bool {
continue
}
// If the rule is looking for directories, and this is not a directory,
// skip it.
if
p
.
mustDir
&&
!
fi
.
IsDir
()
{
return
fals
e
continu
e
}
if
p
.
match
(
path
,
fi
)
{
return
true
...
...
pkg/kube/client.go
View file @
ae2d6c50
...
...
@@ -20,15 +20,21 @@ import (
"fmt"
"io"
"log"
"reflect"
"time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
"k8s.io/kubernetes/pkg/kubectl"
cmdutil
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/strategicpatch"
"k8s.io/kubernetes/pkg/util/yaml"
"k8s.io/kubernetes/pkg/watch"
)
...
...
@@ -57,6 +63,77 @@ func (c *Client) Create(namespace string, reader io.Reader) error {
return
perform
(
c
,
namespace
,
reader
,
createResource
)
}
// Update reads in the current configuration and a modified configuration from io.reader
// and creates resources that don't already exists, updates resources that have been modified
// and deletes resources from the current configuration that are not present in the
// modified configuration
//
// Namespace will set the namespaces
func
(
c
*
Client
)
Update
(
namespace
string
,
currentReader
,
modifiedReader
io
.
Reader
)
error
{
current
:=
c
.
NewBuilder
(
includeThirdPartyAPIs
)
.
ContinueOnError
()
.
NamespaceParam
(
namespace
)
.
DefaultNamespace
()
.
Stream
(
currentReader
,
""
)
.
Flatten
()
.
Do
()
modified
:=
c
.
NewBuilder
(
includeThirdPartyAPIs
)
.
ContinueOnError
()
.
NamespaceParam
(
namespace
)
.
DefaultNamespace
()
.
Stream
(
modifiedReader
,
""
)
.
Flatten
()
.
Do
()
currentInfos
,
err
:=
current
.
Infos
()
if
err
!=
nil
{
return
err
}
modifiedInfos
:=
[]
*
resource
.
Info
{}
modified
.
Visit
(
func
(
info
*
resource
.
Info
,
err
error
)
error
{
modifiedInfos
=
append
(
modifiedInfos
,
info
)
if
err
!=
nil
{
return
err
}
resourceName
:=
info
.
Name
helper
:=
resource
.
NewHelper
(
info
.
Client
,
info
.
Mapping
)
if
_
,
err
:=
helper
.
Get
(
info
.
Namespace
,
resourceName
,
info
.
Export
);
err
!=
nil
{
if
!
errors
.
IsNotFound
(
err
)
{
return
fmt
.
Errorf
(
"Could not get information about the resource: err: %s"
,
err
)
}
// Since the resource does not exist, create it.
if
err
:=
createResource
(
info
);
err
!=
nil
{
return
err
}
kind
:=
info
.
Mapping
.
GroupVersionKind
.
Kind
log
.
Printf
(
"Created a new %s called %s
\n
"
,
kind
,
resourceName
)
return
nil
}
currentObj
,
err
:=
getCurrentObject
(
resourceName
,
currentInfos
)
if
err
!=
nil
{
return
err
}
if
err
:=
updateResource
(
info
,
currentObj
);
err
!=
nil
{
log
.
Printf
(
"error updating the resource %s:
\n\t
%v"
,
resourceName
,
err
)
return
err
}
return
err
})
deleteUnwantedResources
(
currentInfos
,
modifiedInfos
)
return
nil
}
// Delete deletes kubernetes resources from an io.reader
//
// Namespace will set the namespace
...
...
@@ -136,6 +213,51 @@ func createResource(info *resource.Info) error {
return
err
}
func
deleteResource
(
info
*
resource
.
Info
)
error
{
return
resource
.
NewHelper
(
info
.
Client
,
info
.
Mapping
)
.
Delete
(
info
.
Namespace
,
info
.
Name
)
}
func
updateResource
(
modified
*
resource
.
Info
,
currentObj
runtime
.
Object
)
error
{
encoder
:=
api
.
Codecs
.
LegacyCodec
(
registered
.
EnabledVersions
()
...
)
originalSerialization
,
err
:=
runtime
.
Encode
(
encoder
,
currentObj
)
if
err
!=
nil
{
return
err
}
editedSerialization
,
err
:=
runtime
.
Encode
(
encoder
,
modified
.
Object
)
if
err
!=
nil
{
return
err
}
originalJS
,
err
:=
yaml
.
ToJSON
(
originalSerialization
)
if
err
!=
nil
{
return
err
}
editedJS
,
err
:=
yaml
.
ToJSON
(
editedSerialization
)
if
err
!=
nil
{
return
err
}
if
reflect
.
DeepEqual
(
originalJS
,
editedJS
)
{
return
fmt
.
Errorf
(
"Looks like there are no changes for %s"
,
modified
.
Name
)
}
patch
,
err
:=
strategicpatch
.
CreateStrategicMergePatch
(
originalJS
,
editedJS
,
currentObj
)
if
err
!=
nil
{
return
err
}
// send patch to server
helper
:=
resource
.
NewHelper
(
modified
.
Client
,
modified
.
Mapping
)
if
_
,
err
=
helper
.
Patch
(
modified
.
Namespace
,
modified
.
Name
,
api
.
StrategicMergePatchType
,
patch
);
err
!=
nil
{
return
err
}
return
nil
}
func
watchUntilReady
(
info
*
resource
.
Info
)
error
{
w
,
err
:=
resource
.
NewHelper
(
info
.
Client
,
info
.
Mapping
)
.
WatchSingle
(
info
.
Namespace
,
info
.
Name
,
info
.
ResourceVersion
)
if
err
!=
nil
{
...
...
@@ -213,3 +335,37 @@ func (c *Client) ensureNamespace(namespace string) error {
}
return
nil
}
func
deleteUnwantedResources
(
currentInfos
,
modifiedInfos
[]
*
resource
.
Info
)
{
for
_
,
cInfo
:=
range
currentInfos
{
found
:=
false
for
_
,
m
:=
range
modifiedInfos
{
if
m
.
Name
==
cInfo
.
Name
{
found
=
true
}
}
if
!
found
{
log
.
Printf
(
"Deleting %s..."
,
cInfo
.
Name
)
if
err
:=
deleteResource
(
cInfo
);
err
!=
nil
{
log
.
Printf
(
"Failed to delete %s, err: %s"
,
cInfo
.
Name
,
err
)
}
}
}
}
func
getCurrentObject
(
targetName
string
,
infos
[]
*
resource
.
Info
)
(
runtime
.
Object
,
error
)
{
var
curr
*
resource
.
Info
for
_
,
currInfo
:=
range
infos
{
if
currInfo
.
Name
==
targetName
{
curr
=
currInfo
}
}
if
curr
==
nil
{
return
nil
,
fmt
.
Errorf
(
"No resource with the name %s found."
,
targetName
)
}
encoder
:=
api
.
Codecs
.
LegacyCodec
(
registered
.
EnabledVersions
()
...
)
defaultVersion
:=
unversioned
.
GroupVersion
{}
return
resource
.
AsVersionedObject
([]
*
resource
.
Info
{
curr
},
false
,
defaultVersion
,
encoder
)
}
pkg/kube/client_test.go
View file @
ae2d6c50
...
...
@@ -17,15 +17,55 @@ limitations under the License.
package
kube
import
(
"bytes"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
api
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/unversioned/fake"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
)
func
TestUpdateResource
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
namespace
string
modified
*
resource
.
Info
currentObj
runtime
.
Object
err
bool
errMessage
string
}{
{
name
:
"no changes when updating resources"
,
modified
:
createFakeInfo
(
"nginx"
,
nil
),
currentObj
:
createFakePod
(
"nginx"
,
nil
),
err
:
true
,
errMessage
:
"Looks like there are no changes for nginx"
,
},
//{
//name: "valid update input",
//modified: createFakeInfo("nginx", map[string]string{"app": "nginx"}),
//currentObj: createFakePod("nginx", nil),
//},
}
for
_
,
tt
:=
range
tests
{
err
:=
updateResource
(
tt
.
modified
,
tt
.
currentObj
)
if
err
!=
nil
&&
err
.
Error
()
!=
tt
.
errMessage
{
t
.
Errorf
(
"%q. expected error message: %v, got %v"
,
tt
.
name
,
tt
.
errMessage
,
err
)
}
}
}
func
TestPerform
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
...
...
@@ -214,3 +254,53 @@ spec:
ports:
- containerPort: 80
`
func
createFakePod
(
name
string
,
labels
map
[
string
]
string
)
runtime
.
Object
{
objectMeta
:=
createObjectMeta
(
name
,
labels
)
object
:=
&
api
.
Pod
{
ObjectMeta
:
objectMeta
,
}
return
object
}
func
createFakeInfo
(
name
string
,
labels
map
[
string
]
string
)
*
resource
.
Info
{
pod
:=
createFakePod
(
name
,
labels
)
marshaledObj
,
_
:=
json
.
Marshal
(
pod
)
mapping
:=
&
meta
.
RESTMapping
{
Resource
:
name
,
Scope
:
meta
.
RESTScopeNamespace
,
GroupVersionKind
:
unversioned
.
GroupVersionKind
{
Kind
:
"Pod"
,
Version
:
"v1"
,
}}
client
:=
&
fake
.
RESTClient
{
Codec
:
testapi
.
Default
.
Codec
(),
Client
:
fake
.
CreateHTTPClient
(
func
(
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
header
:=
http
.
Header
{}
header
.
Set
(
"Content-Type"
,
runtime
.
ContentTypeJSON
)
return
&
http
.
Response
{
StatusCode
:
200
,
Header
:
header
,
Body
:
ioutil
.
NopCloser
(
bytes
.
NewReader
(
marshaledObj
)),
},
nil
})}
info
:=
resource
.
NewInfo
(
client
,
mapping
,
"default"
,
"nginx"
,
false
)
info
.
Object
=
pod
return
info
}
func
createObjectMeta
(
name
string
,
labels
map
[
string
]
string
)
api
.
ObjectMeta
{
objectMeta
:=
api
.
ObjectMeta
{
Name
:
name
,
Namespace
:
"default"
}
if
labels
!=
nil
{
objectMeta
.
Labels
=
labels
}
return
objectMeta
}
pkg/kube/tunnel.go
View file @
ae2d6c50
...
...
@@ -51,7 +51,7 @@ func (c *Client) ForwardPort(namespace, podName string, remote int) (*Tunnel, er
}
// Build a url to the portforward endpoing
// example: http://localhost:8080/api/v1/namespaces/helm/pods/tiller-
rc
-9itlq/portforward
// example: http://localhost:8080/api/v1/namespaces/helm/pods/tiller-
deploy
-9itlq/portforward
u
:=
client
.
RESTClient
.
Post
()
.
Resource
(
"pods"
)
.
Namespace
(
namespace
)
.
...
...
pkg/proto/hapi/services/tiller.pb.go
View file @
ae2d6c50
This diff is collapsed.
Click to expand it.
pkg/repo/repo.go
View file @
ae2d6c50
...
...
@@ -98,8 +98,7 @@ func LoadChartRepository(dir, url string) (*ChartRepository, error) {
return
nil
}
r
.
IndexFile
=
i
}
else
{
// TODO: check for tgz extension
}
else
if
strings
.
HasSuffix
(
f
.
Name
(),
".tgz"
)
{
r
.
ChartPaths
=
append
(
r
.
ChartPaths
,
path
)
}
}
...
...
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