<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package chartutil

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"k8s.io/helm/pkg/proto/hapi/chart"
)

const (
	// ChartfileName is the default Chart file name.
	ChartfileName = "Chart.yaml"
	// ValuesfileName is the default values file name.
	ValuesfileName = "values.yaml"
	// TemplatesDir is the relative directory name for templates.
	TemplatesDir = "templates"
	// ChartsDir is the relative directory name for charts dependencies.
	ChartsDir = "charts"
	// IgnorefileName is the name of the Helm ignore file.
	IgnorefileName = ".helmignore"
	// IngressFileName is the name of the example ingress file.
	IngressFileName = "ingress.yaml"
	// DeploymentName is the name of the example deployment file.
	DeploymentName = "deployment.yaml"
	// ServiceName is the name of the example service file.
	ServiceName = "service.yaml"
	// NotesName is the name of the example NOTES.txt file.
	NotesName = "NOTES.txt"
	// HelpersName is the name of the example NOTES.txt file.
	HelpersName = "_helpers.tpl"
)

const defaultValues = `# Default values for %s.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  path: /
  hosts:
    - chart-example.local
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #  cpu: 100m
  #  memory: 128Mi
  # requests:
  #  cpu: 100m
  #  memory: 128Mi

nodeSelector: {}

tolerations: []

affinity: {}
`

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
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
`

const defaultIngress = `{{- if .Values.ingress.enabled -}}
{{- $fullName := include "<CHARTNAME>.fullname" . -}}
{{- $servicePort := .Values.service.port -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
    app: {{ template "<CHARTNAME>.name" . }}
    chart: {{ template "<CHARTNAME>.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
  annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
  tls:
  {{- range .Values.ingress.tls }}
    - hosts:
      {{- range .hosts }}
        - {{ . }}
      {{- end }}
      secretName: {{ .secretName }}
  {{- end }}
{{- end }}
  rules:
  {{- range .Values.ingress.hosts }}
    - host: {{ . }}
      http:
        paths:
          - path: {{ $ingressPath }}
            backend:
              serviceName: {{ $fullName }}
              servicePort: http
  {{- end }}
{{- end }}
`

const defaultDeployment = `apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: {{ template "<CHARTNAME>.fullname" . }}
  labels:
    app: {{ template "<CHARTNAME>.name" . }}
    chart: {{ template "<CHARTNAME>.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ template "<CHARTNAME>.name" . }}
      release: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ template "<CHARTNAME>.name" . }}
        release: {{ .Release.Name }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
{{ toYaml .Values.resources | indent 12 }}
    {{- with .Values.nodeSelector }}
      nodeSelector:
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.affinity }}
      affinity:
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.tolerations }}
      tolerations:
{{ toYaml . | indent 8 }}
    {{- end }}
`

const defaultService = `apiVersion: v1
kind: Service
metadata:
  name: {{ template "<CHARTNAME>.fullname" . }}
  labels:
    app: {{ template "<CHARTNAME>.name" . }}
    chart: {{ template "<CHARTNAME>.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: {{ template "<CHARTNAME>.name" . }}
    release: {{ .Release.Name }}
`

const defaultNotes = `1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "<CHARTNAME>.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch the status of by running 'kubectl get svc -w {{ template "<CHARTNAME>.fullname" . }}'
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "<CHARTNAME>.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "<CHARTNAME>.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl port-forward $POD_NAME 8080:80
{{- end }}
`

const defaultHelpers = `{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "<CHARTNAME>.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "<CHARTNAME>.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "<CHARTNAME>.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
`

// CreateFrom creates a new chart, but scaffolds it from the src chart.
func CreateFrom(chartfile *chart.Metadata, dest string, src string) error {
	schart, err := Load(src)
	if err != nil {
		return fmt.Errorf("could not load %s: %s", src, err)
	}

	schart.Metadata = chartfile

	var updatedTemplates []*chart.Template

	for _, template := range schart.Templates {
		newData := Transform(string(template.Data), "<CHARTNAME>", schart.Metadata.Name)
		updatedTemplates = append(updatedTemplates, &chart.Template{Name: template.Name, Data: newData})
	}

	schart.Templates = updatedTemplates
	schart.Values = &chart.Config{Raw: string(Transform(schart.Values.Raw, "<CHARTNAME>", schart.Metadata.Name))}

	return SaveDir(schart, dest)
}

// Create creates a new chart in a directory.
//
// Inside of dir, this will create a directory based on the name of
// chartfile.Name. It will then write the Chart.yaml into this directory and
// create the (empty) appropriate directories.
//
// The returned string will point to the newly created directory. It will be
// an absolute path, even if the provided base directory was relative.
//
// If dir does not exist, this will return an error.
// If Chart.yaml or any directories cannot be created, this will return an
// error. In such a case, this will attempt to clean up by removing the
// new chart directory.
func Create(chartfile *chart.Metadata, dir string) (string, error) {
	path, err := filepath.Abs(dir)
	if err != nil {
		return path, err
	}

	if fi, err := os.Stat(path); err != nil {
		return path, err
	} else if !fi.IsDir() {
		return path, fmt.Errorf("no such directory %s", path)
	}

	n := chartfile.Name
	cdir := filepath.Join(path, n)
	if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
		return cdir, fmt.Errorf("file %s already exists and is not a directory", cdir)
	}
	if err := os.MkdirAll(cdir, 0755); err != nil {
		return cdir, err
	}

	cf := filepath.Join(cdir, ChartfileName)
	if _, err := os.Stat(cf); err != nil {
		if err := SaveChartfile(cf, chartfile); err != nil {
			return cdir, err
		}
	}

	for _, d := range []string{TemplatesDir, ChartsDir} {
		if err := os.MkdirAll(filepath.Join(cdir, d), 0755); err != nil {
			return cdir, err
		}
	}

	files := []struct {
		path    string
		content []byte
	}{
		{
			// values.yaml
			path:    filepath.Join(cdir, ValuesfileName),
			content: []byte(fmt.Sprintf(defaultValues, chartfile.Name)),
		},
		{
			// .helmignore
			path:    filepath.Join(cdir, IgnorefileName),
			content: []byte(defaultIgnore),
		},
		{
			// ingress.yaml
			path:    filepath.Join(cdir, TemplatesDir, IngressFileName),
			content: Transform(defaultIngress, "<CHARTNAME>", chartfile.Name),
		},
		{
			// deployment.yaml
			path:    filepath.Join(cdir, TemplatesDir, DeploymentName),
			content: Transform(defaultDeployment, "<CHARTNAME>", chartfile.Name),
		},
		{
			// service.yaml
			path:    filepath.Join(cdir, TemplatesDir, ServiceName),
			content: Transform(defaultService, "<CHARTNAME>", chartfile.Name),
		},
		{
			// NOTES.txt
			path:    filepath.Join(cdir, TemplatesDir, NotesName),
			content: Transform(defaultNotes, "<CHARTNAME>", chartfile.Name),
		},
		{
			// _helpers.tpl
			path:    filepath.Join(cdir, TemplatesDir, HelpersName),
			content: Transform(defaultHelpers, "<CHARTNAME>", chartfile.Name),
		},
	}

	for _, file := range files {
		if _, err := os.Stat(file.path); err == nil {
			// File exists and is okay. Skip it.
			continue
		}
		if err := ioutil.WriteFile(file.path, file.content, 0644); err != nil {
			return cdir, err
		}
	}
	return cdir, nil
}
<commit_msg>Fixed SIGSEGV when running helm create with -p and no values.yaml file<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package chartutil

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"k8s.io/helm/pkg/proto/hapi/chart"
)

const (
	// ChartfileName is the default Chart file name.
	ChartfileName = "Chart.yaml"
	// ValuesfileName is the default values file name.
	ValuesfileName = "values.yaml"
	// TemplatesDir is the relative directory name for templates.
	TemplatesDir = "templates"
	// ChartsDir is the relative directory name for charts dependencies.
	ChartsDir = "charts"
	// IgnorefileName is the name of the Helm ignore file.
	IgnorefileName = ".helmignore"
	// IngressFileName is the name of the example ingress file.
	IngressFileName = "ingress.yaml"
	// DeploymentName is the name of the example deployment file.
	DeploymentName = "deployment.yaml"
	// ServiceName is the name of the example service file.
	ServiceName = "service.yaml"
	// NotesName is the name of the example NOTES.txt file.
	NotesName = "NOTES.txt"
	// HelpersName is the name of the example NOTES.txt file.
	HelpersName = "_helpers.tpl"
)

const defaultValues = `# Default values for %s.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  path: /
  hosts:
    - chart-example.local
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #  cpu: 100m
  #  memory: 128Mi
  # requests:
  #  cpu: 100m
  #  memory: 128Mi

nodeSelector: {}

tolerations: []

affinity: {}
`

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
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
`

const defaultIngress = `{{- if .Values.ingress.enabled -}}
{{- $fullName := include "<CHARTNAME>.fullname" . -}}
{{- $servicePort := .Values.service.port -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
    app: {{ template "<CHARTNAME>.name" . }}
    chart: {{ template "<CHARTNAME>.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
  annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
  tls:
  {{- range .Values.ingress.tls }}
    - hosts:
      {{- range .hosts }}
        - {{ . }}
      {{- end }}
      secretName: {{ .secretName }}
  {{- end }}
{{- end }}
  rules:
  {{- range .Values.ingress.hosts }}
    - host: {{ . }}
      http:
        paths:
          - path: {{ $ingressPath }}
            backend:
              serviceName: {{ $fullName }}
              servicePort: http
  {{- end }}
{{- end }}
`

const defaultDeployment = `apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: {{ template "<CHARTNAME>.fullname" . }}
  labels:
    app: {{ template "<CHARTNAME>.name" . }}
    chart: {{ template "<CHARTNAME>.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ template "<CHARTNAME>.name" . }}
      release: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ template "<CHARTNAME>.name" . }}
        release: {{ .Release.Name }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
{{ toYaml .Values.resources | indent 12 }}
    {{- with .Values.nodeSelector }}
      nodeSelector:
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.affinity }}
      affinity:
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.tolerations }}
      tolerations:
{{ toYaml . | indent 8 }}
    {{- end }}
`

const defaultService = `apiVersion: v1
kind: Service
metadata:
  name: {{ template "<CHARTNAME>.fullname" . }}
  labels:
    app: {{ template "<CHARTNAME>.name" . }}
    chart: {{ template "<CHARTNAME>.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: {{ template "<CHARTNAME>.name" . }}
    release: {{ .Release.Name }}
`

const defaultNotes = `1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "<CHARTNAME>.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch the status of by running 'kubectl get svc -w {{ template "<CHARTNAME>.fullname" . }}'
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "<CHARTNAME>.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "<CHARTNAME>.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl port-forward $POD_NAME 8080:80
{{- end }}
`

const defaultHelpers = `{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "<CHARTNAME>.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "<CHARTNAME>.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "<CHARTNAME>.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
`

// CreateFrom creates a new chart, but scaffolds it from the src chart.
func CreateFrom(chartfile *chart.Metadata, dest string, src string) error {
	schart, err := Load(src)
	if err != nil {
		return fmt.Errorf("could not load %s: %s", src, err)
	}

	schart.Metadata = chartfile

	var updatedTemplates []*chart.Template

	for _, template := range schart.Templates {
		newData := Transform(string(template.Data), "<CHARTNAME>", schart.Metadata.Name)
		updatedTemplates = append(updatedTemplates, &chart.Template{Name: template.Name, Data: newData})
	}

	schart.Templates = updatedTemplates
	if schart.Values != nil {
		schart.Values = &chart.Config{Raw: string(Transform(schart.Values.Raw, "<CHARTNAME>", schart.Metadata.Name))}
	}
	return SaveDir(schart, dest)
}

// Create creates a new chart in a directory.
//
// Inside of dir, this will create a directory based on the name of
// chartfile.Name. It will then write the Chart.yaml into this directory and
// create the (empty) appropriate directories.
//
// The returned string will point to the newly created directory. It will be
// an absolute path, even if the provided base directory was relative.
//
// If dir does not exist, this will return an error.
// If Chart.yaml or any directories cannot be created, this will return an
// error. In such a case, this will attempt to clean up by removing the
// new chart directory.
func Create(chartfile *chart.Metadata, dir string) (string, error) {
	path, err := filepath.Abs(dir)
	if err != nil {
		return path, err
	}

	if fi, err := os.Stat(path); err != nil {
		return path, err
	} else if !fi.IsDir() {
		return path, fmt.Errorf("no such directory %s", path)
	}

	n := chartfile.Name
	cdir := filepath.Join(path, n)
	if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
		return cdir, fmt.Errorf("file %s already exists and is not a directory", cdir)
	}
	if err := os.MkdirAll(cdir, 0755); err != nil {
		return cdir, err
	}

	cf := filepath.Join(cdir, ChartfileName)
	if _, err := os.Stat(cf); err != nil {
		if err := SaveChartfile(cf, chartfile); err != nil {
			return cdir, err
		}
	}

	for _, d := range []string{TemplatesDir, ChartsDir} {
		if err := os.MkdirAll(filepath.Join(cdir, d), 0755); err != nil {
			return cdir, err
		}
	}

	files := []struct {
		path    string
		content []byte
	}{
		{
			// values.yaml
			path:    filepath.Join(cdir, ValuesfileName),
			content: []byte(fmt.Sprintf(defaultValues, chartfile.Name)),
		},
		{
			// .helmignore
			path:    filepath.Join(cdir, IgnorefileName),
			content: []byte(defaultIgnore),
		},
		{
			// ingress.yaml
			path:    filepath.Join(cdir, TemplatesDir, IngressFileName),
			content: Transform(defaultIngress, "<CHARTNAME>", chartfile.Name),
		},
		{
			// deployment.yaml
			path:    filepath.Join(cdir, TemplatesDir, DeploymentName),
			content: Transform(defaultDeployment, "<CHARTNAME>", chartfile.Name),
		},
		{
			// service.yaml
			path:    filepath.Join(cdir, TemplatesDir, ServiceName),
			content: Transform(defaultService, "<CHARTNAME>", chartfile.Name),
		},
		{
			// NOTES.txt
			path:    filepath.Join(cdir, TemplatesDir, NotesName),
			content: Transform(defaultNotes, "<CHARTNAME>", chartfile.Name),
		},
		{
			// _helpers.tpl
			path:    filepath.Join(cdir, TemplatesDir, HelpersName),
			content: Transform(defaultHelpers, "<CHARTNAME>", chartfile.Name),
		},
	}

	for _, file := range files {
		if _, err := os.Stat(file.path); err == nil {
			// File exists and is okay. Skip it.
			continue
		}
		if err := ioutil.WriteFile(file.path, file.content, 0644); err != nil {
			return cdir, err
		}
	}
	return cdir, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package server

import (
	"fmt"
	"io"
	"net"

	"github.com/spf13/cobra"

	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	"k8s.io/apiextensions-apiserver/pkg/apiserver"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	genericregistry "k8s.io/apiserver/pkg/registry/generic"
	genericapiserver "k8s.io/apiserver/pkg/server"
	genericoptions "k8s.io/apiserver/pkg/server/options"
)

const defaultEtcdPathPrefix = "/registry/apiextensions.kubernetes.io"

type CustomResourceDefinitionsServerOptions struct {
	RecommendedOptions *genericoptions.RecommendedOptions

	StdOut io.Writer
	StdErr io.Writer
}

func NewCustomResourceDefinitionsServerOptions(out, errOut io.Writer) *CustomResourceDefinitionsServerOptions {
	o := &CustomResourceDefinitionsServerOptions{
		RecommendedOptions: genericoptions.NewRecommendedOptions(defaultEtcdPathPrefix, apiserver.Scheme, apiserver.Codecs.LegacyCodec(v1beta1.SchemeGroupVersion)),

		StdOut: out,
		StdErr: errOut,
	}

	return o
}

func NewCommandStartCustomResourceDefinitionsServer(out, errOut io.Writer, stopCh <-chan struct{}) *cobra.Command {
	o := NewCustomResourceDefinitionsServerOptions(out, errOut)

	cmd := &cobra.Command{
		Short: "Launch an API extensions API server",
		Long:  "Launch an API extensions API server",
		RunE: func(c *cobra.Command, args []string) error {
			if err := o.Complete(); err != nil {
				return err
			}
			if err := o.Validate(args); err != nil {
				return err
			}
			if err := o.RunCustomResourceDefinitionsServer(stopCh); err != nil {
				return err
			}
			return nil
		},
	}

	flags := cmd.Flags()
	o.RecommendedOptions.AddFlags(flags)

	return cmd
}

func (o CustomResourceDefinitionsServerOptions) Validate(args []string) error {
	return nil
}

func (o *CustomResourceDefinitionsServerOptions) Complete() error {
	return nil
}

func (o CustomResourceDefinitionsServerOptions) Config() (*apiserver.Config, error) {
	// TODO have a "real" external address
	if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost", nil, []net.IP{net.ParseIP("127.0.0.1")}); err != nil {
		return nil, fmt.Errorf("error creating self-signed certificates: %v", err)
	}

	serverConfig := genericapiserver.NewConfig(apiserver.Codecs)
	if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
		return nil, err
	}

	config := &apiserver.Config{
		GenericConfig:        serverConfig,
		CRDRESTOptionsGetter: NewCRDRESTOptionsGetter(*o.RecommendedOptions.Etcd),
	}
	return config, nil
}

func NewCRDRESTOptionsGetter(etcdOptions genericoptions.EtcdOptions) genericregistry.RESTOptionsGetter {
	ret := apiserver.CRDRESTOptionsGetter{
		StorageConfig:           etcdOptions.StorageConfig,
		StoragePrefix:           etcdOptions.StorageConfig.Prefix,
		EnableWatchCache:        etcdOptions.EnableWatchCache,
		DefaultWatchCacheSize:   etcdOptions.DefaultWatchCacheSize,
		EnableGarbageCollection: etcdOptions.EnableGarbageCollection,
		DeleteCollectionWorkers: etcdOptions.DeleteCollectionWorkers,
	}
	ret.StorageConfig.Codec = unstructured.UnstructuredJSONScheme
	ret.StorageConfig.Copier = apiserver.UnstructuredCopier{}

	return ret
}

func (o CustomResourceDefinitionsServerOptions) RunCustomResourceDefinitionsServer(stopCh <-chan struct{}) error {
	config, err := o.Config()
	if err != nil {
		return err
	}

	server, err := config.Complete().New(genericapiserver.EmptyDelegate)
	if err != nil {
		return err
	}
	return server.GenericAPIServer.PrepareRun().Run(stopCh)
}
<commit_msg>disable GC for custom resources<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package server

import (
	"fmt"
	"io"
	"net"

	"github.com/spf13/cobra"

	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	"k8s.io/apiextensions-apiserver/pkg/apiserver"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	genericregistry "k8s.io/apiserver/pkg/registry/generic"
	genericapiserver "k8s.io/apiserver/pkg/server"
	genericoptions "k8s.io/apiserver/pkg/server/options"
)

const defaultEtcdPathPrefix = "/registry/apiextensions.kubernetes.io"

type CustomResourceDefinitionsServerOptions struct {
	RecommendedOptions *genericoptions.RecommendedOptions

	StdOut io.Writer
	StdErr io.Writer
}

func NewCustomResourceDefinitionsServerOptions(out, errOut io.Writer) *CustomResourceDefinitionsServerOptions {
	o := &CustomResourceDefinitionsServerOptions{
		RecommendedOptions: genericoptions.NewRecommendedOptions(defaultEtcdPathPrefix, apiserver.Scheme, apiserver.Codecs.LegacyCodec(v1beta1.SchemeGroupVersion)),

		StdOut: out,
		StdErr: errOut,
	}

	return o
}

func NewCommandStartCustomResourceDefinitionsServer(out, errOut io.Writer, stopCh <-chan struct{}) *cobra.Command {
	o := NewCustomResourceDefinitionsServerOptions(out, errOut)

	cmd := &cobra.Command{
		Short: "Launch an API extensions API server",
		Long:  "Launch an API extensions API server",
		RunE: func(c *cobra.Command, args []string) error {
			if err := o.Complete(); err != nil {
				return err
			}
			if err := o.Validate(args); err != nil {
				return err
			}
			if err := o.RunCustomResourceDefinitionsServer(stopCh); err != nil {
				return err
			}
			return nil
		},
	}

	flags := cmd.Flags()
	o.RecommendedOptions.AddFlags(flags)

	return cmd
}

func (o CustomResourceDefinitionsServerOptions) Validate(args []string) error {
	return nil
}

func (o *CustomResourceDefinitionsServerOptions) Complete() error {
	return nil
}

func (o CustomResourceDefinitionsServerOptions) Config() (*apiserver.Config, error) {
	// TODO have a "real" external address
	if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost", nil, []net.IP{net.ParseIP("127.0.0.1")}); err != nil {
		return nil, fmt.Errorf("error creating self-signed certificates: %v", err)
	}

	serverConfig := genericapiserver.NewConfig(apiserver.Codecs)
	if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
		return nil, err
	}

	config := &apiserver.Config{
		GenericConfig:        serverConfig,
		CRDRESTOptionsGetter: NewCRDRESTOptionsGetter(*o.RecommendedOptions.Etcd),
	}
	return config, nil
}

