<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ir

import (
	"go/constant"
	"math"

	"cmd/compile/internal/base"
	"cmd/compile/internal/types"
)

func ConstType(n Node) constant.Kind {
	if n == nil || n.Op() != OLITERAL {
		return constant.Unknown
	}
	return n.Val().Kind()
}

// ConstValue returns the constant value stored in n as an interface{}.
// It returns int64s for ints and runes, float64s for floats,
// and complex128s for complex values.
func ConstValue(n Node) interface{} {
	switch v := n.Val(); v.Kind() {
	default:
		base.Fatalf("unexpected constant: %v", v)
		panic("unreachable")
	case constant.Bool:
		return constant.BoolVal(v)
	case constant.String:
		return constant.StringVal(v)
	case constant.Int:
		return IntVal(n.Type(), v)
	case constant.Float:
		return Float64Val(v)
	case constant.Complex:
		return complex(Float64Val(constant.Real(v)), Float64Val(constant.Imag(v)))
	}
}

// IntVal returns v converted to int64.
// Note: if t is uint64, very large values will be converted to negative int64.
func IntVal(t *types.Type, v constant.Value) int64 {
	if t.IsUnsigned() {
		if x, ok := constant.Uint64Val(v); ok {
			return int64(x)
		}
	} else {
		if x, ok := constant.Int64Val(v); ok {
			return x
		}
	}
	base.Fatalf("%v out of range for %v", v, t)
	panic("unreachable")
}

func Float64Val(v constant.Value) float64 {
	if x, _ := constant.Float64Val(v); !math.IsInf(x, 0) {
		return x + 0 // avoid -0 (should not be needed, but be conservative)
	}
	base.Fatalf("bad float64 value: %v", v)
	panic("unreachable")
}

func AssertValidTypeForConst(t *types.Type, v constant.Value) {
	if !ValidTypeForConst(t, v) {
		base.Fatalf("%v (%v) does not represent %v (%v)", t, t.Kind(), v, v.Kind())
	}
}

func ValidTypeForConst(t *types.Type, v constant.Value) bool {
	switch v.Kind() {
	case constant.Unknown:
		return OKForConst[t.Kind()]
	case constant.Bool:
		return t.IsBoolean()
	case constant.String:
		return t.IsString()
	case constant.Int:
		return t.IsInteger()
	case constant.Float:
		return t.IsFloat()
	case constant.Complex:
		return t.IsComplex()
	}

	base.Fatalf("unexpected constant kind: %v", v)
	panic("unreachable")
}

// NewLiteral returns a new untyped constant with value v.
func NewLiteral(v constant.Value) Node {
	return NewBasicLit(base.Pos, v)
}

func idealType(ct constant.Kind) *types.Type {
	switch ct {
	case constant.String:
		return types.UntypedString
	case constant.Bool:
		return types.UntypedBool
	case constant.Int:
		return types.UntypedInt
	case constant.Float:
		return types.UntypedFloat
	case constant.Complex:
		return types.UntypedComplex
	}
	base.Fatalf("unexpected Ctype: %v", ct)
	return nil
}

var OKForConst [types.NTYPE]bool

// CanInt64 reports whether it is safe to call Int64Val() on n.
func CanInt64(n Node) bool {
	if !IsConst(n, constant.Int) {
		return false
	}

	// if the value inside n cannot be represented as an int64, the
	// return value of Int64 is undefined
	_, ok := constant.Int64Val(n.Val())
	return ok
}

// Int64Val returns n as an int64.
// n must be an integer or rune constant.
func Int64Val(n Node) int64 {
	if !IsConst(n, constant.Int) {
		base.Fatalf("Int64Val(%v)", n)
	}
	x, ok := constant.Int64Val(n.Val())
	if !ok {
		base.Fatalf("Int64Val(%v)", n)
	}
	return x
}

// Uint64Val returns n as an uint64.
// n must be an integer or rune constant.
func Uint64Val(n Node) uint64 {
	if !IsConst(n, constant.Int) {
		base.Fatalf("Uint64Val(%v)", n)
	}
	x, ok := constant.Uint64Val(n.Val())
	if !ok {
		base.Fatalf("Uint64Val(%v)", n)
	}
	return x
}

// BoolVal returns n as a bool.
// n must be a boolean constant.
func BoolVal(n Node) bool {
	if !IsConst(n, constant.Bool) {
		base.Fatalf("BoolVal(%v)", n)
	}
	return constant.BoolVal(n.Val())
}

// StringVal returns the value of a literal string Node as a string.
// n must be a string constant.
func StringVal(n Node) string {
	if !IsConst(n, constant.String) {
		base.Fatalf("StringVal(%v)", n)
	}
	return constant.StringVal(n.Val())
}
<commit_msg>cmd/compile/internal/ir: remove un-used code for const<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ir

import (
	"go/constant"

	"cmd/compile/internal/base"
	"cmd/compile/internal/types"
)

func ConstType(n Node) constant.Kind {
	if n == nil || n.Op() != OLITERAL {
		return constant.Unknown
	}
	return n.Val().Kind()
}

// IntVal returns v converted to int64.
// Note: if t is uint64, very large values will be converted to negative int64.
func IntVal(t *types.Type, v constant.Value) int64 {
	if t.IsUnsigned() {
		if x, ok := constant.Uint64Val(v); ok {
			return int64(x)
		}
	} else {
		if x, ok := constant.Int64Val(v); ok {
			return x
		}
	}
	base.Fatalf("%v out of range for %v", v, t)
	panic("unreachable")
}

func AssertValidTypeForConst(t *types.Type, v constant.Value) {
	if !ValidTypeForConst(t, v) {
		base.Fatalf("%v (%v) does not represent %v (%v)", t, t.Kind(), v, v.Kind())
	}
}

func ValidTypeForConst(t *types.Type, v constant.Value) bool {
	switch v.Kind() {
	case constant.Unknown:
		return OKForConst[t.Kind()]
	case constant.Bool:
		return t.IsBoolean()
	case constant.String:
		return t.IsString()
	case constant.Int:
		return t.IsInteger()
	case constant.Float:
		return t.IsFloat()
	case constant.Complex:
		return t.IsComplex()
	}

	base.Fatalf("unexpected constant kind: %v", v)
	panic("unreachable")
}

// NewLiteral returns a new untyped constant with value v.
func NewLiteral(v constant.Value) Node {
	return NewBasicLit(base.Pos, v)
}

func idealType(ct constant.Kind) *types.Type {
	switch ct {
	case constant.String:
		return types.UntypedString
	case constant.Bool:
		return types.UntypedBool
	case constant.Int:
		return types.UntypedInt
	case constant.Float:
		return types.UntypedFloat
	case constant.Complex:
		return types.UntypedComplex
	}
	base.Fatalf("unexpected Ctype: %v", ct)
	return nil
}

var OKForConst [types.NTYPE]bool

// Int64Val returns n as an int64.
// n must be an integer or rune constant.
func Int64Val(n Node) int64 {
	if !IsConst(n, constant.Int) {
		base.Fatalf("Int64Val(%v)", n)
	}
	x, ok := constant.Int64Val(n.Val())
	if !ok {
		base.Fatalf("Int64Val(%v)", n)
	}
	return x
}

// Uint64Val returns n as an uint64.
// n must be an integer or rune constant.
func Uint64Val(n Node) uint64 {
	if !IsConst(n, constant.Int) {
		base.Fatalf("Uint64Val(%v)", n)
	}
	x, ok := constant.Uint64Val(n.Val())
	if !ok {
		base.Fatalf("Uint64Val(%v)", n)
	}
	return x
}

// BoolVal returns n as a bool.
// n must be a boolean constant.
func BoolVal(n Node) bool {
	if !IsConst(n, constant.Bool) {
		base.Fatalf("BoolVal(%v)", n)
	}
	return constant.BoolVal(n.Val())
}

// StringVal returns the value of a literal string Node as a string.
// n must be a string constant.
func StringVal(n Node) string {
	if !IsConst(n, constant.String) {
		base.Fatalf("StringVal(%v)", n)
	}
	return constant.StringVal(n.Val())
}
<|endoftext|>


<commit_before>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vet

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"cmd/go/internal/base"
	"cmd/go/internal/cmdflag"
	"cmd/go/internal/work"
)

const cmd = "vet"

// vetFlagDefn is the set of flags we process.
var vetFlagDefn = []*cmdflag.Defn{
	// Note: Some flags, in particular -tags and -v, are known to
	// vet but also defined as build flags. This works fine, so we
	// don't define them here but use AddBuildFlags to init them.
	// However some, like -x, are known to the build but not
	// to vet. We handle them in vetFlags.

	// local.
	{Name: "all", BoolVar: new(bool)},
	{Name: "asmdecl", BoolVar: new(bool)},
	{Name: "assign", BoolVar: new(bool)},
	{Name: "atomic", BoolVar: new(bool)},
	{Name: "bool", BoolVar: new(bool)},
	{Name: "buildtags", BoolVar: new(bool)},
	{Name: "cgocall", BoolVar: new(bool)},
	{Name: "composites", BoolVar: new(bool)},
	{Name: "copylocks", BoolVar: new(bool)},
	{Name: "httpresponse", BoolVar: new(bool)},
	{Name: "lostcancel", BoolVar: new(bool)},
	{Name: "methods", BoolVar: new(bool)},
	{Name: "nilfunc", BoolVar: new(bool)},
	{Name: "printf", BoolVar: new(bool)},
	{Name: "printfuncs"},
	{Name: "rangeloops", BoolVar: new(bool)},
	{Name: "shadow", BoolVar: new(bool)},
	{Name: "shadowstrict", BoolVar: new(bool)},
	{Name: "source", BoolVar: new(bool)},
	{Name: "structtags", BoolVar: new(bool)},
	{Name: "tests", BoolVar: new(bool)},
	{Name: "unreachable", BoolVar: new(bool)},
	{Name: "unsafeptr", BoolVar: new(bool)},
	{Name: "unusedfuncs"},
	{Name: "unusedresult", BoolVar: new(bool)},
	{Name: "unusedstringmethods"},
}

// add build flags to vetFlagDefn.
func init() {
	var cmd base.Command
	work.AddBuildFlags(&cmd)
	cmd.Flag.VisitAll(func(f *flag.Flag) {
		vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{
			Name:  f.Name,
			Value: f.Value,
		})
	})
}

// vetFlags processes the command line, splitting it at the first non-flag
// into the list of flags and list of packages.
func vetFlags(args []string) (passToVet, packageNames []string) {
	for i := 0; i < len(args); i++ {
		if !strings.HasPrefix(args[i], "-") {
			return args[:i], args[i:]
		}

		f, value, extraWord := cmdflag.Parse(cmd, vetFlagDefn, args, i)
		if f == nil {
			fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i])
			fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n")
			os.Exit(2)
		}
		if f.Value != nil {
			if err := f.Value.Set(value); err != nil {
				base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
			}
			switch f.Name {
			// Flags known to the build but not to vet, so must be dropped.
			case "x", "n":
				args = append(args[:i], args[i+1:]...)
				i--
			}
		}
		if extraWord {
			i++
		}
	}
	return args, nil
}
<commit_msg>cmd/go: add -shift to go vet's flag whitelist<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vet

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"cmd/go/internal/base"
	"cmd/go/internal/cmdflag"
	"cmd/go/internal/work"
)

const cmd = "vet"

