Merge branch 'master' into readme-fix

pull/647/head
Ken Wronkiewicz 9 years ago
commit 3a7870b96f

1
.gitignore vendored

@ -1,6 +1,5 @@
.coverage/ .coverage/
bin/ bin/
rootfs/helm
rootfs/tiller rootfs/tiller
vendor/ vendor/
_proto/*.pb.go _proto/*.pb.go

@ -4,8 +4,6 @@ SHORT_NAME ?= tiller
# go option # go option
GO ?= go GO ?= go
GOARCH ?= $(shell go env GOARCH)
GOOS ?= $(shell go env GOOS)
PKG := $(shell glide novendor) PKG := $(shell glide novendor)
TAGS := TAGS :=
TESTS := . TESTS := .
@ -30,11 +28,10 @@ check-docker:
fi fi
.PHONY: docker-binary .PHONY: docker-binary
docker-binary: GOOS = linux docker-binary: BINDIR = ./rootfs
docker-binary: GOARCH = amd64
docker-binary: BINDIR = $(CURDIR)/rootfs
docker-binary: GOFLAGS += -a -installsuffix cgo docker-binary: GOFLAGS += -a -installsuffix cgo
docker-binary: build docker-binary:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 $(GO) build -o $(BINDIR)/tiller $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' github.com/kubernetes/helm/cmd/tiller
.PHONY: docker-build .PHONY: docker-build
docker-build: check-docker docker-binary docker-build: check-docker docker-binary
@ -58,13 +55,27 @@ test-style:
.PHONY: clean .PHONY: clean
clean: clean:
@rm -rf $(BINDIR) @rm -rf $(BINDIR)
@rm ./rootfs/tiller
.PHONY: coverage .PHONY: coverage
coverage: coverage:
@scripts/coverage.sh @scripts/coverage.sh
HAS_GLIDE := $(shell command -v glide;)
HAS_HG := $(shell command -v hg;)
HAS_GIT := $(shell command -v git;)
.PHONY: bootstrap .PHONY: bootstrap
bootstrap: bootstrap:
ifndef HAS_GLIDE
go get -u github.com/Masterminds/glide
endif
ifndef HAS_HG
$(error You must install Mercurial (hg))
endif
ifndef HAS_GIT
$(error You must install Git)
endif
glide install glide install
include versioning.mk include versioning.mk

@ -13,8 +13,13 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var untarFile bool
var untarDir string
func init() { func init() {
RootCommand.AddCommand(fetchCmd) RootCommand.AddCommand(fetchCmd)
fetchCmd.Flags().BoolVar(&untarFile, "untar", false, "If set to true, will untar the chart after downloading it.")
fetchCmd.Flags().StringVar(&untarDir, "untardir", ".", "If untar is specified, this flag specifies where to untar the chart.")
} }
var fetchCmd = &cobra.Command{ var fetchCmd = &cobra.Command{
@ -49,10 +54,8 @@ func fetch(cmd *cobra.Command, args []string) error {
} }
defer resp.Body.Close() defer resp.Body.Close()
// TODO(vaikas): Implement untar / flag if untarFile {
untar := false return chart.Expand(untarDir, resp.Body)
if untar {
return untarChart(resp.Body)
} }
p := strings.Split(u.String(), "/") p := strings.Split(u.String(), "/")
return saveChartFile(p[len(p)-1], resp.Body) return saveChartFile(p[len(p)-1], resp.Body)
@ -84,18 +87,6 @@ func mapRepoArg(arg string, r map[string]string) (*url.URL, error) {
return nil, fmt.Errorf("Invalid chart url format: %s", arg) return nil, fmt.Errorf("Invalid chart url format: %s", arg)
} }
func untarChart(r io.Reader) error {
c, err := chart.LoadDataFromReader(r)
if err != nil {
return err
}
if c == nil {
return fmt.Errorf("Failed to untar the chart")
}
return fmt.Errorf("Not implemented yee")
}
func saveChartFile(c string, r io.Reader) error { func saveChartFile(c string, r io.Reader) error {
// Grab the chart name that we'll use for the name of the file to download to. // Grab the chart name that we'll use for the name of the file to download to.
out, err := os.Create(c) out, err := os.Create(c)

@ -39,7 +39,7 @@ func rmRelease(cmd *cobra.Command, args []string) error {
// TODO: Handle dry run use case. // TODO: Handle dry run use case.
if removeDryRun { if removeDryRun {
fmt.Printf("Deleting %s\n", args[0]) fmt.Printf("DRY RUN: Deleting %s\n", args[0])
return nil return nil
} }

@ -128,11 +128,15 @@ type KubeClient interface {
// //
// reader must contain a YAML stream (one or more YAML documents separated // reader must contain a YAML stream (one or more YAML documents separated
// by "\n---\n"). // by "\n---\n").
//
// config is optional. If nil, the client will use its existing configuration.
// If set, the client will override its default configuration with the
// passed in one.
Create(namespace string, reader io.Reader) error Create(namespace string, reader io.Reader) error
// Delete destroys one or more resources.
//
// namespace must contain a valid existing namespace.
//
// reader must contain a YAML stream (one or more YAML documents separated
// by "\n---\n").
Delete(namespace string, reader io.Reader) error
} }
// PrintingKubeClient implements KubeClient, but simply prints the reader to // PrintingKubeClient implements KubeClient, but simply prints the reader to
@ -146,6 +150,10 @@ func (p *PrintingKubeClient) Create(ns string, r io.Reader) error {
_, err := io.Copy(p.Out, r) _, err := io.Copy(p.Out, r)
return err return err
} }
func (p *PrintingKubeClient) Delete(ns string, r io.Reader) error {
_, err := io.Copy(p.Out, r)
return err
}
// Environment provides the context for executing a client request. // Environment provides the context for executing a client request.
// //

@ -53,6 +53,9 @@ type mockKubeClient struct {
func (k *mockKubeClient) Create(ns string, r io.Reader) error { func (k *mockKubeClient) Create(ns string, r io.Reader) error {
return nil return nil
} }
func (k *mockKubeClient) Delete(ns string, r io.Reader) error {
return nil
}
var _ Engine = &mockEngine{} var _ Engine = &mockEngine{}
var _ ReleaseStorage = &mockReleaseStorage{} var _ ReleaseStorage = &mockReleaseStorage{}

@ -207,8 +207,12 @@ func (s *releaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
rel.Info.Status.Code = release.Status_DELETED rel.Info.Status.Code = release.Status_DELETED
rel.Info.Deleted = timeconv.Now() rel.Info.Deleted = timeconv.Now()
// TODO: Once KubeClient is ready, delete the resources. b := bytes.NewBuffer([]byte(rel.Manifest))
log.Println("WARNING: Currently not deleting resources from k8s")
if err := s.env.KubeClient.Delete(s.env.Namespace, b); err != nil {
log.Printf("uninstall: Failed deletion of %q: %s", req.Name, err)
return nil, err
}
if err := s.env.Releases.Update(rel); err != nil { if err := s.env.Releases.Update(rel); err != nil {
log.Printf("uninstall: Failed to store updated release: %s", err) log.Printf("uninstall: Failed to store updated release: %s", err)

@ -5,9 +5,9 @@ metadata:
labels: labels:
heritage: {{.Release.Service}} heritage: {{.Release.Service}}
chartName: {{.Chart.Name}} chartName: {{.Chart.Name}}
chartVersion: {{.Chart.Version}} chartVersion: {{.Chart.Version | quote}}
annotations: annotations:
"helm.sh/created": {{.Release.Time.Seconds}} "helm.sh/created": "{{.Release.Time.Seconds}}"
spec: spec:
restartPolicy: {{default "Never" .restart_policy}} restartPolicy: {{default "Never" .restart_policy}}
containers: containers:

@ -88,7 +88,7 @@ func (c *Chart) TemplatesDir() string {
return filepath.Join(c.loader.dir(), preTemplates) return filepath.Join(c.loader.dir(), preTemplates)
} }
// ChartsDir returns teh directory where dependency charts are stored. // ChartsDir returns the directory where dependency charts are stored.
func (c *Chart) ChartsDir() string { func (c *Chart) ChartsDir() string {
return filepath.Join(c.loader.dir(), preCharts) return filepath.Join(c.loader.dir(), preCharts)
} }
@ -214,6 +214,44 @@ func Create(chartfile *Chartfile, dir string) (*Chart, error) {
}, nil }, nil
} }
// Expand uncompresses and extracts a chart into the specified directory.
func Expand(dir string, r io.Reader) error {
gr, err := gzip.NewReader(r)
if err != nil {
return err
}
defer gr.Close()
tr := tar.NewReader(gr)
for {
header, err := tr.Next()
if err == io.EOF {
break
} else if err != nil {
return err
}
path := filepath.Clean(filepath.Join(dir, header.Name))
info := header.FileInfo()
if info.IsDir() {
if err = os.MkdirAll(path, info.Mode()); err != nil {
return err
}
continue
}
file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, tr)
if err != nil {
return err
}
}
return nil
}
// fname prepares names for the filesystem // fname prepares names for the filesystem
func fname(name string) string { func fname(name string) string {
// Right now, we don't do anything. Do we need to encode any particular // Right now, we don't do anything. Do we need to encode any particular

@ -30,6 +30,7 @@ const (
testdir = "testdata/frobnitz/" testdir = "testdata/frobnitz/"
testarchive = "testdata/frobnitz-0.0.1.tgz" testarchive = "testdata/frobnitz-0.0.1.tgz"
testmember = "templates/template.tpl" testmember = "templates/template.tpl"
expectedTemplate = "Hello {{.Name | default \"world\"}}\n"
) )
// Type canaries. If these fail, they will fail at compile time. // Type canaries. If these fail, they will fail at compile time.
@ -270,3 +271,42 @@ func compareContent(filename string, content []byte) error {
return nil return nil
} }
func TestExpand(t *testing.T) {
r, err := os.Open(testarchive)
if err != nil {
t.Errorf("Failed to read testarchive file: %s", err)
return
}
td, err := ioutil.TempDir("", "helm-unittest-chart-")
if err != nil {
t.Errorf("Failed to create tempdir: %s", err)
return
}
err = Expand(td, r)
if err != nil {
t.Errorf("Failed to expand testarchive file: %s", err)
}
fi, err := os.Lstat(td + "/frobnitz/Chart.yaml")
if err != nil {
t.Errorf("Failed to stat Chart.yaml from expanded archive: %s", err)
}
if fi.Name() != "Chart.yaml" {
t.Errorf("Didn't get the right file name from stat, expected Chart.yaml, got: %s", fi.Name())
}
tr, err := os.Open(td + "/frobnitz/templates/template.tpl")
if err != nil {
t.Errorf("Failed to open template.tpl from expanded archive: %s", err)
}
c, err := ioutil.ReadAll(tr)
if err != nil {
t.Errorf("Failed to read contents of template.tpl from expanded archive: %s", err)
}
if string(c) != expectedTemplate {
t.Errorf("Contents of the expanded template differ, wanted '%s' got '%s'", expectedTemplate, c)
}
}

@ -32,6 +32,14 @@ func (c *Client) Create(namespace string, reader io.Reader) error {
return perform(f, namespace, reader, createResource) return perform(f, namespace, reader, createResource)
} }
// Delete deletes kubernetes resources from an io.reader
//
// Namespace will set the namespace
func (c *Client) Delete(namespace string, reader io.Reader) error {
f := cmdutil.NewFactory(c.config)
return perform(f, namespace, reader, deleteResource)
}
const includeThirdPartyAPIs = false const includeThirdPartyAPIs = false
func perform(f *cmdutil.Factory, namespace string, reader io.Reader, fn ResourceActorFunc) error { func perform(f *cmdutil.Factory, namespace string, reader io.Reader, fn ResourceActorFunc) error {
@ -73,3 +81,7 @@ func createResource(info *resource.Info) error {
_, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object) _, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
return err return err
} }
func deleteResource(info *resource.Info) error {
return resource.NewHelper(info.Client, info.Mapping).Delete(info.Namespace, info.Name)
}

@ -65,6 +65,17 @@ func TestPerform(t *testing.T) {
} }
} }
func TestReal(t *testing.T) {
t.Skip("This is a live test, comment this line to run")
if err := New(nil).Create("test", strings.NewReader(guestbookManifest)); err != nil {
t.Fatal(err)
}
if err := New(nil).Delete("test", strings.NewReader(guestbookManifest)); err != nil {
t.Fatal(err)
}
}
const guestbookManifest = ` const guestbookManifest = `
apiVersion: v1 apiVersion: v1
kind: Service kind: Service

@ -30,6 +30,18 @@ command_exists() {
hash "${1}" 2>/dev/null hash "${1}" 2>/dev/null
} }
# fetch url using wget or curl and print to stdout
fetch_url() {
local url="$1"
if command_exists wget; then
curl -sSL "$url"
elif command_exists curl; then
wget -qO- "$url"
else
error_exit "Couldn't find curl or wget. Bailing out."
fi
}
# Program Functions ------------------------------------------------------------ # Program Functions ------------------------------------------------------------
# Check host platform and docker host # Check host platform and docker host
@ -82,24 +94,26 @@ verify_prereqs() {
error_exit "Can't connect to 'docker' daemon." error_exit "Can't connect to 'docker' daemon."
fi fi
if docker inspect kubelet >/dev/null 2>&1 ; then
error_exit "Kubernetes is already running"
fi
$KUBECTL version --client >/dev/null || download_kubectl $KUBECTL version --client >/dev/null || download_kubectl
} }
# Get the latest stable release tag # Get the latest stable release tag
get_latest_version_number() { get_latest_version_number() {
local -r latest_url="https://storage.googleapis.com/kubernetes-release/release/stable.txt" local channel="stable"
if command_exists wget ; then if [[ -n "${ALPHA:-}" ]]; then
wget -qO- ${latest_url} channel="latest"
elif command_exists curl ; then
curl -Ss ${latest_url}
else
error_exit "Couldn't find curl or wget. Bailing out."
fi fi
local latest_url="https://storage.googleapis.com/kubernetes-release/release/${channel}.txt"
fetch_url "$latest_url"
} }
# Detect ip address od docker host # Detect ip address od docker host
detect_docker_host_ip() { detect_docker_host_ip() {
if [ -n "${DOCKER_HOST:-}" ]; then if [[ -n "${DOCKER_HOST:-}" ]]; then
awk -F'[/:]' '{print $4}' <<< "$DOCKER_HOST" awk -F'[/:]' '{print $4}' <<< "$DOCKER_HOST"
else else
ifconfig docker0 \ ifconfig docker0 \
@ -151,27 +165,33 @@ start_kubernetes() {
/hyperkube kubelet \ /hyperkube kubelet \
--containerized \ --containerized \
--hostname-override="127.0.0.1" \ --hostname-override="127.0.0.1" \
--api-servers=http://localhost:8080 \ --api-servers=http://localhost:${KUBE_PORT} \
--config=/etc/kubernetes/manifests \ --config=/etc/kubernetes/manifests \
--allow-privileged=true \ --allow-privileged=true \
${dns_args} \ ${dns_args} \
--v=${LOG_LEVEL} >/dev/null --v=${LOG_LEVEL} >/dev/null
until $KUBECTL cluster-info &> /dev/null; do
sleep 1
done
# Create kube-system namespace in kubernetes
$KUBECTL create namespace kube-system >/dev/null
# We expect to have at least 3 running pods - etcd, master and kube-proxy. # We expect to have at least 3 running pods - etcd, master and kube-proxy.
local attempt=1 local attempt=1
while (($($KUBECTL get pods --no-headers 2>/dev/null | grep -c "Running") < 3)); do while (($(KUBECTL get pods --all-namespaces --no-headers 2>/dev/null | grep -c "Running") < 3)); do
echo -n "." echo -n "."
sleep $(( attempt++ )) sleep $(( attempt++ ))
done done
echo echo
local end_time=$(date +%s) echo "Started master components in $(($(date +%s) - start_time)) seconds."
echo "Started master components in $((end_time - start_time)) seconds."
} }
# Open kubernetes master api port. # Open kubernetes master api port.
setup_firewall() { setup_firewall() {
[[ -n "${DOCKER_MACHINE_NAME}" ]] || return [[ -n "${DOCKER_MACHINE_NAME:-}" ]] || return
echo "Adding iptables hackery for docker-machine..." echo "Adding iptables hackery for docker-machine..."
@ -184,13 +204,6 @@ setup_firewall() {
fi fi
} }
# Create kube-system namespace in kubernetes
create_kube_system_namespace() {
echo "Creating kube-system namespace..."
$KUBECTL create -f ./scripts/cluster/kube-system.yaml >/dev/null
}
# Activate skydns in kubernetes and wait for pods to be ready. # Activate skydns in kubernetes and wait for pods to be ready.
create_kube_dns() { create_kube_dns() {
[[ "${ENABLE_CLUSTER_DNS}" = true ]] || return [[ "${ENABLE_CLUSTER_DNS}" = true ]] || return
@ -209,8 +222,7 @@ create_kube_dns() {
sleep $(( attempt++ )) sleep $(( attempt++ ))
done done
echo echo
local end_time=$(date +%s) echo "Started DNS in $(($(date +%s) - start_time)) seconds."
echo "Started DNS in $((end_time - start_time)) seconds."
} }
# Generate kubeconfig data for the created cluster. # Generate kubeconfig data for the created cluster.
@ -231,17 +243,13 @@ generate_kubeconfig() {
download_kubectl() { download_kubectl() {
echo "Downloading kubectl binary..." echo "Downloading kubectl binary..."
local output="/usr/local/bin/kubectl"
kubectl_url="https://storage.googleapis.com/kubernetes-release/release/${KUBE_VERSION}/bin/${host_os}/${host_arch}/kubectl" kubectl_url="https://storage.googleapis.com/kubernetes-release/release/${KUBE_VERSION}/bin/${host_os}/${host_arch}/kubectl"
if command_exists wget; then fetch_url "${kubectl_url}" > "${output}"
wget -O ./bin/kubectl "${kubectl_url}" chmod a+x "${output}"
elif command_exists curl; then
curl -sSOL ./bin/kubectl "${kubectl_url}"
else
error_exit "Couldn't find curl or wget. Bailing out."
fi
chmod a+x ./bin/kubectl
KUBECTL=./bin/kubectl KUBECTL="${output}"
} }
# Clean volumes that are left by kubelet # Clean volumes that are left by kubelet
@ -297,9 +305,8 @@ kube_up() {
clean_volumes clean_volumes
setup_firewall setup_firewall
start_kubernetes
generate_kubeconfig generate_kubeconfig
create_kube_system_namespace start_kubernetes
create_kube_dns create_kube_dns
$KUBECTL cluster-info $KUBECTL cluster-info

Loading…
Cancel
Save