func NewCRDRESTOptionsGetter(etcdOptions genericoptions.EtcdOptions) genericregistry.RESTOptionsGetter {
	ret := apiserver.CRDRESTOptionsGetter{
		StorageConfig:         etcdOptions.StorageConfig,
		StoragePrefix:         etcdOptions.StorageConfig.Prefix,
		EnableWatchCache:      etcdOptions.EnableWatchCache,
		DefaultWatchCacheSize: etcdOptions.DefaultWatchCacheSize,
		// garbage collection for custom resources is forced off until GC works with CRs.
		// When GC is enabled, this turns back into etcdOptions.EnableGarbageCollection
		EnableGarbageCollection: false,
		DeleteCollectionWorkers: etcdOptions.DeleteCollectionWorkers,
	}
	ret.StorageConfig.Codec = unstructured.UnstructuredJSONScheme
	ret.StorageConfig.Copier = apiserver.UnstructuredCopier{}

	return ret
}

func (o CustomResourceDefinitionsServerOptions) RunCustomResourceDefinitionsServer(stopCh <-chan struct{}) error {
	config, err := o.Config()
	if err != nil {
		return err
	}

	server, err := config.Complete().New(genericapiserver.EmptyDelegate)
	if err != nil {
		return err
	}
	return server.GenericAPIServer.PrepareRun().Run(stopCh)
}
<|endoftext|>