// vetFlagDefn is the set of flags we process.
var vetFlagDefn = []*cmdflag.Defn{
	// Note: Some flags, in particular -tags and -v, are known to
	// vet but also defined as build flags. This works fine, so we
	// don't define them here but use AddBuildFlags to init them.
	// However some, like -x, are known to the build but not
	// to vet. We handle them in vetFlags.

	// local.
	{Name: "all", BoolVar: new(bool)},
	{Name: "asmdecl", BoolVar: new(bool)},
	{Name: "assign", BoolVar: new(bool)},
	{Name: "atomic", BoolVar: new(bool)},
	{Name: "bool", BoolVar: new(bool)},
	{Name: "buildtags", BoolVar: new(bool)},
	{Name: "cgocall", BoolVar: new(bool)},
	{Name: "composites", BoolVar: new(bool)},
	{Name: "copylocks", BoolVar: new(bool)},
	{Name: "httpresponse", BoolVar: new(bool)},
	{Name: "lostcancel", BoolVar: new(bool)},
	{Name: "methods", BoolVar: new(bool)},
	{Name: "nilfunc", BoolVar: new(bool)},
	{Name: "printf", BoolVar: new(bool)},
	{Name: "printfuncs"},
	{Name: "rangeloops", BoolVar: new(bool)},
	{Name: "shadow", BoolVar: new(bool)},
	{Name: "shadowstrict", BoolVar: new(bool)},
	{Name: "shift", BoolVar: new(bool)},
	{Name: "source", BoolVar: new(bool)},
	{Name: "structtags", BoolVar: new(bool)},
	{Name: "tests", BoolVar: new(bool)},
	{Name: "unreachable", BoolVar: new(bool)},
	{Name: "unsafeptr", BoolVar: new(bool)},
	{Name: "unusedfuncs"},
	{Name: "unusedresult", BoolVar: new(bool)},
	{Name: "unusedstringmethods"},
}

// add build flags to vetFlagDefn.
func init() {
	var cmd base.Command
	work.AddBuildFlags(&cmd)
	cmd.Flag.VisitAll(func(f *flag.Flag) {
		vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{
			Name:  f.Name,
			Value: f.Value,
		})
	})
}

// vetFlags processes the command line, splitting it at the first non-flag
// into the list of flags and list of packages.
func vetFlags(args []string) (passToVet, packageNames []string) {
	for i := 0; i < len(args); i++ {
		if !strings.HasPrefix(args[i], "-") {
			return args[:i], args[i:]
		}

		f, value, extraWord := cmdflag.Parse(cmd, vetFlagDefn, args, i)
		if f == nil {
			fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i])
			fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n")
			os.Exit(2)
		}
		if f.Value != nil {
			if err := f.Value.Set(value); err != nil {
				base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
			}
			switch f.Name {
			// Flags known to the build but not to vet, so must be dropped.
			case "x", "n":
				args = append(args[:i], args[i+1:]...)
				i--
			}
		}
		if extraWord {
			i++
		}
	}
	return args, nil
}
<|endoftext|>