<commit_before>package runtime_test

import (
	"net/http"
	"testing"

	"github.com/gengo/grpc-gateway/runtime"
	"golang.org/x/net/context"
	"google.golang.org/grpc/metadata"
)

func TestAnnotateContext(t *testing.T) {
	ctx := context.Background()

	request, _ := http.NewRequest("GET", "http://localhost", nil)
	request.Header = http.Header{}
	annotated := runtime.AnnotateContext(ctx, request)
	if annotated != ctx {
		t.Errorf("AnnotateContext(ctx, request) = %v; want %v", annotated, ctx)
	}
	request.Header.Add("Grpc-Metadata-FooBar", "Value1")
	request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2")
	annotated = runtime.AnnotateContext(ctx, request)
	md, ok := metadata.FromContext(annotated)
	if !ok || len(md) != 2 {
		t.Errorf("Expected 2 metadata items in context; got %v", md)
	}
	if md["Foobar"] != "Value1" {
		t.Errorf("md[\"Foobar\"] = %v; want %v", md["Foobar"], "Value1")
	}
	if md["Foo-Baz"] != "Value2" {
		t.Errorf("md[\"Foo-Baz\"] = %v want %v", md["Foo-Baz"], "Value2")
	}
}
<commit_msg>Follow definition change of metadata.Meta in grpc-go<commit_after>package runtime_test

import (
	"Reflect"
	"net/http"
	"testing"

	"github.com/gengo/grpc-gateway/runtime"
	"golang.org/x/net/context"
	"google.golang.org/grpc/metadata"
)

func TestAnnotateContext(t *testing.T) {
	ctx := context.Background()

	request, _ := http.NewRequest("GET", "http://localhost", nil)
	request.Header = http.Header{}
	annotated := runtime.AnnotateContext(ctx, request)
	if annotated != ctx {
		t.Errorf("AnnotateContext(ctx, request) = %v; want %v", annotated, ctx)
	}
	request.Header.Add("Grpc-Metadata-FooBar", "Value1")
	request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2")
	annotated = runtime.AnnotateContext(ctx, request)
	md, ok := metadata.FromContext(annotated)
	if !ok || len(md) != 2 {
		t.Errorf("Expected 2 metadata items in context; got %v", md)
	}
	if got, want := md["Foobar"], []string{"Value1"}; !reflect.DeepEqual(got, want) {
		t.Errorf("md[\"Foobar\"] = %v; want %v", got, want)
	}
	if got, want := md["Foo-Baz"], []string{"Value2"}; !reflect.DeepEqual(got, want) {
		t.Errorf("md[\"Foo-Baz\"] = %v want %v", got, want)
	}
}
<|endoftext|>


<commit_before>package libdocker

import (
	"os"
	"os/exec"
	"os/signal"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/docker/libcontainer"
	"github.com/docker/libcontainer/configs"
	"github.com/docker/libcontainer/utils"
)

var standardEnvironment = &cli.StringSlice{
	"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
	"HOSTNAME=nsinit",
	"TERM=xterm",
}

// RunInContainer runs a process in a running docker container using the options
// specified. It returns the exit code and/or error.
func RunInContainer(containerId string, options *DockerExecOptions) (int, error) {
	var factory libcontainer.Factory
	var config *configs.Config
	var containerConfig *ContainerConfig
	var err error
	factory, err = loadDockerFactory()
	if err != nil {
		return -1, err
	}
	config, err = loadDockerConfig(containerId)
	if err != nil {
		return -1, err
	}

	container, err := factory.Load(containerId)
	if err != nil {
		return -1, err
	}

	containerConfig, err = loadContainerConfig(containerId)
	if err != nil {
		return -1, err
	}
	process := &libcontainer.Process{
		Args:   options.Args,
		Env:    options.Env,
		User:   options.User,
		Cwd:    options.Cwd,
		Stdin:  options.Stdin,
		Stdout: options.Stdout,
		Stderr: options.Stderr,
	}
	rootuid, err := config.HostUID()
	if err != nil {
		return -1, err
	}
	tty, err := newTty(options.Tty, process, rootuid)
	if err != nil {
		return -1, err
	}
	if err := tty.attach(process); err != nil {
		return -1, err
	}
	go handleSignals(process, tty)
	err = container.Start(process)
	if err != nil {
		tty.Close()
		return -1, err
	}

	status, err := process.Wait()
	if err != nil {
		exitError, ok := err.(*exec.ExitError)
		if ok {
			status = exitError.ProcessState
		} else {
			tty.Close()
			return -1, err
		}
	}
	tty.Close()
	return utils.ExitStatus(status.Sys().(syscall.WaitStatus)), nil
}

func handleSignals(container *libcontainer.Process, tty *tty) {
	sigc := make(chan os.Signal, 10)
	signal.Notify(sigc)
	tty.resize()
	for sig := range sigc {
		switch sig {
		case syscall.SIGWINCH:
			tty.resize()
		default:
			container.Signal(sig)
		}
	}
}
<commit_msg>Default to env/user of the container.<commit_after>package libdocker

import (
	"os"
	"os/exec"
	"os/signal"
	"syscall"

	"github.com/docker/libcontainer"
	"github.com/docker/libcontainer/configs"
	"github.com/docker/libcontainer/utils"
)

// RunInContainer runs a process in a running docker container using the options
// specified. It returns the exit code and/or error.
func RunInContainer(containerId string, options *DockerExecOptions) (int, error) {
	var factory libcontainer.Factory
	var config *configs.Config
	var containerConfig *ContainerConfig
	var err error
	factory, err = loadDockerFactory()
	if err != nil {
		return -1, err
	}
	config, err = loadDockerConfig(containerId)
	if err != nil {
		return -1, err
	}

	container, err := factory.Load(containerId)
	if err != nil {
		return -1, err
	}

	containerConfig, err = loadContainerConfig(containerId)
	if err != nil {
		return -1, err
	}

	user := options.User
	if user == "" {
		user = containerConfig.Config.User
	}

	env := containerConfig.Config.Env
	env = append(env, options.Env...)

	process := &libcontainer.Process{
		Args:   options.Args,
		Env:    env,
		User:   user,
		Cwd:    options.Cwd,
		Stdin:  options.Stdin,
		Stdout: options.Stdout,
		Stderr: options.Stderr,
	}
	rootuid, err := config.HostUID()
	if err != nil {
		return -1, err
	}
	tty, err := newTty(options.Tty, process, rootuid)
	if err != nil {
		return -1, err
	}
	if err := tty.attach(process); err != nil {
		return -1, err
	}
	go handleSignals(process, tty)
	err = container.Start(process)
	if err != nil {
		tty.Close()
		return -1, err
	}

	status, err := process.Wait()
	if err != nil {
		exitError, ok := err.(*exec.ExitError)
		if ok {
			status = exitError.ProcessState
		} else {
			tty.Close()
			return -1, err
		}
	}
	tty.Close()
	return utils.ExitStatus(status.Sys().(syscall.WaitStatus)), nil
}

func handleSignals(container *libcontainer.Process, tty *tty) {
	sigc := make(chan os.Signal, 10)
	signal.Notify(sigc)
	tty.resize()
	for sig := range sigc {
		switch sig {
		case syscall.SIGWINCH:
			tty.resize()
		default:
			container.Signal(sig)
		}
	}
}
<|endoftext|>


<commit_before>package msg_test

import (
	"testing"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux/msg"
	"github.com/stretchr/testify/assert"
)

func TestIsEvent(t *testing.T) {
	cases := map[string]struct {
		pld      []byte
		expected bool
	}{
		"event type": {
			pld:      []byte(`{}`),
			expected: true,
		},
		"not event type": {
			pld:      []byte(`[]`),
			expected: false,
		},
	}

	for k, v := range cases {
		t.Run(k, func(t *testing.T) {
			m := msg.Msg{
				Data: v.pld,
			}

			got := m.IsEvent()
			assert.Equal(t, v.expected, got)
		})
	}
}

func TestIsRaw(t *testing.T) {
	cases := map[string]struct {
		pld      []byte
		expected bool
	}{
		"raw type": {
			pld:      []byte(`[]`),
			expected: true,
		},
		"not raw type": {
			pld:      []byte(`{}`),
			expected: false,
		},
	}

	for k, v := range cases {
		t.Run(k, func(t *testing.T) {
			m := msg.Msg{
				Data: v.pld,
			}

			got := m.IsRaw()
			assert.Equal(t, v.expected, got)
		})
	}
}
<commit_msg>testing msg ability to process event type msg<commit_after>package msg_test

import (
	"testing"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/event"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux/msg"
	"github.com/stretchr/testify/assert"
)

func TestIsEvent(t *testing.T) {
	cases := map[string]struct {
		pld      []byte
		expected bool
	}{
		"event type": {
			pld:      []byte(`{}`),
			expected: true,
		},
		"not event type": {
			pld:      []byte(`[]`),
			expected: false,
		},
	}

	for k, v := range cases {
		t.Run(k, func(t *testing.T) {
			m := msg.Msg{
				Data: v.pld,
			}

			got := m.IsEvent()
			assert.Equal(t, v.expected, got)
		})
	}
}

func TestIsRaw(t *testing.T) {
	cases := map[string]struct {
		pld      []byte
		expected bool
	}{
		"raw type": {
			pld:      []byte(`[]`),
			expected: true,
		},
		"not raw type": {
			pld:      []byte(`{}`),
			expected: false,
		},
	}

	for k, v := range cases {
		t.Run(k, func(t *testing.T) {
			m := msg.Msg{
				Data: v.pld,
			}

			got := m.IsRaw()
			assert.Equal(t, v.expected, got)
		})
	}
}

func TestProcessEvent(t *testing.T) {
	m := msg.Msg{
		Data: []byte(`{"event":"info","version":2,"serverId":"dbea77ee-4740-4a82-84f3-c6bc1b5abb9a","platform":{"status":1}}`),
	}

	expected := event.Info{
		Subscribe: event.Subscribe{
			Event: "info",
		},
		Version:  2,
		ServerID: "dbea77ee-4740-4a82-84f3-c6bc1b5abb9a",
		Platform: event.Platform{Status: 1},
	}

	got, err := m.ProcessEvent()
	assert.NoError(t, err)
	assert.Equal(t, expected, got)
}
<|endoftext|>


<commit_before>package block_manager_stress_test

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/kopia/kopia/auth"
	"github.com/kopia/kopia/block"
	"github.com/kopia/kopia/repo"
	"github.com/kopia/kopia/storage"
	"github.com/kopia/kopia/storage/filesystem"
)

type testContext struct {
	r *repo.Repository
}

var (
	knownBlocks      []string
	knownBlocksMutex sync.Mutex
)

func TestStressRepository(t *testing.T) {
	ctx := context.Background()
	tmpPath, err := ioutil.TempDir("", "kopia")
	if err != nil {
		t.Fatalf("unable to create temp directory")
	}

	defer func() {
		if !t.Failed() {
			os.RemoveAll(tmpPath)
		}
	}()

	t.Logf("path: %v", tmpPath)

	creds, err := auth.Password("foo-bar-baz-1234")
	if err != nil {
		t.Fatalf("unable to initialize credentials: %v", err)
	}

	storagePath := filepath.Join(tmpPath, "storage")
	configFile1 := filepath.Join(tmpPath, "kopia1.config")
	configFile2 := filepath.Join(tmpPath, "kopia2.config")

	os.MkdirAll(storagePath, 0700)
	st, err := filesystem.New(ctx, &filesystem.Options{
		Path: storagePath,
	})
	if err != nil {
		t.Fatalf("unable to initialize storage: %v", err)
	}

	// create repository
	if err := repo.Initialize(ctx, st, &repo.NewRepositoryOptions{}, creds); err != nil {
		t.Fatalf("unable to initialize repository: %v", err)
	}

	// set up two parallel kopia connections, each with its own config file and cache.
	if err := repo.Connect(ctx, configFile1, st, creds, repo.ConnectOptions{
		PersistCredentials: true,
		CachingOptions: block.CachingOptions{
			CacheDirectory:    filepath.Join(tmpPath, "cache1"),
			MaxCacheSizeBytes: 2000000000,
		},
	}); err != nil {
		t.Fatalf("unable to connect 1: %v", err)
	}

	if err := repo.Connect(ctx, configFile2, st, creds, repo.ConnectOptions{
		PersistCredentials: true,
		CachingOptions: block.CachingOptions{
			CacheDirectory:    filepath.Join(tmpPath, "cache2"),
			MaxCacheSizeBytes: 2000000000,
		},
	}); err != nil {
		t.Fatalf("unable to connect 2: %v", err)
	}

	cancel := make(chan struct{})

	var wg sync.WaitGroup
	wg.Add(8)

	go longLivedRepositoryTest(t, cancel, configFile1, &wg)
	go longLivedRepositoryTest(t, cancel, configFile1, &wg)
	go longLivedRepositoryTest(t, cancel, configFile1, &wg)
	go longLivedRepositoryTest(t, cancel, configFile1, &wg)
	go longLivedRepositoryTest(t, cancel, configFile2, &wg)
	go longLivedRepositoryTest(t, cancel, configFile2, &wg)
	go longLivedRepositoryTest(t, cancel, configFile2, &wg)
	go longLivedRepositoryTest(t, cancel, configFile2, &wg)

	time.Sleep(5 * time.Second)
	close(cancel)

	wg.Wait()
}

func longLivedRepositoryTest(t *testing.T, cancel chan struct{}, configFile string, wg *sync.WaitGroup) {
	defer wg.Done()
	ctx := context.Background()

	rep, err := repo.Open(ctx, configFile, &repo.Options{})
	if err != nil {
		t.Errorf("error opening repository: %v", err)
		return
	}
	defer rep.Close(ctx)

	var wg2 sync.WaitGroup

	for i := 0; i < 4; i++ {
		wg2.Add(1)
		go func() {
			defer wg2.Done()

			repositoryTest(t, cancel, rep)
		}()
	}

	wg2.Wait()
}

func repositoryTest(t *testing.T, cancel chan struct{}, rep *repo.Repository) {
	ctx := context.Background()
	// reopen := func(t *testing.T, r *repo.Repository) error {
	// 	if err := rep.Close(ctx); err != nil {
	// 		return fmt.Errorf("error closing: %v", err)
	// 	}

	// 	t0 := time.Now()
	// 	rep, err = repo.Open(ctx, configFile, &repo.Options{})
	// 	log.Printf("reopened in %v", time.Since(t0))
	// 	return err
	// }

	workTypes := []*struct {
		name     string
		fun      func(t *testing.T, r *repo.Repository) error
		weight   int
		hitCount int
	}{
		//{"reopen", reopen, 1, 0},
		{"writeRandomBlock", writeRandomBlock, 100, 0},
		{"writeRandomManifest", writeRandomManifest, 100, 0},
		{"readKnownBlock", readKnownBlock, 500, 0},
		{"listBlocks", listBlocks, 50, 0},
		{"listAndReadAllBlocks", listAndReadAllBlocks, 5, 0},
		{"readRandomManifest", readRandomManifest, 50, 0},
		{"compact", compact, 1, 0},
		{"refresh", refresh, 3, 0},
		{"flush", flush, 1, 0},
	}

	var totalWeight int
	for _, w := range workTypes {
		totalWeight += w.weight
	}

	iter := 0
	for {
		select {
		case <-cancel:
			rep.Close(ctx)
			return
		default:
		}

		if iter%1000 == 0 {
			var bits []string
			for _, w := range workTypes {
				bits = append(bits, fmt.Sprintf("%v:%v", w.name, w.hitCount))
			}
			log.Printf("#%v %v %v goroutines", iter, strings.Join(bits, " "), runtime.NumGoroutine())
		}
		iter++

		roulette := rand.Intn(totalWeight)
		for _, w := range workTypes {
			if roulette < w.weight {
				w.hitCount++
				//log.Printf("running %v", w.name)
				if err := w.fun(t, rep); err != nil {
					w.hitCount++
					t.Errorf("error: %v", fmt.Errorf("error running %v: %v", w.name, err))
					return
				}
				break
			}

			roulette -= w.weight
		}
	}

}

func writeRandomBlock(t *testing.T, r *repo.Repository) error {
	ctx := context.Background()

	data := make([]byte, 1000)
	rand.Read(data)
	blockID, err := r.Blocks.WriteBlock(ctx, data, "")
	if err == nil {
		knownBlocksMutex.Lock()
		if len(knownBlocks) >= 1000 {
			n := rand.Intn(len(knownBlocks))
			knownBlocks[n] = blockID
		} else {
			knownBlocks = append(knownBlocks, blockID)
		}
		knownBlocksMutex.Unlock()
	}
	return err
}

func readKnownBlock(t *testing.T, r *repo.Repository) error {
	ctx := context.Background()

	knownBlocksMutex.Lock()
	if len(knownBlocks) == 0 {
		knownBlocksMutex.Unlock()
		return nil
	}
	blockID := knownBlocks[rand.Intn(len(knownBlocks))]
	knownBlocksMutex.Unlock()

	_, err := r.Blocks.GetBlock(ctx, blockID)
	if err == nil || err == storage.ErrBlockNotFound {
		return nil
	}

	return err
}