<commit_before>/*
Copyright YEAR 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 v1alpha1

import (
	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: "clusterregistry.k8s.io", Version: "v1alpha1"}

// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
	return SchemeGroupVersion.WithKind(kind).GroupKind()
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
	return SchemeGroupVersion.WithResource(resource).GroupResource()
}

var (
	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
	AddToScheme   = SchemeBuilder.AddToScheme
)

// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(SchemeGroupVersion,
		&Cluster{},
		&ClusterList{},
	)
	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
	return nil
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type ClusterList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []Cluster `json:"items"`
}

// CRD Generation
func getFloat(f float64) *float64 {
	return &f
}

func getInt(i int64) *int64 {
	return &i
}

var (
	// Define CRDs for resources
	ClusterCRD = v1beta1.CustomResourceDefinition{
		ObjectMeta: metav1.ObjectMeta{
			Name: "clusters.clusterregistry.k8s.io",
		},
		Spec: v1beta1.CustomResourceDefinitionSpec{
			Group:   "clusterregistry.k8s.io",
			Version: "v1alpha1",
			Names: v1beta1.CustomResourceDefinitionNames{
				Kind:   "Cluster",
				Plural: "clusters",
			},
			Scope: "Namespaced",
			Validation: &v1beta1.CustomResourceValidation{
				OpenAPIV3Schema: &v1beta1.JSONSchemaProps{
					Type: "object",
					Properties: map[string]v1beta1.JSONSchemaProps{
						"apiVersion": v1beta1.JSONSchemaProps{
							Type: "string",
						},
						"kind": v1beta1.JSONSchemaProps{
							Type: "string",
						},
						"metadata": v1beta1.JSONSchemaProps{
							Type: "object",
						},
						"spec": v1beta1.JSONSchemaProps{
							Type: "object",
							Properties: map[string]v1beta1.JSONSchemaProps{
								"authInfo": v1beta1.JSONSchemaProps{
									Type: "object",
									Properties: map[string]v1beta1.JSONSchemaProps{
										"controller": v1beta1.JSONSchemaProps{
											Type: "object",
											Properties: map[string]v1beta1.JSONSchemaProps{
												"kind": v1beta1.JSONSchemaProps{
													Type: "string",
												},
												"name": v1beta1.JSONSchemaProps{
													Type: "string",
												},
												"namespace": v1beta1.JSONSchemaProps{
													Type: "string",
												},
											},
										},
										"user": v1beta1.JSONSchemaProps{
											Type: "object",
											Properties: map[string]v1beta1.JSONSchemaProps{
												"kind": v1beta1.JSONSchemaProps{
													Type: "string",
												},
												"name": v1beta1.JSONSchemaProps{
													Type: "string",
												},
												"namespace": v1beta1.JSONSchemaProps{
													Type: "string",
												},
											},
										},
									},
								},
								"kubernetesApiEndpoints": v1beta1.JSONSchemaProps{
									Type: "object",
									Properties: map[string]v1beta1.JSONSchemaProps{
										"caBundle": v1beta1.JSONSchemaProps{
											Type:   "string",
											Format: "byte",
										},
										"serverEndpoints": v1beta1.JSONSchemaProps{
											Type: "array",
											Items: &v1beta1.JSONSchemaPropsOrArray{
												Schema: &v1beta1.JSONSchemaProps{
													Type: "object",
													Properties: map[string]v1beta1.JSONSchemaProps{
														"clientCIDR": v1beta1.JSONSchemaProps{
															Type: "string",
														},
														"serverAddress": v1beta1.JSONSchemaProps{
															Type: "string",
														},
													},
												},
											},
										},
									},
								},
							},
						},
						"status": v1beta1.JSONSchemaProps{
							Type: "object",
							Properties: map[string]v1beta1.JSONSchemaProps{
								"conditions": v1beta1.JSONSchemaProps{
									Type: "array",
									Items: &v1beta1.JSONSchemaPropsOrArray{
										Schema: &v1beta1.JSONSchemaProps{
											Type: "object",
											Properties: map[string]v1beta1.JSONSchemaProps{
												"lastHeartbeatTime": v1beta1.JSONSchemaProps{
													Type:   "string",
													Format: "date-time",
												},
												"lastTransitionTime": v1beta1.JSONSchemaProps{
													Type:   "string",
													Format: "date-time",
												},
												"message": v1beta1.JSONSchemaProps{
													Type: "string",
												},
												"reason": v1beta1.JSONSchemaProps{
													Type: "string",
												},
												"status": v1beta1.JSONSchemaProps{
													Type: "string",
												},
												"type": v1beta1.JSONSchemaProps{
													Type: "string",
												},
											},
											Required: []string{
												"type",
												"status",
											}},
									},
								},
							},
						},
					},
					Required: []string{
						"status",
					}},
			},
		},
	}
)
<commit_msg>Updated format.<commit_after>/*
Copyright YEAR 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 v1alpha1

import (
	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: "clusterregistry.k8s.io", Version: "v1alpha1"}

// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
	return SchemeGroupVersion.WithKind(kind).GroupKind()
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
	return SchemeGroupVersion.WithResource(resource).GroupResource()
}

var (
	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
	AddToScheme   = SchemeBuilder.AddToScheme
)

// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(SchemeGroupVersion,
		&Cluster{},
		&ClusterList{},
	)
	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
	return nil
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type ClusterList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []Cluster `json:"items"`
}

// CRD Generation
func getFloat(f float64) *float64 {
	return &f
}

func getInt(i int64) *int64 {
	return &i
}

var (
	// Define CRDs for resources
	ClusterCRD = v1beta1.CustomResourceDefinition{
		ObjectMeta: metav1.ObjectMeta{
			Name: "clusters.clusterregistry.k8s.io",
		},
		Spec: v1beta1.CustomResourceDefinitionSpec{
			Group:   "clusterregistry.k8s.io",
			Version: "v1alpha1",
			Names: v1beta1.CustomResourceDefinitionNames{
				Kind:   "Cluster",
				Plural: "clusters",
			},
			Scope: "Namespaced",
			Validation: &v1beta1.CustomResourceValidation{
				OpenAPIV3Schema: &v1beta1.JSONSchemaProps{
					Type: "object",
					Properties: map[string]v1beta1.JSONSchemaProps{
						"apiVersion": {
							Type: "string",
						},
						"kind": {
							Type: "string",
						},
						"metadata": {
							Type: "object",
						},
						"spec": {
							Type: "object",
							Properties: map[string]v1beta1.JSONSchemaProps{
								"authInfo": {
									Type: "object",
									Properties: map[string]v1beta1.JSONSchemaProps{
										"controller": {
											Type: "object",
											Properties: map[string]v1beta1.JSONSchemaProps{
												"kind": {
													Type: "string",
												},
												"name": {
													Type: "string",
												},
												"namespace": {
													Type: "string",
												},
											},
										},
										"user": {
											Type: "object",
											Properties: map[string]v1beta1.JSONSchemaProps{
												"kind": {
													Type: "string",
												},
												"name": {
													Type: "string",
												},
												"namespace": {
													Type: "string",
												},
											},
										},
									},
								},
								"kubernetesApiEndpoints": {
									Type: "object",
									Properties: map[string]v1beta1.JSONSchemaProps{
										"caBundle": {
											Type:   "string",
											Format: "byte",
										},
										"serverEndpoints": {
											Type: "array",
											Items: &v1beta1.JSONSchemaPropsOrArray{
												Schema: &v1beta1.JSONSchemaProps{
													Type: "object",
													Properties: map[string]v1beta1.JSONSchemaProps{
														"clientCIDR": {
															Type: "string",
														},
														"serverAddress": {
															Type: "string",
														},
													},
												},
											},
										},
									},
								},
							},
						},
						"status": {
							Type: "object",
							Properties: map[string]v1beta1.JSONSchemaProps{
								"conditions": {
									Type: "array",
									Items: &v1beta1.JSONSchemaPropsOrArray{
										Schema: &v1beta1.JSONSchemaProps{
											Type: "object",
											Properties: map[string]v1beta1.JSONSchemaProps{
												"lastHeartbeatTime": {
													Type:   "string",
													Format: "date-time",
												},
												"lastTransitionTime": {
													Type:   "string",
													Format: "date-time",
												},
												"message": {
													Type: "string",
												},
												"reason": {
													Type: "string",
												},
												"status": {
													Type: "string",
												},
												"type": {
													Type: "string",
												},
											},
											Required: []string{
												"type",
												"status",
											}},
									},
								},
							},
						},
					},
					Required: []string{
						"status",
					}},
			},
		},
	}
)
<|endoftext|>


<commit_before>package notifications

import (
	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	pubsub "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/tuxychandru/pubsub"

	blocks "github.com/jbenet/go-ipfs/blocks"
	u "github.com/jbenet/go-ipfs/util"
)

const bufferSize = 16

type PubSub interface {
	Publish(block blocks.Block)
	Subscribe(ctx context.Context, k u.Key) <-chan blocks.Block
	Shutdown()
}

func New() PubSub {
	return &impl{*pubsub.New(bufferSize)}
}

type impl struct {
	wrapped pubsub.PubSub
}

func (ps *impl) Publish(block blocks.Block) {
	topic := string(block.Key())
	ps.wrapped.Pub(block, topic)
}

// Subscribe returns a one-time use |blockChannel|. |blockChannel| returns nil
// if the |ctx| times out or is cancelled. Then channel is closed after the
// block given by |k| is sent.
func (ps *impl) Subscribe(ctx context.Context, k u.Key) <-chan blocks.Block {
	topic := string(k)
	subChan := ps.wrapped.SubOnce(topic)
	blockChannel := make(chan blocks.Block, 1) // buffered so the sender doesn't wait on receiver
	go func() {
		defer close(blockChannel)
		select {
		case val := <-subChan:
			block, ok := val.(blocks.Block)
			if ok {
				blockChannel <- block
			}
		case <-ctx.Done():
			ps.wrapped.Unsub(subChan, topic)
		}
	}()
	return blockChannel
}

func (ps *impl) Shutdown() {
	ps.wrapped.Shutdown()
}
<commit_msg>feat(bitswap/notifications) Subscribe to multiple keys<commit_after>package notifications

import (
	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	pubsub "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/tuxychandru/pubsub"

	blocks "github.com/jbenet/go-ipfs/blocks"
	u "github.com/jbenet/go-ipfs/util"
)

const bufferSize = 16

type PubSub interface {
	Publish(block blocks.Block)
	Subscribe(ctx context.Context, keys ...u.Key) <-chan blocks.Block
	Shutdown()
}

func New() PubSub {
	return &impl{*pubsub.New(bufferSize)}
}

type impl struct {
	wrapped pubsub.PubSub
}

func (ps *impl) Publish(block blocks.Block) {
	topic := string(block.Key())
	ps.wrapped.Pub(block, topic)
}

// Subscribe returns a one-time use |blockChannel|. |blockChannel| returns nil
// if the |ctx| times out or is cancelled. Then channel is closed after the
// blocks given by |keys| are sent.
func (ps *impl) Subscribe(ctx context.Context, keys ...u.Key) <-chan blocks.Block {
	topics := make([]string, 0)
	for _, key := range keys {
		topics = append(topics, string(key))
	}
	subChan := ps.wrapped.SubOnce(topics...)
	blockChannel := make(chan blocks.Block, 1) // buffered so the sender doesn't wait on receiver
	go func() {
		defer close(blockChannel)
		select {
		case val := <-subChan:
			block, ok := val.(blocks.Block)
			if ok {
				blockChannel <- block
			}
		case <-ctx.Done():
			ps.wrapped.Unsub(subChan, topics...)
		}
	}()
	return blockChannel
}

func (ps *impl) Shutdown() {
	ps.wrapped.Shutdown()
}
<|endoftext|>


<commit_before>package artifice

import (
	"log"
	"reflect"
	"time"
)

var (
	triggers []trigger
)

type triggerFunc func(*Artifice) error

type trigger struct {
	name   string
	f      triggerFunc
	ticker *time.Ticker
	daily  bool
	hour   int
}

// Register a trigger to a queue operation.
func registerTrigger(name string, f triggerFunc, ticker *time.Ticker) {
	triggers = append(triggers, trigger{name, f, ticker, false, 0})
}

// Register a daily trigger to a queue operation.
func registerDailyTrigger(name string, f triggerFunc, hour int) {
	ticker := time.NewTicker(getNextTickDuration(hour))
	triggers = append(triggers, trigger{name, f, ticker, true, hour})
}

func (s *Artifice) runTriggers() {
	for {
		cases := make([]reflect.SelectCase, len(triggers))
		for i, ch := range triggers {
			cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch.ticker.C)}
		}
		chosen, _, ok := reflect.Select(cases)
		if ok {
			trigger := triggers[chosen]
			if trigger.daily {
				trigger.ticker.Stop()
				trigger.ticker = time.NewTicker(getNextTickDuration(trigger.hour))
			}
			log.Printf("Running trigger %s\n", trigger.name)
			err := trigger.f(s)
			if err != nil {
				log.Println(err)
			}
		}
	}
}

func getNextTickDuration(hour int) time.Duration {
	now := time.Now()
	nextTick := time.Date(now.Year(), now.Month(), now.Day(), hour, 1, 1, 1, time.UTC)
	if nextTick.Before(now) {
		nextTick = nextTick.Add(24 * time.Hour)
	}
	return nextTick.Sub(time.Now())
}
<commit_msg>Would fail around date change.<commit_after>package artifice

import (
	"log"
	"reflect"
	"time"
)

var (
	triggers []trigger
)

type triggerFunc func(*Artifice) error

type trigger struct {
	name   string
	f      triggerFunc
	ticker *time.Ticker
	daily  bool
	hour   int
}

// Register a trigger to a queue operation.
func registerTrigger(name string, f triggerFunc, ticker *time.Ticker) {
	triggers = append(triggers, trigger{name, f, ticker, false, 0})
}

// Register a daily trigger to a queue operation.
func registerDailyTrigger(name string, f triggerFunc, hour int) {
	ticker := time.NewTicker(getNextTickDuration(hour))
	triggers = append(triggers, trigger{name, f, ticker, true, hour})
}

func (s *Artifice) runTriggers() {
	for {
		cases := make([]reflect.SelectCase, len(triggers))
		for i, ch := range triggers {
			cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch.ticker.C)}
		}
		chosen, _, ok := reflect.Select(cases)
		if ok {
			trigger := triggers[chosen]
			if trigger.daily {
				trigger.ticker.Stop()
				trigger.ticker = time.NewTicker(getNextTickDuration(trigger.hour))
			}
			log.Printf("Running trigger %s\n", trigger.name)
			err := trigger.f(s)
			if err != nil {
				log.Println(err)
			}
		}
	}
}

func getNextTickDuration(hour int) time.Duration {
	now := time.Now()
	nextTick := time.Date(now.UTC().Year(), now.UTC().Month(), now.UTC().Day(), hour, 1, 1, 1, time.UTC)
	if nextTick.Before(now) {
		nextTick = nextTick.Add(24 * time.Hour)
	}
	return nextTick.Sub(time.Now())
}
<|endoftext|>


<commit_before>package certificates

import (
	"context"
	"crypto/x509"
	"fmt"
	"time"

	api "k8s.io/api/core/v1"
	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/runtime"

	"github.com/golang/glog"
	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
	"github.com/jetstack/cert-manager/pkg/issuer"
	"github.com/jetstack/cert-manager/pkg/util"
	"github.com/jetstack/cert-manager/pkg/util/errors"
	"github.com/jetstack/cert-manager/pkg/util/kube"
	"github.com/jetstack/cert-manager/pkg/util/pki"
)

const renewBefore = time.Hour * 24 * 30

const (
	errorIssuerNotFound       = "ErrorIssuerNotFound"
	errorIssuerNotReady       = "ErrorIssuerNotReady"
	errorIssuerInit           = "ErrorIssuerInitialization"
	errorCheckCertificate     = "ErrorCheckCertificate"
	errorGetCertificate       = "ErrorGetCertificate"
	errorPreparingCertificate = "ErrorPrepareCertificate"
	errorIssuingCertificate   = "ErrorIssueCertificate"
	errorRenewingCertificate  = "ErrorRenewCertificate"
	errorSavingCertificate    = "ErrorSaveCertificate"

	reasonPreparingCertificate = "PrepareCertificate"
	reasonIssuingCertificate   = "IssueCertificate"
	reasonRenewingCertificate  = "RenewCertificate"

	successCeritificateIssued  = "CeritifcateIssued"
	successCeritificateRenewed = "CeritifcateRenewed"
	successRenewalScheduled    = "RenewalScheduled"

	messageIssuerNotFound            = "Issuer %s does not exist"
	messageIssuerNotReady            = "Issuer %s not ready"
	messageIssuerErrorInit           = "Error initializing issuer: "
	messageErrorCheckCertificate     = "Error checking existing TLS certificate: "
	messageErrorGetCertificate       = "Error getting TLS certificate: "
	messageErrorPreparingCertificate = "Error preparing issuer for certificate: "
	messageErrorIssuingCertificate   = "Error issuing certificate: "
	messageErrorRenewingCertificate  = "Error renewing certificate: "
	messageErrorSavingCertificate    = "Error saving TLS certificate: "

	messagePreparingCertificate = "Preparing certificate with issuer"
	messageIssuingCertificate   = "Issuing certificate..."
	messageRenewingCertificate  = "Renewing certificate..."

	messageCertificateIssued  = "Certificated issued successfully"
	messageCertificateRenewed = "Certificated renewed successfully"
	messageRenewalScheduled   = "Certificate scheduled for renewal in %d hours"
)

func (c *Controller) Sync(ctx context.Context, crt *v1alpha1.Certificate) (err error) {
	// step zero: check if the referenced issuer exists and is ready
	issuerObj, err := c.getGenericIssuer(crt)

	if err != nil {
		s := fmt.Sprintf(messageIssuerNotFound, err.Error())
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorIssuerNotFound, s)
		return err
	}

	issuerReady := issuerObj.HasCondition(v1alpha1.IssuerCondition{
		Type:   v1alpha1.IssuerConditionReady,
		Status: v1alpha1.ConditionTrue,
	})
	if !issuerReady {
		s := fmt.Sprintf(messageIssuerNotReady, issuerObj.GetObjectMeta().Name)
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorIssuerNotReady, s)
		return fmt.Errorf(s)
	}

	i, err := c.issuerFactory.IssuerFor(issuerObj)
	if err != nil {
		s := messageIssuerErrorInit + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorIssuerInit, s)
		return err
	}

	expectedCN, err := pki.CommonNameForCertificate(crt)
	if err != nil {
		return err
	}
	expectedDNSNames, err := pki.DNSNamesForCertificate(crt)
	if err != nil {
		return err
	}

	// grab existing certificate and validate private key
	cert, err := kube.SecretTLSCert(c.secretLister, crt.Namespace, crt.Spec.SecretName)
	if err != nil {
		s := messageErrorCheckCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorCheckCertificate, s)
	}

	// if an error is returned, and that error is something other than
	// IsNotFound or invalid data, then we should return the error.
	if err != nil && !k8sErrors.IsNotFound(err) && !errors.IsInvalidData(err) {
		return err
	}

	// as there is an existing certificate, or we may create one below, we will
	// run scheduleRenewal to schedule a renewal if required at the end of
	// execution.
	defer c.scheduleRenewal(crt)

	crtCopy := crt.DeepCopy()

	// if the certificate was not found, or the certificate data is invalid, we
	// should issue a new certificate.
	// if the certificate is valid for a list of domains other than those
	// listed in the certificate spec, we should re-issue the certificate.
	if k8sErrors.IsNotFound(err) || errors.IsInvalidData(err) ||
		expectedCN != cert.Subject.CommonName || !util.EqualUnsorted(cert.DNSNames, expectedDNSNames) {
		err := c.issue(ctx, i, crtCopy)
		updateErr := c.updateCertificateStatus(crtCopy)
		if err != nil || updateErr != nil {
			return utilerrors.NewAggregate([]error{err, updateErr})
		}
		return nil
	}

	// calculate the amount of time until expiry
	durationUntilExpiry := cert.NotAfter.Sub(time.Now())
	// calculate how long until we should start attempting to renew the
	// certificate
	renewIn := durationUntilExpiry - renewBefore
	// if we should being attempting to renew now, then trigger a renewal
	if renewIn <= 0 {
		err := c.renew(ctx, i, crtCopy)
		updateErr := c.updateCertificateStatus(crtCopy)
		if err != nil || updateErr != nil {
			return utilerrors.NewAggregate([]error{err, updateErr})
		}
	}

	return nil
}

func (c *Controller) getGenericIssuer(crt *v1alpha1.Certificate) (v1alpha1.GenericIssuer, error) {
	switch crt.Spec.IssuerRef.Kind {
	case "", v1alpha1.IssuerKind:
		return c.issuerLister.Issuers(crt.Namespace).Get(crt.Spec.IssuerRef.Name)
	case v1alpha1.ClusterIssuerKind:
		if c.clusterIssuerLister == nil {
			return nil, fmt.Errorf("cannot get ClusterIssuer for %q as cert-manager is scoped to a single namespace", crt.Name)
		}
		return c.clusterIssuerLister.Get(crt.Spec.IssuerRef.Name)
	default:
		return nil, fmt.Errorf(`invalid value %q for certificate issuer kind. Must be empty, %q or %q`, crt.Spec.IssuerRef.Kind, v1alpha1.IssuerKind, v1alpha1.ClusterIssuerKind)
	}
}

func needsRenew(cert *x509.Certificate) bool {
	durationUntilExpiry := cert.NotAfter.Sub(time.Now())
	renewIn := durationUntilExpiry - renewBefore
	// step three: check if referenced secret is valid (after start & before expiry)
	if renewIn <= 0 {
		return true
	}
	return false
}

func (c *Controller) scheduleRenewal(crt *v1alpha1.Certificate) {
	key, err := keyFunc(crt)

	if err != nil {
		runtime.HandleError(fmt.Errorf("error getting key for certificate resource: %s", err.Error()))
		return
	}

	cert, err := kube.SecretTLSCert(c.secretLister, crt.Namespace, crt.Spec.SecretName)

	if err != nil {
		runtime.HandleError(fmt.Errorf("[%s/%s] Error getting certificate '%s': %s", crt.Namespace, crt.Name, crt.Spec.SecretName, err.Error()))
		return
	}

	durationUntilExpiry := cert.NotAfter.Sub(time.Now())
	renewIn := durationUntilExpiry - renewBefore

	c.scheduledWorkQueue.Add(key, renewIn)

	s := fmt.Sprintf(messageRenewalScheduled, renewIn/time.Hour)
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, successRenewalScheduled, s)
}

// return an error on failure. If retrieval is succesful, the certificate data
// and private key will be stored in the named secret
func (c *Controller) issue(ctx context.Context, issuer issuer.Interface, crt *v1alpha1.Certificate) error {
	var err error
	s := messagePreparingCertificate
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, reasonPreparingCertificate, s)
	if err = issuer.Prepare(ctx, crt); err != nil {
		s := messageErrorPreparingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorPreparingCertificate, s)
		return err
	}

	s = messageIssuingCertificate
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, reasonIssuingCertificate, s)

	var key, cert []byte
	key, cert, err = issuer.Issue(ctx, crt)

	if err != nil {
		s := messageErrorIssuingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorIssuingCertificate, s)
		return err
	}

	_, err = kube.EnsureSecret(c.client, &api.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name:      crt.Spec.SecretName,
			Namespace: crt.Namespace,
		},
		Type: api.SecretTypeTLS,
		Data: map[string][]byte{
			api.TLSCertKey:       cert,
			api.TLSPrivateKeyKey: key,
		},
	})

	if err != nil {
		s := messageErrorSavingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorSavingCertificate, s)
		return err
	}

	s = messageCertificateIssued
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, successCeritificateIssued, s)

	return nil
}

// renew will attempt to renew a certificate from the specified issuer, or
// return an error on failure. If renewal is succesful, the certificate data
// and private key will be stored in the named secret
func (c *Controller) renew(ctx context.Context, issuer issuer.Interface, crt *v1alpha1.Certificate) error {
	var err error
	s := messagePreparingCertificate
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, reasonPreparingCertificate, s)

	if err = issuer.Prepare(ctx, crt); err != nil {
		s := messageErrorPreparingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorPreparingCertificate, s)
		return err
	}

	s = messageRenewingCertificate
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, reasonRenewingCertificate, s)

	var key, cert []byte
	key, cert, err = issuer.Renew(ctx, crt)

	if err != nil {
		s := messageErrorRenewingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorRenewingCertificate, s)
		return err
	}

	_, err = kube.EnsureSecret(c.client, &api.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name:      crt.Spec.SecretName,
			Namespace: crt.Namespace,
		},
		Type: api.SecretTypeTLS,
		Data: map[string][]byte{
			api.TLSCertKey:       cert,
			api.TLSPrivateKeyKey: key,
		},
	})

	if err != nil {
		s := messageErrorSavingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorSavingCertificate, s)
		return err
	}

	s = messageCertificateRenewed
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, successCeritificateRenewed, s)

	return nil
}

func (c *Controller) updateCertificateStatus(crt *v1alpha1.Certificate) error {
	// TODO: replace Update call with UpdateStatus. This requires a custom API
	// server with the /status subresource enabled and/or subresource support
	// for CRDs (https://github.com/kubernetes/kubernetes/issues/38113)
	_, err := c.cmClient.CertmanagerV1alpha1().Certificates(crt.Namespace).Update(crt)
	return err
}
<commit_msg>Update Secrets instead of replacing to preserve additional metadata<commit_after>package certificates

import (
	"context"
	"crypto/x509"
	"fmt"
	"time"

	api "k8s.io/api/core/v1"
	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/runtime"

	"github.com/golang/glog"
	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
	"github.com/jetstack/cert-manager/pkg/issuer"
	"github.com/jetstack/cert-manager/pkg/util"
	"github.com/jetstack/cert-manager/pkg/util/errors"
	"github.com/jetstack/cert-manager/pkg/util/kube"
	"github.com/jetstack/cert-manager/pkg/util/pki"
)

const renewBefore = time.Hour * 24 * 30

const (
	errorIssuerNotFound       = "ErrorIssuerNotFound"
	errorIssuerNotReady       = "ErrorIssuerNotReady"
	errorIssuerInit           = "ErrorIssuerInitialization"
	errorCheckCertificate     = "ErrorCheckCertificate"
	errorGetCertificate       = "ErrorGetCertificate"
	errorPreparingCertificate = "ErrorPrepareCertificate"
	errorIssuingCertificate   = "ErrorIssueCertificate"
	errorRenewingCertificate  = "ErrorRenewCertificate"
	errorSavingCertificate    = "ErrorSaveCertificate"

	reasonPreparingCertificate = "PrepareCertificate"
	reasonIssuingCertificate   = "IssueCertificate"
	reasonRenewingCertificate  = "RenewCertificate"

	successCeritificateIssued  = "CeritifcateIssued"
	successCeritificateRenewed = "CeritifcateRenewed"
	successRenewalScheduled    = "RenewalScheduled"

	messageIssuerNotFound            = "Issuer %s does not exist"
	messageIssuerNotReady            = "Issuer %s not ready"
	messageIssuerErrorInit           = "Error initializing issuer: "
	messageErrorCheckCertificate     = "Error checking existing TLS certificate: "
	messageErrorGetCertificate       = "Error getting TLS certificate: "
	messageErrorPreparingCertificate = "Error preparing issuer for certificate: "
	messageErrorIssuingCertificate   = "Error issuing certificate: "
	messageErrorRenewingCertificate  = "Error renewing certificate: "
	messageErrorSavingCertificate    = "Error saving TLS certificate: "

	messagePreparingCertificate = "Preparing certificate with issuer"
	messageIssuingCertificate   = "Issuing certificate..."
	messageRenewingCertificate  = "Renewing certificate..."

	messageCertificateIssued  = "Certificated issued successfully"
	messageCertificateRenewed = "Certificated renewed successfully"
	messageRenewalScheduled   = "Certificate scheduled for renewal in %d hours"
)

func (c *Controller) Sync(ctx context.Context, crt *v1alpha1.Certificate) (err error) {
	// step zero: check if the referenced issuer exists and is ready
	issuerObj, err := c.getGenericIssuer(crt)

	if err != nil {
		s := fmt.Sprintf(messageIssuerNotFound, err.Error())
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorIssuerNotFound, s)
		return err
	}

	issuerReady := issuerObj.HasCondition(v1alpha1.IssuerCondition{
		Type:   v1alpha1.IssuerConditionReady,
		Status: v1alpha1.ConditionTrue,
	})
	if !issuerReady {
		s := fmt.Sprintf(messageIssuerNotReady, issuerObj.GetObjectMeta().Name)
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorIssuerNotReady, s)
		return fmt.Errorf(s)
	}

	i, err := c.issuerFactory.IssuerFor(issuerObj)
	if err != nil {
		s := messageIssuerErrorInit + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorIssuerInit, s)
		return err
	}

	expectedCN, err := pki.CommonNameForCertificate(crt)
	if err != nil {
		return err
	}
	expectedDNSNames, err := pki.DNSNamesForCertificate(crt)
	if err != nil {
		return err
	}

	// grab existing certificate and validate private key
	cert, err := kube.SecretTLSCert(c.secretLister, crt.Namespace, crt.Spec.SecretName)
	if err != nil {
		s := messageErrorCheckCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorCheckCertificate, s)
	}

	// if an error is returned, and that error is something other than
	// IsNotFound or invalid data, then we should return the error.
	if err != nil && !k8sErrors.IsNotFound(err) && !errors.IsInvalidData(err) {
		return err
	}

	// as there is an existing certificate, or we may create one below, we will
	// run scheduleRenewal to schedule a renewal if required at the end of
	// execution.
	defer c.scheduleRenewal(crt)

	crtCopy := crt.DeepCopy()

	// if the certificate was not found, or the certificate data is invalid, we
	// should issue a new certificate.
	// if the certificate is valid for a list of domains other than those
	// listed in the certificate spec, we should re-issue the certificate.
	if k8sErrors.IsNotFound(err) || errors.IsInvalidData(err) ||
		expectedCN != cert.Subject.CommonName || !util.EqualUnsorted(cert.DNSNames, expectedDNSNames) {
		err := c.issue(ctx, i, crtCopy)
		updateErr := c.updateCertificateStatus(crtCopy)
		if err != nil || updateErr != nil {
			return utilerrors.NewAggregate([]error{err, updateErr})
		}
		return nil
	}

	// calculate the amount of time until expiry
	durationUntilExpiry := cert.NotAfter.Sub(time.Now())
	// calculate how long until we should start attempting to renew the
	// certificate
	renewIn := durationUntilExpiry - renewBefore
	// if we should being attempting to renew now, then trigger a renewal
	if renewIn <= 0 {
		err := c.renew(ctx, i, crtCopy)
		updateErr := c.updateCertificateStatus(crtCopy)
		if err != nil || updateErr != nil {
			return utilerrors.NewAggregate([]error{err, updateErr})
		}
	}

	return nil
}

func (c *Controller) getGenericIssuer(crt *v1alpha1.Certificate) (v1alpha1.GenericIssuer, error) {
	switch crt.Spec.IssuerRef.Kind {
	case "", v1alpha1.IssuerKind:
		return c.issuerLister.Issuers(crt.Namespace).Get(crt.Spec.IssuerRef.Name)
	case v1alpha1.ClusterIssuerKind:
		if c.clusterIssuerLister == nil {
			return nil, fmt.Errorf("cannot get ClusterIssuer for %q as cert-manager is scoped to a single namespace", crt.Name)
		}
		return c.clusterIssuerLister.Get(crt.Spec.IssuerRef.Name)
	default:
		return nil, fmt.Errorf(`invalid value %q for certificate issuer kind. Must be empty, %q or %q`, crt.Spec.IssuerRef.Kind, v1alpha1.IssuerKind, v1alpha1.ClusterIssuerKind)
	}
}

func needsRenew(cert *x509.Certificate) bool {
	durationUntilExpiry := cert.NotAfter.Sub(time.Now())
	renewIn := durationUntilExpiry - renewBefore
	// step three: check if referenced secret is valid (after start & before expiry)
	if renewIn <= 0 {
		return true
	}
	return false
}

func (c *Controller) scheduleRenewal(crt *v1alpha1.Certificate) {
	key, err := keyFunc(crt)

	if err != nil {
		runtime.HandleError(fmt.Errorf("error getting key for certificate resource: %s", err.Error()))
		return
	}

	cert, err := kube.SecretTLSCert(c.secretLister, crt.Namespace, crt.Spec.SecretName)

	if err != nil {
		runtime.HandleError(fmt.Errorf("[%s/%s] Error getting certificate '%s': %s", crt.Namespace, crt.Name, crt.Spec.SecretName, err.Error()))
		return
	}

	durationUntilExpiry := cert.NotAfter.Sub(time.Now())
	renewIn := durationUntilExpiry - renewBefore

	c.scheduledWorkQueue.Add(key, renewIn)

	s := fmt.Sprintf(messageRenewalScheduled, renewIn/time.Hour)
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, successRenewalScheduled, s)
}

func (c *Controller) updateSecret(name, namespace string, cert, key []byte) (*api.Secret, error) {
	secret, err := c.client.CoreV1().Secrets(namespace).Get(name, metav1.GetOptions{})
	if err != nil && !k8sErrors.IsNotFound(err) {
		return nil, err
	}
	if k8sErrors.IsNotFound(err) {
		secret = &api.Secret{
			ObjectMeta: metav1.ObjectMeta{
				Name:      name,
				Namespace: namespace,
			},
			Type: api.SecretTypeTLS,
			Data: map[string][]byte{},
		}
	}
	secret.Data[api.TLSCertKey] = cert
	secret.Data[api.TLSPrivateKeyKey] = key
	// if it is a new resource
	if secret.SelfLink == "" {
		secret, err = c.client.CoreV1().Secrets(namespace).Create(secret)
	} else {
		secret, err = c.client.CoreV1().Secrets(namespace).Update(secret)
	}
	if err != nil {
		return nil, err
	}
	return secret, nil
}

// return an error on failure. If retrieval is succesful, the certificate data
// and private key will be stored in the named secret
func (c *Controller) issue(ctx context.Context, issuer issuer.Interface, crt *v1alpha1.Certificate) error {
	var err error
	s := messagePreparingCertificate
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, reasonPreparingCertificate, s)
	if err = issuer.Prepare(ctx, crt); err != nil {
		s := messageErrorPreparingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorPreparingCertificate, s)
		return err
	}

	s = messageIssuingCertificate
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, reasonIssuingCertificate, s)

	var key, cert []byte
	key, cert, err = issuer.Issue(ctx, crt)

	if err != nil {
		s := messageErrorIssuingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorIssuingCertificate, s)
		return err
	}

	if _, err := c.updateSecret(crt.Spec.SecretName, crt.Namespace, cert, key); err != nil {
		s := messageErrorSavingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorSavingCertificate, s)
		return err
	}

	s = messageCertificateIssued
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, successCeritificateIssued, s)

	return nil
}

// renew will attempt to renew a certificate from the specified issuer, or
// return an error on failure. If renewal is succesful, the certificate data
// and private key will be stored in the named secret
func (c *Controller) renew(ctx context.Context, issuer issuer.Interface, crt *v1alpha1.Certificate) error {
	var err error
	s := messagePreparingCertificate
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, reasonPreparingCertificate, s)

	if err = issuer.Prepare(ctx, crt); err != nil {
		s := messageErrorPreparingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorPreparingCertificate, s)
		return err
	}

	s = messageRenewingCertificate
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, reasonRenewingCertificate, s)

	var key, cert []byte
	key, cert, err = issuer.Renew(ctx, crt)

	if err != nil {
		s := messageErrorRenewingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorRenewingCertificate, s)
		return err
	}

	if _, err := c.updateSecret(crt.Spec.SecretName, crt.Namespace, cert, key); err != nil {
		s := messageErrorSavingCertificate + err.Error()
		glog.Info(s)
		c.recorder.Event(crt, api.EventTypeWarning, errorSavingCertificate, s)
		return err
	}

	s = messageCertificateRenewed
	glog.Info(s)
	c.recorder.Event(crt, api.EventTypeNormal, successCeritificateRenewed, s)

	return nil
}

func (c *Controller) updateCertificateStatus(crt *v1alpha1.Certificate) error {
	// TODO: replace Update call with UpdateStatus. This requires a custom API
	// server with the /status subresource enabled and/or subresource support
	// for CRDs (https://github.com/kubernetes/kubernetes/issues/38113)
	_, err := c.cmClient.CertmanagerV1alpha1().Certificates(crt.Namespace).Update(crt)
	return err
}
<|endoftext|>


<commit_before>package header

import (
    "fmt"
    "github.com/caa-dev-apps/cefmdd_v1/pkg/diag"
//x     "errors"
//x     "strings"
//x     "github.com/caa-dev-apps/cefmdd_v1/pkg/utils"
//x     "github.com/caa-dev-apps/cefmdd_v1/pkg/diag"
)

//.             type Attrs struct {
//.                 m_map map[string][]string
//.             }
//.
//.             func NewAttrs() *Attrs {
//.                 return &Attrs{m_map: make(map[string][]string)}
//.             }
//.
//.             func (a *Attrs) Map() (map[string][]string) {
//.                 return a.m_map
//.             }
//.
//.             func (m *Attrs) push_kv(kv *readers.KeyVal) (err error) {
//.
//.                 val, is_present := m.m_map[kv.Key]
//.                 if is_present == true {
//.                     val = append(val, kv.Val...)
//.                 } else {
//.                     val = kv.Val
//.                 }
//.
//.                 m.m_map[kv.Key] = val
//.
//.                 return err
//.             }
//.
//.             func (m *Attrs) push_k_v(k, v string) (err error) {
//.                 vs := []string{ v }
//.
//.                 kv := readers.NewMetaKeyVal(k , vs)
//.
//.                 return m.push_kv(kv)
//.             }

//.             type Vars struct {
//.                 m_map map[string]Attrs
//.                 m_list []Attrs
//.             }
//.
//.             func NewVars() *Vars {
//.                 return &Vars{
//.                     m_map: make(map[string]Attrs),
//.                     m_list: make([]Attrs, 0),
//.                 }
//.             }
//.
//.             func (v *Vars) Map() (map[string]Attrs) {
//.                 return v.m_map
//.             }
//.
//.             func (v *Vars) List() ([]Attrs) {
//.                 return v.m_list
//.             }
//.
//.             type CefHeaderData struct {
//.                 m_state State
//.                 m_name  string
//.                 m_cur* Attrs
//.
//.                 m_attrs* Attrs
//.                 m_meta* Meta
//.                 m_vars* Vars
//.             }

func (h *CefHeaderData) Var_Checks() (err error) {
    h.print_results("VAR CHECKS TODO", err)

    var_list := h.Vars().List()
    var_map  := h.Vars().Map()

    for k, v := range var_list {
        v_map := v.Map()
        var_name := v_map["variable_name"]

        fmt.Println("\n\n")
        fmt.Println("k:", k)
        fmt.Println("n:", var_name)
//.         fmt.Println(v)

        depend0, p := v_map["DEPEND_0"]
        if p == true {
            fmt.Println("DEPEND_0 = ", depend0)

            v1_map, p1 := var_map[depend0[0]]
            if p1 == false {
                diag.Error("DEPEND_0 VAR not found", depend0[0])
            } else {
                fmt.Println("DEPEND_0 VAR OK", depend0[0], v1_map.Map()["variable_name"])
            }
        }

    }

    return
}

//x h.dumpMeta()

<commit_msg>var checks in progress<commit_after>package header

import (
    "fmt"
    "github.com/caa-dev-apps/cefmdd_v1/pkg/diag"
//x     "errors"
//x     "strings"
//x     "github.com/caa-dev-apps/cefmdd_v1/pkg/utils"
//x     "github.com/caa-dev-apps/cefmdd_v1/pkg/diag"
)

//.             type Attrs struct {
//.                 m_map map[string][]string
//.             }
//.
//.             func NewAttrs() *Attrs {
//.                 return &Attrs{m_map: make(map[string][]string)}
//.             }
//.
//.             func (a *Attrs) Map() (map[string][]string) {
//.                 return a.m_map
//.             }
//.
//.             func (m *Attrs) push_kv(kv *readers.KeyVal) (err error) {
//.
//.                 val, is_present := m.m_map[kv.Key]
//.                 if is_present == true {
//.                     val = append(val, kv.Val...)
//.                 } else {
//.                     val = kv.Val
//.                 }
//.
//.                 m.m_map[kv.Key] = val
//.
//.                 return err
//.             }
//.
//.             func (m *Attrs) push_k_v(k, v string) (err error) {
//.                 vs := []string{ v }
//.
//.                 kv := readers.NewMetaKeyVal(k , vs)
//.
//.                 return m.push_kv(kv)
//.             }

//.             type Vars struct {
//.                 m_map map[string]Attrs
//.                 m_list []Attrs
//.             }
//.
//.             func NewVars() *Vars {
//.                 return &Vars{
//.                     m_map: make(map[string]Attrs),
//.                     m_list: make([]Attrs, 0),
//.                 }
//.             }
//.
//.             func (v *Vars) Map() (map[string]Attrs) {
//.                 return v.m_map
//.             }
//.
//.             func (v *Vars) List() ([]Attrs) {
//.                 return v.m_list
//.             }
//.
//.             type CefHeaderData struct {
//.                 m_state State
//.                 m_name  string
//.                 m_cur* Attrs
//.
//.                 m_attrs* Attrs
//.                 m_meta* Meta
//.                 m_vars* Vars
//.             }

//x func (h *CefHeaderData) Var_Checks() (err error) {
//x     h.print_results("VAR CHECKS TODO", err)
//x
//x     var_list := h.Vars().List()
//x     var_map  := h.Vars().Map()
//x
//x     for k, v := range var_list {
//x         v_map := v.Map()
//x         var_name := v_map["variable_name"]
//x
//x         fmt.Println("\n\n")
//x         fmt.Println("k:", k)
//x         fmt.Println("n:", var_name)
//x //.         fmt.Println(v)
//x
//x
//x         depend0, p := v_map["DEPEND_0"]
//x         if p == true {
//x             fmt.Println("DEPEND_0 = ", depend0)
//x
//x             v1_map, p1 := var_map[depend0[0]]
//x             if p1 == false {
//x                 diag.Error("DEPEND_0 VAR not found", depend0[0])
//x             } else {
//x                 fmt.Println("DEPEND_0 VAR OK", depend0[0], v1_map.Map()["variable_name"])
//x             }
//x         }
//x
//x     }
//x
//x     return
//x }

func (h *CefHeaderData) Depend_N_Checks(a Attrs) (err error) {
    // all vars
    //vars_map  := h.Vars().Map()

    var_name := a.Map()["variable_name"]
    diag.Info("n:", var_name)

    depend0, p := a.Map()["DEPEND_0"]
    if p == true {
        diag.Info("DEPEND_0 = ", depend0)

//        v1_map, p1 := vars_map[depend0[0]]
//        if p1 == false {
//            diag.Error("DEPEND_0 VAR not found", depend0[0])
//        } else {
//            fmt.Println("DEPEND_0 VAR OK", depend0[0], v1_map.Map()["variable_name"])
//        }
    }

    for k, v := range a.Map() {
        fmt.Println("k:", k)
        fmt.Println("v:", v)
    }

    return
}

func (h *CefHeaderData) Var_Checks() (err error) {
    h.print_results("VAR CHECKS TODO", err)

    var_list := h.Vars().List()

    for k, v := range var_list {
        fmt.Println("k:", k)

        h.Depend_N_Checks(v)
    }

    return
}

//x h.dumpMeta()

<|endoftext|>


<commit_before>package resolver

import (
	"fmt"
	"sync"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/patrickmn/go-cache"

	"nimona.io/internal/net"
	"nimona.io/internal/rand"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/did"
	"nimona.io/pkg/errors"
	"nimona.io/pkg/hyperspace"
	"nimona.io/pkg/hyperspace/peerstore"
	"nimona.io/pkg/keystream"
	"nimona.io/pkg/log"
	"nimona.io/pkg/object"
	"nimona.io/pkg/peer"
	"nimona.io/pkg/sqlobjectstore"
	"nimona.io/pkg/tilde"
)

const (
	ErrNoPeersToAsk = errors.Error("no peers to ask")

	peerCacheTTL = 1 * time.Minute
)

//go:generate mockgen -destination=../resolvermock/resolvermock_generated.go -package=resolvermock -source=resolver.go
//go:generate genny -in=$GENERATORS/synclist/synclist.go -out=hashes_generated.go -imp=nimona.io/pkg/object -pkg=resolver gen "KeyType=tilde.Digest"

type (
	Resolver interface {
		Lookup(
			ctx context.Context,
			opts ...LookupOption,
		) ([]*peer.ConnectionInfo, error)
		LookupPeer(
			ctx context.Context,
			id did.DID,
		) ([]*peer.ConnectionInfo, error)
	}
	resolver struct {
		peerKey                        crypto.PrivateKey
		context                        context.Context
		network                        net.Network
		peerCache                      *peerstore.PeerCache
		localPeerAnnouncementCache     *hyperspace.Announcement
		localPeerAnnouncementCacheLock sync.RWMutex
		bootstrapPeers                 []*peer.ConnectionInfo
		blocklist                      *cache.Cache
		hashes                         *TildeDigestSyncList
		keyStreamManager               keystream.Manager
	}
	// Option for customizing a new resolver
	Option func(*resolver)
)

// New returns a new resolver.
// Object store is currently optional.
func New(
	ctx context.Context,
	network net.Network,
	peerKey crypto.PrivateKey,
	str *sqlobjectstore.Store,
	ksm keystream.Manager,
	opts ...Option,
) Resolver {
	r := &resolver{
		context: ctx,
		peerKey: peerKey,
		network: network,
		peerCache: peerstore.NewPeerCache(
			time.Minute,
			"nimona_hyperspace_resolver",
		),
		localPeerAnnouncementCacheLock: sync.RWMutex{},
		bootstrapPeers:                 []*peer.ConnectionInfo{},
		blocklist:                      cache.New(time.Second*5, time.Second*60),
		hashes:                         &TildeDigestSyncList{},
		keyStreamManager:               ksm,
	}

	for _, opt := range opts {
		opt(r)
	}

	// we are listening for all incoming object types in order to learn about
	// new peers that are talking to us so we can announce ourselves to them
	go r.network.RegisterConnectionHandler(
		func(c net.Connection) {
			go func() {
				or := c.Read(ctx)
				for {
					o, err := or.Read()
					if err != nil {
						return
					}
					r.handleObject(c.RemotePeerKey(), o)
				}
			}()
		},
	)

	// go through all existing objects and add them as well
	if str != nil {
		if hashes, err := str.ListHashes(); err == nil {
			for _, hash := range hashes {
				r.hashes.Put(hash)
			}
		}
	}

	for _, p := range r.bootstrapPeers {
		r.peerCache.Put(&hyperspace.Announcement{
			ConnectionInfo: p,
		}, 0)
	}

	// announce when our key stream has a new controller
	go func() {
		_, err := r.keyStreamManager.WaitForController(ctx)
		if err != nil {
			r.announceSelf()
		}
	}()

	// announce on startup, timeout, and when we have new objects
	go func() {
		r.announceSelf()

		// announce on object updates
		strSub := make(<-chan sqlobjectstore.Event)
		strCf := func() {}
		if str != nil {
			strSub, strCf = str.ListenForUpdates()
		}
		defer strCf()

		// or every 30 seconds
		announceTicker := time.NewTicker(30 * time.Second)
		for {
			select {
			case <-announceTicker.C:
				r.announceSelf()
			case event := <-strSub:
				switch event.Action {
				case sqlobjectstore.ObjectInserted:
					r.hashes.Put(event.ObjectHash)
					r.announceSelf()
				case sqlobjectstore.ObjectRemoved:
					r.hashes.Delete(event.ObjectHash)
					r.announceSelf()
				}
			}
		}
	}()

	return r
}

func (r *resolver) LookupPeer(
	ctx context.Context,
	id did.DID,
) ([]*peer.ConnectionInfo, error) {
	return r.Lookup(ctx, LookupByDID(id))
}

// Lookup finds and returns peer infos from a fingerprint
// TODO consider returning peers synchronously
func (r *resolver) Lookup(
	ctx context.Context,
	opts ...LookupOption,
) ([]*peer.ConnectionInfo, error) {
	if len(r.bootstrapPeers) == 0 {
		return nil, errors.Error("no peers to ask")
	}

	logger := log.FromContext(ctx).With(
		log.String("method", "resolver.Lookup"),
	)
	logger.Debug("looking up")

	opt := ParseLookupOptions(opts...)

	// send content requests to recipients
	var reqObject *object.Object
	var err error
	nonce := rand.String(12)
	if !opt.DID.IsEmpty() {
		req := &hyperspace.LookupByDIDRequest{
			Metadata: object.Metadata{
				Owner: r.peerKey.PublicKey().DID(),
			},
			Nonce: nonce,
			Owner: opt.DID,
		}
		reqObject, err = object.Marshal(req)
		if err != nil {
			return nil, err
		}
	} else if !opt.Digest.IsEmpty() {
		req := &hyperspace.LookupByDigestRequest{
			Metadata: object.Metadata{
				Owner: r.peerKey.PublicKey().DID(),
			},
			Nonce:  nonce,
			Digest: opt.Digest,
		}
		reqObject, err = object.Marshal(req)
		if err != nil {
			return nil, err
		}
	} else {
		return nil, fmt.Errorf("missing lookup options")
	}

	responses := make(chan *object.Object)

	go func() {
		for _, bp := range r.bootstrapPeers {
			conn, err := r.network.Dial(ctx, bp)
			if err != nil {
				logger.Debug("failed to dial peer", log.Error(err))
				continue
			}
			// read all objects from the connection
			go func() {
				reader := conn.Read(ctx)
				for {
					o, err := reader.Read()
					if err != nil {
						return
					}
					// find any responses
					v := o.Data["nonce"]
					rn, ok := v.(tilde.String)
					if ok && string(rn) == nonce {
						// and write them to the channel
						responses <- o
					}
				}
			}()
			err = conn.Write(
				ctx,
				reqObject,
			)
			if err != nil {
				logger.Debug("could send request to peer", log.Error(err))
				continue
			}
			logger.Debug(
				"asked peer",
				log.String("peer", bp.PublicKey.String()),
			)
		}
	}()

	// create channel to keep peers we find
	peers := []*peer.ConnectionInfo{}
	done := make(chan struct{})

	go func() {
		for {
			o := <-responses
			r := &hyperspace.LookupResponse{}
			if err := object.Unmarshal(o, r); err != nil {
				continue
			}
			// TODO verify peer?
			for _, ann := range r.Announcements {
				fmt.Println("*** got back peer", ann.ConnectionInfo.PublicKey.DID())
				peers = append(peers, ann.ConnectionInfo)
			}
			close(done)
			break
		}
	}()

	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	case <-done:
		return peers, nil
	}
}

func (r *resolver) handleObject(
	sender crypto.PublicKey,
	o *object.Object,
) {
	// attempt to recover correlation id from request id
	ctx := r.context

	logger := log.FromContext(ctx).With(
		log.String("method", "resolver.handleObject"),
		log.String("env.Sender", sender.String()),
	)

	// handle payload
	// o := e.Payload
	if o.Type == hyperspace.AnnouncementType {
		v := &hyperspace.Announcement{}
		if err := object.Unmarshal(o, v); err != nil {
			logger.Warn(
				"error handling announcement",
				log.Error(err),
			)
			return
		}
		r.handleAnnouncement(ctx, v)
	}
}

func (r *resolver) handleAnnouncement(
	ctx context.Context,
	p *hyperspace.Announcement,
) {
	logger := log.FromContext(ctx).With(
		log.String("method", "resolver.handleAnnouncement"),
		log.String("peer.publicKey", p.ConnectionInfo.PublicKey.String()),
		log.Strings("peer.addresses", p.ConnectionInfo.Addresses),
	)
	logger.Debug("adding peer to cache")
	r.peerCache.Put(p, peerCacheTTL)
}

func (r *resolver) announceSelf() {
	ctx := context.New(
		context.WithParent(r.context),
	)
	logger := log.FromContext(ctx).With(
		log.String("method", "resolver.announceSelf"),
	)
	n := 0
	anno, err := object.Marshal(r.getLocalPeerAnnouncement())
	if err != nil {
		logger.Error("error marshaling announcement", log.Error(err))
		return
	}
	for _, p := range r.bootstrapPeers {
		conn, err := r.network.Dial(
			context.New(
				context.WithParent(ctx),
				context.WithTimeout(time.Second*3),
			),
			p,
		)
		if err != nil {
			logger.Debug("failed to dial peer", log.Error(err))
			continue
		}
		err = conn.Write(
			ctx,
			anno,
		)
		if err != nil {
			logger.Error(
				"error announcing self to bootstrap",
				log.String("peer", p.PublicKey.String()),
				log.Error(err),
			)
			continue
		}
		n++
	}
	if n == 0 {
		logger.Error(
			"failed to announce self to any bootstrap peers",
		)
		return
	}
	logger.Info(
		"announced self to bootstrap peers",
		log.Int("bootstrapPeers", n),
	)
}

func (r *resolver) getLocalPeerAnnouncement() *hyperspace.Announcement {
	r.localPeerAnnouncementCacheLock.RLock()
	lastAnnouncement := r.localPeerAnnouncementCache
	r.localPeerAnnouncementCacheLock.RUnlock()

	owner := r.peerKey.PublicKey().DID()
	ctrl, err := r.keyStreamManager.GetController()
	if err == nil && ctrl != nil {
		owner = ctrl.GetKeyStream().GetDID()
	}
	digests := r.hashes.List()
	addresses := r.network.Addresses()

	// TODO support relays
	// relays := r.network.GetRelays()

	if lastAnnouncement != nil &&
		cmp.Equal(lastAnnouncement.ConnectionInfo.Addresses, addresses) &&
		cmp.Equal(lastAnnouncement.Digests, digests) {
		return lastAnnouncement
	}

	localPeerAnnouncementCache := &hyperspace.Announcement{
		Metadata: object.Metadata{
			Owner: owner,
		},
		Version: time.Now().Unix(),
		ConnectionInfo: &peer.ConnectionInfo{
			PublicKey: r.peerKey.PublicKey(),
			Addresses: addresses,
			// Relays:    relays,
		},
		Digests: digests,
		// TODO add capabilities
	}

	r.localPeerAnnouncementCacheLock.Lock()
	r.localPeerAnnouncementCache = localPeerAnnouncementCache
	r.localPeerAnnouncementCacheLock.Unlock()

	return localPeerAnnouncementCache
}
<commit_msg>chore(resolver): remove println<commit_after>package resolver

import (
	"fmt"
	"sync"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/patrickmn/go-cache"

	"nimona.io/internal/net"
	"nimona.io/internal/rand"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/did"
	"nimona.io/pkg/errors"
	"nimona.io/pkg/hyperspace"
	"nimona.io/pkg/hyperspace/peerstore"
	"nimona.io/pkg/keystream"
	"nimona.io/pkg/log"
	"nimona.io/pkg/object"
	"nimona.io/pkg/peer"
	"nimona.io/pkg/sqlobjectstore"
	"nimona.io/pkg/tilde"
)

const (
	ErrNoPeersToAsk = errors.Error("no peers to ask")

	peerCacheTTL = 1 * time.Minute
)

//go:generate mockgen -destination=../resolvermock/resolvermock_generated.go -package=resolvermock -source=resolver.go
//go:generate genny -in=$GENERATORS/synclist/synclist.go -out=hashes_generated.go -imp=nimona.io/pkg/object -pkg=resolver gen "KeyType=tilde.Digest"

type (
	Resolver interface {
		Lookup(
			ctx context.Context,
			opts ...LookupOption,
		) ([]*peer.ConnectionInfo, error)
		LookupPeer(
			ctx context.Context,
			id did.DID,
		) ([]*peer.ConnectionInfo, error)
	}
	resolver struct {
		peerKey                        crypto.PrivateKey
		context                        context.Context
		network                        net.Network
		peerCache                      *peerstore.PeerCache
		localPeerAnnouncementCache     *hyperspace.Announcement
		localPeerAnnouncementCacheLock sync.RWMutex
		bootstrapPeers                 []*peer.ConnectionInfo
		blocklist                      *cache.Cache
		hashes                         *TildeDigestSyncList
		keyStreamManager               keystream.Manager
	}
	// Option for customizing a new resolver
	Option func(*resolver)
)

// New returns a new resolver.
// Object store is currently optional.
func New(
	ctx context.Context,
	network net.Network,
	peerKey crypto.PrivateKey,
	str *sqlobjectstore.Store,
	ksm keystream.Manager,
	opts ...Option,
) Resolver {
	r := &resolver{
		context: ctx,
		peerKey: peerKey,
		network: network,
		peerCache: peerstore.NewPeerCache(
			time.Minute,
			"nimona_hyperspace_resolver",
		),
		localPeerAnnouncementCacheLock: sync.RWMutex{},
		bootstrapPeers:                 []*peer.ConnectionInfo{},
		blocklist:                      cache.New(time.Second*5, time.Second*60),
		hashes:                         &TildeDigestSyncList{},
		keyStreamManager:               ksm,
	}

	for _, opt := range opts {
		opt(r)
	}

	// we are listening for all incoming object types in order to learn about
	// new peers that are talking to us so we can announce ourselves to them
	go r.network.RegisterConnectionHandler(
		func(c net.Connection) {
			go func() {
				or := c.Read(ctx)
				for {
					o, err := or.Read()
					if err != nil {
						return
					}
					r.handleObject(c.RemotePeerKey(), o)
				}
			}()
		},
	)

	// go through all existing objects and add them as well
	if str != nil {
		if hashes, err := str.ListHashes(); err == nil {
			for _, hash := range hashes {
				r.hashes.Put(hash)
			}
		}
	}

	for _, p := range r.bootstrapPeers {
		r.peerCache.Put(&hyperspace.Announcement{
			ConnectionInfo: p,
		}, 0)
	}

	// announce when our key stream has a new controller
	go func() {
		_, err := r.keyStreamManager.WaitForController(ctx)
		if err != nil {
			r.announceSelf()
		}
	}()

	// announce on startup, timeout, and when we have new objects
	go func() {
		r.announceSelf()

		// announce on object updates
		strSub := make(<-chan sqlobjectstore.Event)
		strCf := func() {}
		if str != nil {
			strSub, strCf = str.ListenForUpdates()
		}
		defer strCf()

		// or every 30 seconds
		announceTicker := time.NewTicker(30 * time.Second)
		for {
			select {
			case <-announceTicker.C:
				r.announceSelf()
			case event := <-strSub:
				switch event.Action {
				case sqlobjectstore.ObjectInserted:
					r.hashes.Put(event.ObjectHash)
					r.announceSelf()
				case sqlobjectstore.ObjectRemoved:
					r.hashes.Delete(event.ObjectHash)
					r.announceSelf()
				}
			}
		}
	}()

	return r
}

func (r *resolver) LookupPeer(
	ctx context.Context,
	id did.DID,
) ([]*peer.ConnectionInfo, error) {
	return r.Lookup(ctx, LookupByDID(id))
}

// Lookup finds and returns peer infos from a fingerprint
// TODO consider returning peers synchronously
func (r *resolver) Lookup(
	ctx context.Context,
	opts ...LookupOption,
) ([]*peer.ConnectionInfo, error) {
	if len(r.bootstrapPeers) == 0 {
		return nil, errors.Error("no peers to ask")
	}

	logger := log.FromContext(ctx).With(
		log.String("method", "resolver.Lookup"),
	)
	logger.Debug("looking up")

	opt := ParseLookupOptions(opts...)

	// send content requests to recipients
	var reqObject *object.Object
	var err error
	nonce := rand.String(12)
	if !opt.DID.IsEmpty() {
		req := &hyperspace.LookupByDIDRequest{
			Metadata: object.Metadata{
				Owner: r.peerKey.PublicKey().DID(),
			},
			Nonce: nonce,
			Owner: opt.DID,
		}
		reqObject, err = object.Marshal(req)
		if err != nil {
			return nil, err
		}
	} else if !opt.Digest.IsEmpty() {
		req := &hyperspace.LookupByDigestRequest{
			Metadata: object.Metadata{
				Owner: r.peerKey.PublicKey().DID(),
			},
			Nonce:  nonce,
			Digest: opt.Digest,
		}
		reqObject, err = object.Marshal(req)
		if err != nil {
			return nil, err
		}
	} else {
		return nil, fmt.Errorf("missing lookup options")
	}

	responses := make(chan *object.Object)

	go func() {
		for _, bp := range r.bootstrapPeers {
			conn, err := r.network.Dial(ctx, bp)
			if err != nil {
				logger.Debug("failed to dial peer", log.Error(err))
				continue
			}
			// read all objects from the connection
			go func() {
				reader := conn.Read(ctx)
				for {
					o, err := reader.Read()
					if err != nil {
						return
					}
					// find any responses
					v := o.Data["nonce"]
					rn, ok := v.(tilde.String)
					if ok && string(rn) == nonce {
						// and write them to the channel
						responses <- o
					}
				}
			}()
			err = conn.Write(
				ctx,
				reqObject,
			)
			if err != nil {
				logger.Debug("could send request to peer", log.Error(err))
				continue
			}
			logger.Debug(
				"asked peer",
				log.String("peer", bp.PublicKey.String()),
			)
		}
	}()

	// create channel to keep peers we find
	peers := []*peer.ConnectionInfo{}
	done := make(chan struct{})

	go func() {
		for {
			o := <-responses
			r := &hyperspace.LookupResponse{}
			if err := object.Unmarshal(o, r); err != nil {
				continue
			}
			// TODO verify peer?
			for _, ann := range r.Announcements {
				peers = append(peers, ann.ConnectionInfo)
			}
			close(done)
			break
		}
	}()

	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	case <-done:
		return peers, nil
	}
}

func (r *resolver) handleObject(
	sender crypto.PublicKey,
	o *object.Object,
) {
	// attempt to recover correlation id from request id
	ctx := r.context

	logger := log.FromContext(ctx).With(
		log.String("method", "resolver.handleObject"),
		log.String("env.Sender", sender.String()),
	)

	// handle payload
	// o := e.Payload
	if o.Type == hyperspace.AnnouncementType {
		v := &hyperspace.Announcement{}
		if err := object.Unmarshal(o, v); err != nil {
			logger.Warn(
				"error handling announcement",
				log.Error(err),
			)
			return
		}
		r.handleAnnouncement(ctx, v)
	}
}

func (r *resolver) handleAnnouncement(
	ctx context.Context,
	p *hyperspace.Announcement,
) {
	logger := log.FromContext(ctx).With(
		log.String("method", "resolver.handleAnnouncement"),
		log.String("peer.publicKey", p.ConnectionInfo.PublicKey.String()),
		log.Strings("peer.addresses", p.ConnectionInfo.Addresses),
	)
	logger.Debug("adding peer to cache")
	r.peerCache.Put(p, peerCacheTTL)
}

func (r *resolver) announceSelf() {
	ctx := context.New(
		context.WithParent(r.context),
	)
	logger := log.FromContext(ctx).With(
		log.String("method", "resolver.announceSelf"),
	)
	n := 0
	anno, err := object.Marshal(r.getLocalPeerAnnouncement())
	if err != nil {
		logger.Error("error marshaling announcement", log.Error(err))
		return
	}
	for _, p := range r.bootstrapPeers {
		conn, err := r.network.Dial(
			context.New(
				context.WithParent(ctx),
				context.WithTimeout(time.Second*3),
			),
			p,
		)
		if err != nil {
			logger.Debug("failed to dial peer", log.Error(err))
			continue
		}
		err = conn.Write(
			ctx,
			anno,
		)
		if err != nil {
			logger.Error(
				"error announcing self to bootstrap",
				log.String("peer", p.PublicKey.String()),
				log.Error(err),
			)
			continue
		}
		n++
	}
	if n == 0 {
		logger.Error(
			"failed to announce self to any bootstrap peers",
		)
		return
	}
	logger.Info(
		"announced self to bootstrap peers",
		log.Int("bootstrapPeers", n),
	)
}

func (r *resolver) getLocalPeerAnnouncement() *hyperspace.Announcement {
	r.localPeerAnnouncementCacheLock.RLock()
	lastAnnouncement := r.localPeerAnnouncementCache
	r.localPeerAnnouncementCacheLock.RUnlock()

	owner := r.peerKey.PublicKey().DID()
	ctrl, err := r.keyStreamManager.GetController()
	if err == nil && ctrl != nil {
		owner = ctrl.GetKeyStream().GetDID()
	}
	digests := r.hashes.List()
	addresses := r.network.Addresses()

	// TODO support relays
	// relays := r.network.GetRelays()

	if lastAnnouncement != nil &&
		cmp.Equal(lastAnnouncement.ConnectionInfo.Addresses, addresses) &&
		cmp.Equal(lastAnnouncement.Digests, digests) {
		return lastAnnouncement
	}

	localPeerAnnouncementCache := &hyperspace.Announcement{
		Metadata: object.Metadata{
			Owner: owner,
		},
		Version: time.Now().Unix(),
		ConnectionInfo: &peer.ConnectionInfo{
			PublicKey: r.peerKey.PublicKey(),
			Addresses: addresses,
			// Relays:    relays,
		},
		Digests: digests,
		// TODO add capabilities
	}

	r.localPeerAnnouncementCacheLock.Lock()
	r.localPeerAnnouncementCache = localPeerAnnouncementCache
	r.localPeerAnnouncementCacheLock.Unlock()

	return localPeerAnnouncementCache
}
<|endoftext|>


<commit_before>package integration

import (
	"os"
	"testing"

	"github.com/pkg/errors"

	"google.golang.org/grpc"

	"github.com/havoc-io/mutagen/cmd"
	"github.com/havoc-io/mutagen/pkg/agent"
	"github.com/havoc-io/mutagen/pkg/daemon"
	"github.com/havoc-io/mutagen/pkg/forwarding"
	"github.com/havoc-io/mutagen/pkg/grpcutil"
	"github.com/havoc-io/mutagen/pkg/ipc"
	"github.com/havoc-io/mutagen/pkg/logging"
	daemonsvc "github.com/havoc-io/mutagen/pkg/service/daemon"
	forwardingsvc "github.com/havoc-io/mutagen/pkg/service/forwarding"
	promptsvc "github.com/havoc-io/mutagen/pkg/service/prompt"
	synchronizationsvc "github.com/havoc-io/mutagen/pkg/service/synchronization"
	"github.com/havoc-io/mutagen/pkg/synchronization"

	// Explicitly import packages that need to register protocol handlers.
	_ "github.com/havoc-io/mutagen/pkg/forwarding/protocols/docker"
	_ "github.com/havoc-io/mutagen/pkg/forwarding/protocols/local"
	_ "github.com/havoc-io/mutagen/pkg/forwarding/protocols/ssh"
	_ "github.com/havoc-io/mutagen/pkg/integration/protocols/netpipe"
	_ "github.com/havoc-io/mutagen/pkg/synchronization/protocols/docker"
	_ "github.com/havoc-io/mutagen/pkg/synchronization/protocols/local"
	_ "github.com/havoc-io/mutagen/pkg/synchronization/protocols/ssh"
)

// forwardingManager is the forwarding session manager for the integration
// testing daemon. It is exposed for integration tests that operate at the API
// level (as opposed to the gRPC or command line level).
var forwardingManager *forwarding.Manager

// synchronizationManager is the synchronization session manager for the
// integration testing daemon. It is exposed for integration tests that operate
// at the API level (as opposed to the gRPC or command line level).
var synchronizationManager *synchronization.Manager

// testMainInternal is the internal testing entry point, needed so that shutdown
// operations can be deferred (since TestMain will invoke os.Exit). It copies
// the mutagen executable to a well-known path, sets up the agent bundle to work
// during testing, sets up a functionally complete daemon instance for testing,
// runs integration tests, and finally tears down all of the aforementioned
// infrastructure.
func testMainInternal(m *testing.M) (int, error) {
	// Override the expected agent bundle location.
	agent.ExpectedBundleLocation = agent.BundleLocationBuildDirectory

	// Acquire the daemon lock and defer its release.
	lock, err := daemon.AcquireLock()
	if err != nil {
		return -1, errors.Wrap(err, "unable to acquire daemon lock")
	}
	defer lock.Release()

	// Create a forwarding session manager and defer its shutdown.
	forwardingManager, err = forwarding.NewManager(logging.RootLogger.Sublogger("forwarding"))
	if err != nil {
		return -1, errors.Wrap(err, "unable to create forwarding session manager")
	}
	defer forwardingManager.Shutdown()

	// Create a session manager and defer its shutdown. Note that we assign to
	// the global instance here.
	synchronizationManager, err = synchronization.NewManager(logging.RootLogger.Sublogger("sync"))
	if err != nil {
		return -1, errors.Wrap(err, "unable to create synchronization session manager")
	}
	defer synchronizationManager.Shutdown()

	// Create the gRPC server and defer its stoppage. We use a hard stop rather
	// than a graceful stop so that it doesn't hang on open requests.
	server := grpc.NewServer(
		grpc.MaxSendMsgSize(grpcutil.MaximumMessageSize),
		grpc.MaxRecvMsgSize(grpcutil.MaximumMessageSize),
	)
	defer server.Stop()

	// Create and register the daemon service and defer its shutdown.
	daemonServer := daemonsvc.NewServer()
	daemonsvc.RegisterDaemonServer(server, daemonServer)
	defer daemonServer.Shutdown()

	// Create and register the prompt service.
	promptsvc.RegisterPromptingServer(server, promptsvc.NewServer())

	// Create and register the forwarding server.
	forwardingServer := forwardingsvc.NewServer(forwardingManager)
	forwardingsvc.RegisterForwardingServer(server, forwardingServer)

	// Create and register the session service.
	synchronizationServer := synchronizationsvc.NewServer(synchronizationManager)
	synchronizationsvc.RegisterSynchronizationServer(server, synchronizationServer)

	// Compute the path to the daemon IPC endpoint.
	endpoint, err := daemon.EndpointPath()
	if err != nil {
		return -1, errors.Wrap(err, "unable to compute endpoint path")
	}

	// Create the daemon listener and defer its closure. Since we hold the
	// daemon lock, we preemptively remove any existing socket since it (should)
	// be stale.
	os.Remove(endpoint)
	listener, err := ipc.NewListener(endpoint)
	if err != nil {
		return -1, errors.Wrap(err, "unable to create daemon listener")
	}
	defer listener.Close()

	// Serve incoming connections in a separate Goroutine. We don't monitor for
	// errors since there's nothing that we can do about them and because
	// they'll likely show up in the test output anyway.
	go server.Serve(listener)

	// Run tests.
	return m.Run(), nil
}

// TestMain is the entry point for integration tests (overriding the default
// generated entry point).
func TestMain(m *testing.M) {
	// Invoke the internal entry point. If there's an error, print it out before
	// exiting.
	result, err := testMainInternal(m)
	if err != nil {
		cmd.Error(err)
	}

	// Exit with the result.
	os.Exit(result)
}
<commit_msg>Disabled logging in integration tests.<commit_after>package integration

import (
	"io/ioutil"
	"log"
	"os"
	"testing"

	"github.com/pkg/errors"

	"google.golang.org/grpc"

	"github.com/havoc-io/mutagen/cmd"
	"github.com/havoc-io/mutagen/pkg/agent"
	"github.com/havoc-io/mutagen/pkg/daemon"
	"github.com/havoc-io/mutagen/pkg/forwarding"
	"github.com/havoc-io/mutagen/pkg/grpcutil"
	"github.com/havoc-io/mutagen/pkg/ipc"
	"github.com/havoc-io/mutagen/pkg/logging"
	daemonsvc "github.com/havoc-io/mutagen/pkg/service/daemon"
	forwardingsvc "github.com/havoc-io/mutagen/pkg/service/forwarding"
	promptsvc "github.com/havoc-io/mutagen/pkg/service/prompt"
	synchronizationsvc "github.com/havoc-io/mutagen/pkg/service/synchronization"
	"github.com/havoc-io/mutagen/pkg/synchronization"

	// Explicitly import packages that need to register protocol handlers.
	_ "github.com/havoc-io/mutagen/pkg/forwarding/protocols/docker"
	_ "github.com/havoc-io/mutagen/pkg/forwarding/protocols/local"
	_ "github.com/havoc-io/mutagen/pkg/forwarding/protocols/ssh"
	_ "github.com/havoc-io/mutagen/pkg/integration/protocols/netpipe"
	_ "github.com/havoc-io/mutagen/pkg/synchronization/protocols/docker"
	_ "github.com/havoc-io/mutagen/pkg/synchronization/protocols/local"
	_ "github.com/havoc-io/mutagen/pkg/synchronization/protocols/ssh"
)

// forwardingManager is the forwarding session manager for the integration
// testing daemon. It is exposed for integration tests that operate at the API
// level (as opposed to the gRPC or command line level).
var forwardingManager *forwarding.Manager

// synchronizationManager is the synchronization session manager for the
// integration testing daemon. It is exposed for integration tests that operate
// at the API level (as opposed to the gRPC or command line level).
var synchronizationManager *synchronization.Manager

// testMainInternal is the internal testing entry point, needed so that shutdown
// operations can be deferred (since TestMain will invoke os.Exit). It copies
// the mutagen executable to a well-known path, sets up the agent bundle to work
// during testing, sets up a functionally complete daemon instance for testing,
// runs integration tests, and finally tears down all of the aforementioned
// infrastructure.
func testMainInternal(m *testing.M) (int, error) {
	// Disable logging.
	log.SetOutput(ioutil.Discard)

	// Override the expected agent bundle location.
	agent.ExpectedBundleLocation = agent.BundleLocationBuildDirectory

	// Acquire the daemon lock and defer its release.
	lock, err := daemon.AcquireLock()
	if err != nil {
		return -1, errors.Wrap(err, "unable to acquire daemon lock")
	}
	defer lock.Release()

	// Create a forwarding session manager and defer its shutdown.
	forwardingManager, err = forwarding.NewManager(logging.RootLogger.Sublogger("forwarding"))
	if err != nil {
		return -1, errors.Wrap(err, "unable to create forwarding session manager")
	}
	defer forwardingManager.Shutdown()

	// Create a session manager and defer its shutdown. Note that we assign to
	// the global instance here.
	synchronizationManager, err = synchronization.NewManager(logging.RootLogger.Sublogger("sync"))
	if err != nil {
		return -1, errors.Wrap(err, "unable to create synchronization session manager")
	}
	defer synchronizationManager.Shutdown()

	// Create the gRPC server and defer its stoppage. We use a hard stop rather
	// than a graceful stop so that it doesn't hang on open requests.
	server := grpc.NewServer(
		grpc.MaxSendMsgSize(grpcutil.MaximumMessageSize),
		grpc.MaxRecvMsgSize(grpcutil.MaximumMessageSize),
	)
	defer server.Stop()

	// Create and register the daemon service and defer its shutdown.
	daemonServer := daemonsvc.NewServer()
	daemonsvc.RegisterDaemonServer(server, daemonServer)
	defer daemonServer.Shutdown()

	// Create and register the prompt service.
	promptsvc.RegisterPromptingServer(server, promptsvc.NewServer())

	// Create and register the forwarding server.
	forwardingServer := forwardingsvc.NewServer(forwardingManager)
	forwardingsvc.RegisterForwardingServer(server, forwardingServer)

	// Create and register the session service.
	synchronizationServer := synchronizationsvc.NewServer(synchronizationManager)
	synchronizationsvc.RegisterSynchronizationServer(server, synchronizationServer)

	// Compute the path to the daemon IPC endpoint.
	endpoint, err := daemon.EndpointPath()
	if err != nil {
		return -1, errors.Wrap(err, "unable to compute endpoint path")
	}

	// Create the daemon listener and defer its closure. Since we hold the
	// daemon lock, we preemptively remove any existing socket since it (should)
	// be stale.
	os.Remove(endpoint)
	listener, err := ipc.NewListener(endpoint)
	if err != nil {
		return -1, errors.Wrap(err, "unable to create daemon listener")
	}
	defer listener.Close()

	// Serve incoming connections in a separate Goroutine. We don't monitor for
	// errors since there's nothing that we can do about them and because
	// they'll likely show up in the test output anyway.
	go server.Serve(listener)

	// Run tests.
	return m.Run(), nil
}

// TestMain is the entry point for integration tests (overriding the default
// generated entry point).
func TestMain(m *testing.M) {
	// Invoke the internal entry point. If there's an error, print it out before
	// exiting.
	result, err := testMainInternal(m)
	if err != nil {
		cmd.Error(err)
	}

	// Exit with the result.
	os.Exit(result)
}
<|endoftext|>