func listBlocks(t *testing.T, r *repo.Repository) error {
	_, err := r.Blocks.ListBlocks("")
	return err
}

func listAndReadAllBlocks(t *testing.T, r *repo.Repository) error {
	blocks, err := r.Blocks.ListBlocks("")
	if err != nil {
		return err
	}

	for _, bi := range blocks {
		_, err := r.Blocks.GetBlock(context.Background(), bi)
		if err != nil {
			return err
		}
	}

	return nil
}

func compact(t *testing.T, r *repo.Repository) error {
	return r.Blocks.CompactIndexes(context.Background(), 1, 1)
}

func flush(t *testing.T, r *repo.Repository) error {
	return r.Flush(context.Background())
}

func refresh(t *testing.T, r *repo.Repository) error {
	return r.Refresh(context.Background())
}

func readRandomManifest(t *testing.T, r *repo.Repository) error {
	manifests := r.Manifests.Find(nil)
	if len(manifests) == 0 {
		return nil
	}
	n := rand.Intn(len(manifests))
	_, err := r.Manifests.GetRaw(manifests[n].ID)
	return err
}

func writeRandomManifest(t *testing.T, r *repo.Repository) error {
	key1 := fmt.Sprintf("key-%v", rand.Intn(10))
	key2 := fmt.Sprintf("key-%v", rand.Intn(10))
	val1 := fmt.Sprintf("val1-%v", rand.Intn(10))
	val2 := fmt.Sprintf("val2-%v", rand.Intn(10))
	content1 := fmt.Sprintf("content-%v", rand.Intn(10))
	content2 := fmt.Sprintf("content-%v", rand.Intn(10))
	content1val := fmt.Sprintf("val1-%v", rand.Intn(10))
	content2val := fmt.Sprintf("val2-%v", rand.Intn(10))
	_, err := r.Manifests.Put(map[string]string{
		"type": key1,
		key1:   val1,
		key2:   val2,
	}, map[string]string{
		content1: content1val,
		content2: content2val,
	})
	return err
}
<commit_msg>disabled repository stress<commit_after>package block_manager_stress_test

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/kopia/kopia/auth"
	"github.com/kopia/kopia/block"
	"github.com/kopia/kopia/repo"
	"github.com/kopia/kopia/storage"
	"github.com/kopia/kopia/storage/filesystem"
)

type testContext struct {
	r *repo.Repository
}

var (
	knownBlocks      []string
	knownBlocksMutex sync.Mutex
)

func TestStressRepository(t *testing.T) {
	t.Skip("skipped until stress test is fixed")
	ctx := context.Background()
	tmpPath, err := ioutil.TempDir("", "kopia")
	if err != nil {
		t.Fatalf("unable to create temp directory")
	}

	defer func() {
		if !t.Failed() {
			os.RemoveAll(tmpPath)
		}
	}()

	t.Logf("path: %v", tmpPath)

	creds, err := auth.Password("foo-bar-baz-1234")
	if err != nil {
		t.Fatalf("unable to initialize credentials: %v", err)
	}

	storagePath := filepath.Join(tmpPath, "storage")
	configFile1 := filepath.Join(tmpPath, "kopia1.config")
	configFile2 := filepath.Join(tmpPath, "kopia2.config")

	os.MkdirAll(storagePath, 0700)
	st, err := filesystem.New(ctx, &filesystem.Options{
		Path: storagePath,
	})
	if err != nil {
		t.Fatalf("unable to initialize storage: %v", err)
	}

	// create repository
	if err := repo.Initialize(ctx, st, &repo.NewRepositoryOptions{}, creds); err != nil {
		t.Fatalf("unable to initialize repository: %v", err)
	}

	// set up two parallel kopia connections, each with its own config file and cache.
	if err := repo.Connect(ctx, configFile1, st, creds, repo.ConnectOptions{
		PersistCredentials: true,
		CachingOptions: block.CachingOptions{
			CacheDirectory:    filepath.Join(tmpPath, "cache1"),
			MaxCacheSizeBytes: 2000000000,
		},
	}); err != nil {
		t.Fatalf("unable to connect 1: %v", err)
	}

	if err := repo.Connect(ctx, configFile2, st, creds, repo.ConnectOptions{
		PersistCredentials: true,
		CachingOptions: block.CachingOptions{
			CacheDirectory:    filepath.Join(tmpPath, "cache2"),
			MaxCacheSizeBytes: 2000000000,
		},
	}); err != nil {
		t.Fatalf("unable to connect 2: %v", err)
	}

	cancel := make(chan struct{})

	var wg sync.WaitGroup
	wg.Add(8)

	go longLivedRepositoryTest(t, cancel, configFile1, &wg)
	go longLivedRepositoryTest(t, cancel, configFile1, &wg)
	go longLivedRepositoryTest(t, cancel, configFile1, &wg)
	go longLivedRepositoryTest(t, cancel, configFile1, &wg)
	go longLivedRepositoryTest(t, cancel, configFile2, &wg)
	go longLivedRepositoryTest(t, cancel, configFile2, &wg)
	go longLivedRepositoryTest(t, cancel, configFile2, &wg)
	go longLivedRepositoryTest(t, cancel, configFile2, &wg)

	time.Sleep(5 * time.Second)
	close(cancel)

	wg.Wait()
}

func longLivedRepositoryTest(t *testing.T, cancel chan struct{}, configFile string, wg *sync.WaitGroup) {
	defer wg.Done()
	ctx := context.Background()

	rep, err := repo.Open(ctx, configFile, &repo.Options{})
	if err != nil {
		t.Errorf("error opening repository: %v", err)
		return
	}
	defer rep.Close(ctx)

	var wg2 sync.WaitGroup

	for i := 0; i < 4; i++ {
		wg2.Add(1)
		go func() {
			defer wg2.Done()

			repositoryTest(t, cancel, rep)
		}()
	}

	wg2.Wait()
}

func repositoryTest(t *testing.T, cancel chan struct{}, rep *repo.Repository) {
	ctx := context.Background()
	// reopen := func(t *testing.T, r *repo.Repository) error {
	// 	if err := rep.Close(ctx); err != nil {
	// 		return fmt.Errorf("error closing: %v", err)
	// 	}

	// 	t0 := time.Now()
	// 	rep, err = repo.Open(ctx, configFile, &repo.Options{})
	// 	log.Printf("reopened in %v", time.Since(t0))
	// 	return err
	// }

	workTypes := []*struct {
		name     string
		fun      func(t *testing.T, r *repo.Repository) error
		weight   int
		hitCount int
	}{
		//{"reopen", reopen, 1, 0},
		{"writeRandomBlock", writeRandomBlock, 100, 0},
		{"writeRandomManifest", writeRandomManifest, 100, 0},
		{"readKnownBlock", readKnownBlock, 500, 0},
		{"listBlocks", listBlocks, 50, 0},
		{"listAndReadAllBlocks", listAndReadAllBlocks, 5, 0},
		{"readRandomManifest", readRandomManifest, 50, 0},
		{"compact", compact, 1, 0},
		{"refresh", refresh, 3, 0},
		{"flush", flush, 1, 0},
	}

	var totalWeight int
	for _, w := range workTypes {
		totalWeight += w.weight
	}

	iter := 0
	for {
		select {
		case <-cancel:
			rep.Close(ctx)
			return
		default:
		}

		if iter%1000 == 0 {
			var bits []string
			for _, w := range workTypes {
				bits = append(bits, fmt.Sprintf("%v:%v", w.name, w.hitCount))
			}
			log.Printf("#%v %v %v goroutines", iter, strings.Join(bits, " "), runtime.NumGoroutine())
		}
		iter++

		roulette := rand.Intn(totalWeight)
		for _, w := range workTypes {
			if roulette < w.weight {
				w.hitCount++
				//log.Printf("running %v", w.name)
				if err := w.fun(t, rep); err != nil {
					w.hitCount++
					t.Errorf("error: %v", fmt.Errorf("error running %v: %v", w.name, err))
					return
				}
				break
			}

			roulette -= w.weight
		}
	}

}

func writeRandomBlock(t *testing.T, r *repo.Repository) error {
	ctx := context.Background()

	data := make([]byte, 1000)
	rand.Read(data)
	blockID, err := r.Blocks.WriteBlock(ctx, data, "")
	if err == nil {
		knownBlocksMutex.Lock()
		if len(knownBlocks) >= 1000 {
			n := rand.Intn(len(knownBlocks))
			knownBlocks[n] = blockID
		} else {
			knownBlocks = append(knownBlocks, blockID)
		}
		knownBlocksMutex.Unlock()
	}
	return err
}

func readKnownBlock(t *testing.T, r *repo.Repository) error {
	ctx := context.Background()

	knownBlocksMutex.Lock()
	if len(knownBlocks) == 0 {
		knownBlocksMutex.Unlock()
		return nil
	}
	blockID := knownBlocks[rand.Intn(len(knownBlocks))]
	knownBlocksMutex.Unlock()

	_, err := r.Blocks.GetBlock(ctx, blockID)
	if err == nil || err == storage.ErrBlockNotFound {
		return nil
	}

	return err
}

func listBlocks(t *testing.T, r *repo.Repository) error {
	_, err := r.Blocks.ListBlocks("")
	return err
}

func listAndReadAllBlocks(t *testing.T, r *repo.Repository) error {
	blocks, err := r.Blocks.ListBlocks("")
	if err != nil {
		return err
	}

	for _, bi := range blocks {
		_, err := r.Blocks.GetBlock(context.Background(), bi)
		if err != nil {
			return err
		}
	}

	return nil
}

func compact(t *testing.T, r *repo.Repository) error {
	return r.Blocks.CompactIndexes(context.Background(), 1, 1)
}

func flush(t *testing.T, r *repo.Repository) error {
	return r.Flush(context.Background())
}

func refresh(t *testing.T, r *repo.Repository) error {
	return r.Refresh(context.Background())
}

func readRandomManifest(t *testing.T, r *repo.Repository) error {
	manifests := r.Manifests.Find(nil)
	if len(manifests) == 0 {
		return nil
	}
	n := rand.Intn(len(manifests))
	_, err := r.Manifests.GetRaw(manifests[n].ID)
	return err
}

func writeRandomManifest(t *testing.T, r *repo.Repository) error {
	key1 := fmt.Sprintf("key-%v", rand.Intn(10))
	key2 := fmt.Sprintf("key-%v", rand.Intn(10))
	val1 := fmt.Sprintf("val1-%v", rand.Intn(10))
	val2 := fmt.Sprintf("val2-%v", rand.Intn(10))
	content1 := fmt.Sprintf("content-%v", rand.Intn(10))
	content2 := fmt.Sprintf("content-%v", rand.Intn(10))
	content1val := fmt.Sprintf("val1-%v", rand.Intn(10))
	content2val := fmt.Sprintf("val2-%v", rand.Intn(10))
	_, err := r.Manifests.Put(map[string]string{
		"type": key1,
		key1:   val1,
		key2:   val2,
	}, map[string]string{
		content1: content1val,
		content2: content2val,
	})
	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package util

import (
	"fmt"
	"os"
	"path"

	"github.com/golang/glog"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/api/v1"
	storage "k8s.io/kubernetes/pkg/apis/storage/v1beta1"
	"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
	"k8s.io/kubernetes/pkg/util/mount"
)

const readyFileName = "ready"

// IsReady checks for the existence of a regular file
// called 'ready' in the given directory and returns
// true if that file exists.
func IsReady(dir string) bool {
	readyFile := path.Join(dir, readyFileName)
	s, err := os.Stat(readyFile)
	if err != nil {
		return false
	}

	if !s.Mode().IsRegular() {
		glog.Errorf("ready-file is not a file: %s", readyFile)
		return false
	}

	return true
}

// SetReady creates a file called 'ready' in the given
// directory.  It logs an error if the file cannot be
// created.
func SetReady(dir string) {
	if err := os.MkdirAll(dir, 0750); err != nil && !os.IsExist(err) {
		glog.Errorf("Can't mkdir %s: %v", dir, err)
		return
	}

	readyFile := path.Join(dir, readyFileName)
	file, err := os.Create(readyFile)
	if err != nil {
		glog.Errorf("Can't touch %s: %v", readyFile, err)
		return
	}
	file.Close()
}

// UnmountPath is a common unmount routine that unmounts the given path and
// deletes the remaining directory if successful.
func UnmountPath(mountPath string, mounter mount.Interface) error {
	if pathExists, pathErr := PathExists(mountPath); pathErr != nil {
		return fmt.Errorf("Error checking if path exists: %v", pathErr)
	} else if !pathExists {
		glog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath)
		return nil
	}

	notMnt, err := mounter.IsLikelyNotMountPoint(mountPath)
	if err != nil {
		return err
	}
	if notMnt {
		glog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath)
		return os.Remove(mountPath)
	}

	// Unmount the mount path
	if err := mounter.Unmount(mountPath); err != nil {
		return err
	}
	notMnt, mntErr := mounter.IsLikelyNotMountPoint(mountPath)
	if mntErr != nil {
		return err
	}
	if notMnt {
		glog.V(4).Infof("%q is unmounted, deleting the directory", mountPath)
		return os.Remove(mountPath)
	}
	return fmt.Errorf("Failed to unmount path %v", mountPath)
}

// PathExists returns true if the specified path exists.
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	} else if os.IsNotExist(err) {
		return false, nil
	} else {
		return false, err
	}
}

// GetSecretForPod locates secret by name in the pod's namespace and returns secret map
func GetSecretForPod(pod *v1.Pod, secretName string, kubeClient clientset.Interface) (map[string]string, error) {
	secret := make(map[string]string)
	if kubeClient == nil {
		return secret, fmt.Errorf("Cannot get kube client")
	}
	secrets, err := kubeClient.Core().Secrets(pod.Namespace).Get(secretName, metav1.GetOptions{})
	if err != nil {
		return secret, err
	}
	for name, data := range secrets.Data {
		secret[name] = string(data)
	}
	return secret, nil
}

// GetSecretForPV locates secret by name and namespace, verifies the secret type, and returns secret map
func GetSecretForPV(secretNamespace, secretName, volumePluginName string, kubeClient clientset.Interface) (map[string]string, error) {
	secret := make(map[string]string)
	if kubeClient == nil {
		return secret, fmt.Errorf("Cannot get kube client")
	}
	secrets, err := kubeClient.Core().Secrets(secretNamespace).Get(secretName, metav1.GetOptions{})
	if err != nil {
		return secret, err
	}
	if secrets.Type != v1.SecretType(volumePluginName) {
		return secret, fmt.Errorf("Cannot get secret of type %s", volumePluginName)
	}
	for name, data := range secrets.Data {
		secret[name] = string(data)
	}
	return secret, nil
}

func GetClassForVolume(kubeClient clientset.Interface, pv *v1.PersistentVolume) (*storage.StorageClass, error) {
	if kubeClient == nil {
		return nil, fmt.Errorf("Cannot get kube client")
	}
	// TODO: replace with a real attribute after beta
	className, found := pv.Annotations["volume.beta.kubernetes.io/storage-class"]
	if !found {
		return nil, fmt.Errorf("Volume has no class annotation")
	}

	class, err := kubeClient.Storage().StorageClasses().Get(className, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}
	return class, nil
}
<commit_msg>Add storage.k8s.io/v1<commit_after>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package util

import (
	"fmt"
	"os"
	"path"

	"github.com/golang/glog"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/api/v1"
	storage "k8s.io/kubernetes/pkg/apis/storage/v1"
	"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
	"k8s.io/kubernetes/pkg/util/mount"
)

const readyFileName = "ready"

// IsReady checks for the existence of a regular file
// called 'ready' in the given directory and returns
// true if that file exists.
func IsReady(dir string) bool {
	readyFile := path.Join(dir, readyFileName)
	s, err := os.Stat(readyFile)
	if err != nil {
		return false
	}

	if !s.Mode().IsRegular() {
		glog.Errorf("ready-file is not a file: %s", readyFile)
		return false
	}

	return true
}

// SetReady creates a file called 'ready' in the given
// directory.  It logs an error if the file cannot be
// created.
func SetReady(dir string) {
	if err := os.MkdirAll(dir, 0750); err != nil && !os.IsExist(err) {
		glog.Errorf("Can't mkdir %s: %v", dir, err)
		return
	}

	readyFile := path.Join(dir, readyFileName)
	file, err := os.Create(readyFile)
	if err != nil {
		glog.Errorf("Can't touch %s: %v", readyFile, err)
		return
	}
	file.Close()
}

// UnmountPath is a common unmount routine that unmounts the given path and
// deletes the remaining directory if successful.
func UnmountPath(mountPath string, mounter mount.Interface) error {
	if pathExists, pathErr := PathExists(mountPath); pathErr != nil {
		return fmt.Errorf("Error checking if path exists: %v", pathErr)
	} else if !pathExists {
		glog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath)
		return nil
	}

	notMnt, err := mounter.IsLikelyNotMountPoint(mountPath)
	if err != nil {
		return err
	}
	if notMnt {
		glog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath)
		return os.Remove(mountPath)
	}

	// Unmount the mount path
	if err := mounter.Unmount(mountPath); err != nil {
		return err
	}
	notMnt, mntErr := mounter.IsLikelyNotMountPoint(mountPath)
	if mntErr != nil {
		return err
	}
	if notMnt {
		glog.V(4).Infof("%q is unmounted, deleting the directory", mountPath)
		return os.Remove(mountPath)
	}
	return fmt.Errorf("Failed to unmount path %v", mountPath)
}

// PathExists returns true if the specified path exists.
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	} else if os.IsNotExist(err) {
		return false, nil
	} else {
		return false, err
	}
}

// GetSecretForPod locates secret by name in the pod's namespace and returns secret map
func GetSecretForPod(pod *v1.Pod, secretName string, kubeClient clientset.Interface) (map[string]string, error) {
	secret := make(map[string]string)
	if kubeClient == nil {
		return secret, fmt.Errorf("Cannot get kube client")
	}
	secrets, err := kubeClient.Core().Secrets(pod.Namespace).Get(secretName, metav1.GetOptions{})
	if err != nil {
		return secret, err
	}
	for name, data := range secrets.Data {
		secret[name] = string(data)
	}
	return secret, nil
}

// GetSecretForPV locates secret by name and namespace, verifies the secret type, and returns secret map
func GetSecretForPV(secretNamespace, secretName, volumePluginName string, kubeClient clientset.Interface) (map[string]string, error) {
	secret := make(map[string]string)
	if kubeClient == nil {
		return secret, fmt.Errorf("Cannot get kube client")
	}
	secrets, err := kubeClient.Core().Secrets(secretNamespace).Get(secretName, metav1.GetOptions{})
	if err != nil {
		return secret, err
	}
	if secrets.Type != v1.SecretType(volumePluginName) {
		return secret, fmt.Errorf("Cannot get secret of type %s", volumePluginName)
	}
	for name, data := range secrets.Data {
		secret[name] = string(data)
	}
	return secret, nil
}

func GetClassForVolume(kubeClient clientset.Interface, pv *v1.PersistentVolume) (*storage.StorageClass, error) {
	if kubeClient == nil {
		return nil, fmt.Errorf("Cannot get kube client")
	}
	// TODO: replace with a real attribute after beta
	className, found := pv.Annotations["volume.beta.kubernetes.io/storage-class"]
	if !found {
		return nil, fmt.Errorf("Volume has no class annotation")
	}

	class, err := kubeClient.Storage().StorageClasses().Get(className, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}
	return class, nil
}
<|endoftext|>


<commit_before>package wfe

import (
	"fmt"
	"net/http"
	"time"

	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
	"github.com/letsencrypt/boulder/core"
	blog "github.com/letsencrypt/boulder/log"
)

type requestEvent struct {
	ID            string    `json:",omitempty"`
	RealIP        string    `json:",omitempty"`
	ClientAddr    string    `json:",omitempty"`
	Endpoint      string    `json:",omitempty"`
	Method        string    `json:",omitempty"`
	RequestTime   time.Time `json:",omitempty"`
	ResponseTime  time.Time `json:",omitempty"`
	Errors        []string
	Requester     int64                  `json:",omitempty"`
	Contacts      []*core.AcmeURL        `json:",omitempty"`
	RequestNonce  string                 `json:",omitempty"`
	ResponseNonce string                 `json:",omitempty"`
	Extra         map[string]interface{} `json:",omitempty"`
}

func (e *requestEvent) AddError(msg string, args ...interface{}) {
	e.Errors = append(e.Errors, fmt.Sprintf(msg, args...))
}

type wfeHandlerFunc func(*requestEvent, http.ResponseWriter, *http.Request)

func (f wfeHandlerFunc) ServeHTTP(e *requestEvent, w http.ResponseWriter, r *http.Request) {
	f(e, w, r)
}

type wfeHandler interface {
	ServeHTTP(e *requestEvent, w http.ResponseWriter, r *http.Request)
}

type topHandler struct {
	wfe wfeHandler
	log *blog.AuditLogger
	clk clock.Clock
}

func (th *topHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	logEvent := &requestEvent{
		ID:          core.NewToken(),
		RealIP:      r.Header.Get("X-Real-IP"),
		ClientAddr:  getClientAddr(r),
		Method:      r.Method,
		RequestTime: time.Now(),
		Extra:       make(map[string]interface{}, 0),
	}
	if r.URL != nil {
		logEvent.Endpoint = r.URL.String()
	}
	defer th.logEvent(logEvent)

	th.wfe.ServeHTTP(logEvent, w, r)
}

func (th *topHandler) logEvent(logEvent *requestEvent) {
	logEvent.ResponseTime = th.clk.Now()
	var msg string
	if len(logEvent.Errors) != 0 {
		msg = "Terminated request"
	} else {
		msg = "Successful request"
	}
	th.log.InfoObject(msg, logEvent)
}

// Comma-separated list of HTTP clients involved in making this
// request, starting with the original requestor and ending with the
// remote end of our TCP connection (which is typically our own
// proxy).
func getClientAddr(r *http.Request) string {
	if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
		return xff + "," + r.RemoteAddr
	}
	return r.RemoteAddr
}
<commit_msg>include User-Agent in logEvent<commit_after>package wfe

import (
	"fmt"
	"net/http"
	"time"

	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
	"github.com/letsencrypt/boulder/core"
	blog "github.com/letsencrypt/boulder/log"
)

type requestEvent struct {
	ID            string    `json:",omitempty"`
	RealIP        string    `json:",omitempty"`
	ClientAddr    string    `json:",omitempty"`
	Endpoint      string    `json:",omitempty"`
	Method        string    `json:",omitempty"`
	RequestTime   time.Time `json:",omitempty"`
	ResponseTime  time.Time `json:",omitempty"`
	Errors        []string
	Requester     int64                  `json:",omitempty"`
	Contacts      []*core.AcmeURL        `json:",omitempty"`
	RequestNonce  string                 `json:",omitempty"`
	ResponseNonce string                 `json:",omitempty"`
	UserAgent     string                 `json:",omitempty"`
	Extra         map[string]interface{} `json:",omitempty"`
}

func (e *requestEvent) AddError(msg string, args ...interface{}) {
	e.Errors = append(e.Errors, fmt.Sprintf(msg, args...))
}

type wfeHandlerFunc func(*requestEvent, http.ResponseWriter, *http.Request)

func (f wfeHandlerFunc) ServeHTTP(e *requestEvent, w http.ResponseWriter, r *http.Request) {
	f(e, w, r)
}

type wfeHandler interface {
	ServeHTTP(e *requestEvent, w http.ResponseWriter, r *http.Request)
}

type topHandler struct {
	wfe wfeHandler
	log *blog.AuditLogger
	clk clock.Clock
}

func (th *topHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	logEvent := &requestEvent{
		ID:          core.NewToken(),
		RealIP:      r.Header.Get("X-Real-IP"),
		ClientAddr:  getClientAddr(r),
		Method:      r.Method,
		RequestTime: time.Now(),
		UserAgent:   r.Header.Get("User-Agent"),
		Extra:       make(map[string]interface{}, 0),
	}
	if r.URL != nil {
		logEvent.Endpoint = r.URL.String()
	}
	defer th.logEvent(logEvent)

	th.wfe.ServeHTTP(logEvent, w, r)
}

func (th *topHandler) logEvent(logEvent *requestEvent) {
	logEvent.ResponseTime = th.clk.Now()
	var msg string
	if len(logEvent.Errors) != 0 {
		msg = "Terminated request"
	} else {
		msg = "Successful request"
	}
	th.log.InfoObject(msg, logEvent)
}

// Comma-separated list of HTTP clients involved in making this
// request, starting with the original requestor and ending with the
// remote end of our TCP connection (which is typically our own
// proxy).
func getClientAddr(r *http.Request) string {
	if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
		return xff + "," + r.RemoteAddr
	}
	return r.RemoteAddr
}
<|endoftext|>


<commit_before>package models

import "github.com/jinzhu/gorm"

type Response struct {
	gorm.Model
	Post
	RequestID uint
}
<commit_msg>Add value/accepted responses<commit_after>package models

import "github.com/jinzhu/gorm"

type Response struct {
	gorm.Model
	Post
	RequestID uint
	Value uint
	Accepted bool
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"math/rand"
	"socialapi/models"
	"strconv"
	"testing"
	. "github.com/smartystreets/goconvey/convey"
)

func TestPrivateMesssage(t *testing.T) {
	Convey("while testing private messages", t, func() {
		account := models.NewAccount()
		account.OldId = AccountOldId.Hex()
		account, err := createAccount(account)
		So(err, ShouldBeNil)
		So(account, ShouldNotBeNil)

		recepient := models.NewAccount()
		recepient.OldId = AccountOldId2.Hex()
		recepient, err = createAccount(recepient)
		So(err, ShouldBeNil)
		So(recepient, ShouldNotBeNil)

		recepient2 := models.NewAccount()
		recepient2.OldId = AccountOldId3.Hex()
		recepient2, err = createAccount(recepient2)
		So(err, ShouldBeNil)
		So(recepient2, ShouldNotBeNil)

		groupName := "testgroup" + strconv.FormatInt(rand.Int63(), 10)

		Convey("one can send private message to one person", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)

		})

		Convey("0 recipient should fail", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{},
				groupName,
			)
			So(err, ShouldNotBeNil)
			So(cmc, ShouldBeNil)

		})
		Convey("if body is nil, should fail to create PM", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"",
				[]int64{recepient.Id},
				groupName,
			)
			So(err, ShouldNotBeNil)
			So(cmc, ShouldBeNil)
		})
		Convey("if group name is nil, should not fail to create PM", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id},
				"",
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)
		})

		Convey("if sender is not defined should fail to create PM", func() {
			cmc, err := sendPrivateMessage(
				0,
				"this is a body for private message",
				[]int64{recepient.Id},
				"",
			)
			So(err, ShouldNotBeNil)
			So(cmc, ShouldBeNil)
		})

		Convey("one can send private message to multiple person", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id, recepient2.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)

		})

		Convey("targetted account should be able to list private message channel of himself", nil)

	})
}

func sendPrivateMessage(senderId int64, body string, recepients []int64, groupName string) (*models.ChannelContainer, error) {

	pmr := models.PrivateMessageRequest{}
	pmr.AccountId = senderId
	pmr.Body = body
	pmr.Recepients = recepients
	pmr.GroupName = groupName

	url := "/privatemessage/send"
	res, err := marshallAndSendRequest("POST", url, pmr)
	if err != nil {
		return nil, err
	}

	model := models.NewChannelContainer()
	err = json.Unmarshal(res, model)
	if err != nil {
		return nil, err
	}

	return model, nil
}

// func getHistory(channelId, accountId int64) (*models.HistoryResponse, error) {
// 	url := fmt.Sprintf("/channel/%d/history?accountId=%d", channelId, accountId)
// 	res, err := sendRequest("GET", url, nil)
// 	if err != nil {
// 		return nil, err
// 	}

// 	var history models.HistoryResponse
// 	err = json.Unmarshal(res, &history)
// 	if err != nil {
// 		return nil, err
// 	}

// 	return &history, nil
// }
<commit_msg>Social: add private message testing for creating and listing<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"socialapi/models"
	"strconv"
	"testing"
	. "github.com/smartystreets/goconvey/convey"
)

func TestPrivateMesssage(t *testing.T) {
	Convey("while testing private messages", t, func() {
		account := models.NewAccount()
		account.OldId = AccountOldId.Hex()
		account, err := createAccount(account)
		So(err, ShouldBeNil)
		So(account, ShouldNotBeNil)

		recepient := models.NewAccount()
		recepient.OldId = AccountOldId2.Hex()
		recepient, err = createAccount(recepient)
		So(err, ShouldBeNil)
		So(recepient, ShouldNotBeNil)

		recepient2 := models.NewAccount()
		recepient2.OldId = AccountOldId3.Hex()
		recepient2, err = createAccount(recepient2)
		So(err, ShouldBeNil)
		So(recepient2, ShouldNotBeNil)

		groupName := "testgroup" + strconv.FormatInt(rand.Int63(), 10)

		Convey("one can send private message to one person", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)

		})

		Convey("0 recipient should fail", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{},
				groupName,
			)
			So(err, ShouldNotBeNil)
			So(cmc, ShouldBeNil)

		})
		Convey("if body is nil, should fail to create PM", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"",
				[]int64{recepient.Id},
				groupName,
			)
			So(err, ShouldNotBeNil)
			So(cmc, ShouldBeNil)
		})
		Convey("if group name is nil, should not fail to create PM", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id},
				"",
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)
		})

		Convey("if sender is not defined should fail to create PM", func() {
			cmc, err := sendPrivateMessage(
				0,
				"this is a body for private message",
				[]int64{recepient.Id},
				"",
			)
			So(err, ShouldNotBeNil)
			So(cmc, ShouldBeNil)
		})

		Convey("one can send private message to multiple person", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id, recepient2.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)

		})
		Convey("private message response should have created channel", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id, recepient2.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)
			So(cmc.Channel.TypeConstant, ShouldEqual, models.Channel_TYPE_PRIVATE_MESSAGE)
			So(cmc.Channel.Id, ShouldBeGreaterThan, 0)
			So(cmc.Channel.GroupName, ShouldEqual, groupName)
			So(cmc.Channel.PrivacyConstant, ShouldEqual, models.Channel_PRIVACY_PRIVATE)

		})

		Convey("private message response should have participant status data", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id, recepient2.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)
			So(cmc.IsParticipant, ShouldBeTrue)
		})

		Convey("private message response should have participant count", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id, recepient2.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)
			So(cmc.ParticipantCount, ShouldEqual, 3)
		})

		Convey("private message response should have participant preview", func() {
			cmc, err := sendPrivateMessage(
				account.Id,
				"this is a body for private message",
				[]int64{recepient.Id, recepient2.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)
			So(len(cmc.ParticipantsPreview), ShouldEqual, 3)
		})

		Convey("private message response should have last Message", func() {
			body := "this is a body for private message"
			cmc, err := sendPrivateMessage(
				account.Id,
				body,
				[]int64{recepient.Id, recepient2.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)
			So(cmc.LastMessage.Body, ShouldEqual, body)
		})

		Convey("private message should be listed by all recipients", func() {
			// use a different group name
			// in order not to interfere with another request
			groupName := "testgroup" + strconv.FormatInt(rand.Int63(), 10)

			body := "this is a body for private message"
			cmc, err := sendPrivateMessage(
				account.Id,
				body,
				[]int64{recepient.Id, recepient2.Id},
				groupName,
			)
			So(err, ShouldBeNil)
			So(cmc, ShouldNotBeNil)

			pm, err := getPrivateMessages(account.Id, groupName)
			So(err, ShouldBeNil)
			So(pm, ShouldNotBeNil)
			So(pm[0], ShouldNotBeNil)
			So(pm[0].Channel.TypeConstant, ShouldEqual, models.Channel_TYPE_PRIVATE_MESSAGE)
			So(pm[0].Channel.Id, ShouldEqual, cmc.Channel.Id)
			So(pm[0].Channel.GroupName, ShouldEqual, cmc.Channel.GroupName)
			So(pm[0].LastMessage.Body, ShouldEqual, cmc.LastMessage.Body)
			So(pm[0].Channel.PrivacyConstant, ShouldEqual, models.Channel_PRIVACY_PRIVATE)
			So(len(pm[0].ParticipantsPreview), ShouldEqual, 3)
			So(pm[0].IsParticipant, ShouldBeTrue)

		})

		Convey("targetted account should be able to list private message channel of himself", nil)

	})
}

func sendPrivateMessage(senderId int64, body string, recepients []int64, groupName string) (*models.ChannelContainer, error) {

	pmr := models.PrivateMessageRequest{}
	pmr.AccountId = senderId
	pmr.Body = body
	pmr.Recepients = recepients
	pmr.GroupName = groupName

	url := "/privatemessage/send"
	res, err := marshallAndSendRequest("POST", url, pmr)
	if err != nil {
		return nil, err
	}

	model := models.NewChannelContainer()
	err = json.Unmarshal(res, model)
	if err != nil {
		return nil, err
	}

	return model, nil
}

func getPrivateMessages(accountId int64, groupName string) ([]models.ChannelContainer, error) {
	url := fmt.Sprintf("/privatemessage/list?accountId=%d&groupName=%s", accountId, groupName)
	res, err := sendRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	var privateMessages []models.ChannelContainer
	err = json.Unmarshal(res, &privateMessages)
	if err != nil {
		return nil, err
	}

	return privateMessages, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"koding/db/mongodb/modelhelper"
	"socialapi/workers/common/runner"
	"socialapi/workers/emailnotifier/controller"
	"socialapi/workers/emailnotifier/models"
	"socialapi/workers/helper"
)

var (
	Name = "EmailNotifier"
)

func main() {
	r := runner.New(Name)
	if err := r.Init(); err != nil {
		fmt.Println(err)
		return
	}

	// init mongo connection
	modelhelper.Initialize(r.Conf.Mongo)

	// init redis connection
	redisConn := helper.MustInitRedisConn(r.Conf.Redis)
	defer redisConn.Close()

	//create connection to RMQ for publishing realtime events
	rmq := helper.NewRabbitMQ(r.Conf, r.Log)

	es := &models.EmailSettings{
		Username:        r.Conf.SendGrid.Username,
		Password:        r.Conf.SendGrid.Password,
		FromMail:        r.Conf.SendGrid.FromMail,
		FromName:        r.Conf.SendGrid.FromName,
		ForcedRecipient: r.Conf.SendGrid.ForcedRecipient,
	}

	handler, err := emailnotifier.New(
		rmq,
		r.Log,
		es,
	)
	if err != nil {
		panic(err)
	}

	r.Listen(handler)
	r.Close()
}
<commit_msg>Notification: emailnotifier is replaced by controller<commit_after>package main

import (
	"fmt"
	"koding/db/mongodb/modelhelper"
	"socialapi/workers/common/runner"
	"socialapi/workers/emailnotifier/controller"
	"socialapi/workers/emailnotifier/models"
	"socialapi/workers/helper"
)

var (
	Name = "EmailNotifier"
)

func main() {
	r := runner.New(Name)
	if err := r.Init(); err != nil {
		fmt.Println(err)
		return
	}

	// init mongo connection
	modelhelper.Initialize(r.Conf.Mongo)

	// init redis connection
	redisConn := helper.MustInitRedisConn(r.Conf.Redis)
	defer redisConn.Close()

	//create connection to RMQ for publishing realtime events
	rmq := helper.NewRabbitMQ(r.Conf, r.Log)

	es := &models.EmailSettings{
		Username:        r.Conf.SendGrid.Username,
		Password:        r.Conf.SendGrid.Password,
		FromMail:        r.Conf.SendGrid.FromMail,
		FromName:        r.Conf.SendGrid.FromName,
		ForcedRecipient: r.Conf.SendGrid.ForcedRecipient,
	}

	handler, err := controller.New(
		rmq,
		r.Log,
		es,
	)
	if err != nil {
		panic(err)
	}

	r.Listen(handler)
	r.Close()
}
<|endoftext|>


<commit_before>package cuckoofilter

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"testing"

	"github.com/seiflotfy/counts/config"
	"github.com/seiflotfy/counts/counters/abstract"
	"github.com/seiflotfy/counts/utils"
)

func setupTests() {
	os.Setenv("COUNTS_DATA_DIR", "/tmp/count_data")
	os.Setenv("COUNTS_INFO_DIR", "/tmp/count_info")
	path, err := os.Getwd()
	utils.PanicOnError(err)
	path = filepath.Dir(path)
	configPath := filepath.Join(path, "../../../config/default.toml")
	os.Setenv("COUNTS_CONFIG", configPath)
	tearDownTests()
}

func tearDownTests() {
	os.RemoveAll(config.GetConfig().GetDataDir())
	os.RemoveAll(config.GetConfig().GetInfoDir())
	os.Mkdir(config.GetConfig().GetDataDir(), 0777)
	os.Mkdir(config.GetConfig().GetInfoDir(), 0777)
}

func TestInsertion(t *testing.T) {
	setupTests()
	defer tearDownTests()

	cf := NewCuckooFilter(&abstract.Info{ID: "ultimates",
		Type:     abstract.Purgable,
		Capacity: 1000000, State: make(map[string]uint64)})

	fd, err := os.Open("/usr/share/dict/web2")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	scanner := bufio.NewScanner(fd)

	var values [][]byte
	for scanner.Scan() {
		s := []byte(scanner.Text())
		cf.InsertUnique(s)
		values = append(values, s)
	}

	count := cf.GetCount()
	if count != 235081 {
		t.Errorf("Expected count = 235081, instead count = %d", count)
	}

	for _, v := range values {
		cf.Delete(v)
	}

	count = cf.GetCount()
	if count != 0 {
		t.Errorf("Expected count = 0, instead count == %d", count)
	}
}
<commit_msg>Update cuckoofilter implementation to use the right domainType enum<commit_after>package cuckoofilter

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"testing"

	"github.com/seiflotfy/counts/config"
	"github.com/seiflotfy/counts/counters/abstract"
	"github.com/seiflotfy/counts/utils"
)

func setupTests() {
	os.Setenv("COUNTS_DATA_DIR", "/tmp/count_data")
	os.Setenv("COUNTS_INFO_DIR", "/tmp/count_info")
	path, err := os.Getwd()
	utils.PanicOnError(err)
	path = filepath.Dir(path)
	configPath := filepath.Join(path, "../../../config/default.toml")
	os.Setenv("COUNTS_CONFIG", configPath)
	tearDownTests()
}

func tearDownTests() {
	os.RemoveAll(config.GetConfig().GetDataDir())
	os.RemoveAll(config.GetConfig().GetInfoDir())
	os.Mkdir(config.GetConfig().GetDataDir(), 0777)
	os.Mkdir(config.GetConfig().GetInfoDir(), 0777)
}

func TestInsertion(t *testing.T) {
	setupTests()
	defer tearDownTests()

	cf := NewCuckooFilter(&abstract.Info{ID: "ultimates",
		Type:     abstract.PurgableCardinality,
		Capacity: 1000000, State: make(map[string]uint64)})

	fd, err := os.Open("/usr/share/dict/web2")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	scanner := bufio.NewScanner(fd)

	var values [][]byte
	for scanner.Scan() {
		s := []byte(scanner.Text())
		cf.InsertUnique(s)
		values = append(values, s)
	}

	count := cf.GetCount()
	if count != 235081 {
		t.Errorf("Expected count = 235081, instead count = %d", count)
	}

	for _, v := range values {
		cf.Delete(v)
	}

	count = cf.GetCount()
	if count != 0 {
		t.Errorf("Expected count = 0, instead count == %d", count)
	}
}
<|endoftext|>