<commit_before>package coreapi_test

import (
	"context"
	"strings"
	"testing"

	opts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
)

func TestListSelf(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	keys, err := api.Key().List(ctx)
	if err != nil {
		t.Fatalf("failed to list keys: %s", err)
		return
	}

	if len(keys) != 1 {
		t.Fatalf("there should be 1 key (self), got %d", len(keys))
		return
	}

	if keys[0].Name() != "self" {
		t.Errorf("expected the key to be called 'self', got '%s'", keys[0].Name())
	}

	if keys[0].Path().String() != "/ipns/"+testPeerID {
		t.Errorf("expected the key to have path '/ipns/Qmfoo', got '%s'", keys[0].Path().String())
	}
}

func TestRenameSelf(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	_, _, err = api.Key().Rename(ctx, "self", "foo")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot rename key with name 'self'" {
			t.Fatalf("expected error 'cannot rename key with name 'self'', got '%s'", err.Error())
		}
	}

	_, _, err = api.Key().Rename(ctx, "self", "foo", api.Key().WithForce(true))
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot rename key with name 'self'" {
			t.Fatalf("expected error 'cannot rename key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestRemoveSelf(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	_, err = api.Key().Remove(ctx, "self")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot remove key with name 'self'" {
			t.Fatalf("expected error 'cannot remove key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestGenerate(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	k, err := api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	if k.Name() != "foo" {
		t.Errorf("expected the key to be called 'foo', got '%s'", k.Name())
	}

	if !strings.HasPrefix(k.Path().String(), "/ipns/Qm") {
		t.Errorf("expected the key to be prefixed with '/ipns/Qm', got '%s'", k.Path().String())
	}
}

func TestGenerateSize(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	k, err := api.Key().Generate(ctx, "foo", api.Key().WithSize(1024))
	if err != nil {
		t.Fatal(err)
		return
	}

	if k.Name() != "foo" {
		t.Errorf("expected the key to be called 'foo', got '%s'", k.Name())
	}

	if !strings.HasPrefix(k.Path().String(), "/ipns/Qm") {
		t.Errorf("expected the key to be prefixed with '/ipns/Qm', got '%s'", k.Path().String())
	}
}

func TestGenerateType(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	k, err := api.Key().Generate(ctx, "bar", api.Key().WithType(opts.Ed25519Key))
	if err != nil {
		t.Fatal(err)
		return
	}

	if k.Name() != "bar" {
		t.Errorf("expected the key to be called 'foo', got '%s'", k.Name())
	}

	if !strings.HasPrefix(k.Path().String(), "/ipns/Qm") {
		t.Errorf("expected the key to be prefixed with '/ipns/Qm', got '%s'", k.Path().String())
	}
}

func TestGenerateExisting(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "key with name 'foo' already exists" {
			t.Fatalf("expected error 'key with name 'foo' already exists', got '%s'", err.Error())
		}
	}

	_, err = api.Key().Generate(ctx, "self")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot overwrite key with name 'self'" {
			t.Fatalf("expected error 'cannot overwrite key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestList(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	l, err := api.Key().List(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	if len(l) != 2 {
		t.Fatalf("expected to get 2 keys, got %d", len(l))
		return
	}

	if l[0].Name() != "self" {
		t.Fatalf("expected key 0 to be called 'self', got '%s'", l[0].Name())
		return
	}

	if l[1].Name() != "foo" {
		t.Fatalf("expected key 1 to be called 'foo', got '%s'", l[1].Name())
		return
	}

	if !strings.HasPrefix(l[0].Path().String(), "/ipns/Qm") {
		t.Fatalf("expected key 0 to be prefixed with '/ipns/Qm', got '%s'", l[0].Name())
		return
	}

	if !strings.HasPrefix(l[1].Path().String(), "/ipns/Qm") {
		t.Fatalf("expected key 1 to be prefixed with '/ipns/Qm', got '%s'", l[1].Name())
		return
	}
}

func TestRename(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	k, overwrote, err := api.Key().Rename(ctx, "foo", "bar")
	if err != nil {
		t.Fatal(err)
		return
	}

	if overwrote {
		t.Error("overwrote should be false")
	}

	if k.Name() != "bar" {
		t.Errorf("returned key should be called 'bar', got '%s'", k.Name())
	}
}

func TestRenameToSelf(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, _, err = api.Key().Rename(ctx, "foo", "self")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot overwrite key with name 'self'" {
			t.Fatalf("expected error 'cannot overwrite key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestRenameToSelfForce(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, _, err = api.Key().Rename(ctx, "foo", "self", api.Key().WithForce(true))
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot overwrite key with name 'self'" {
			t.Fatalf("expected error 'cannot overwrite key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestRenameOverwriteNoForce(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, err = api.Key().Generate(ctx, "bar")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, _, err = api.Key().Rename(ctx, "foo", "bar")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "key by that name already exists, refusing to overwrite" {
			t.Fatalf("expected error 'key by that name already exists, refusing to overwrite', got '%s'", err.Error())
		}
	}
}

func TestRenameOverwrite(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	kfoo, err := api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, err = api.Key().Generate(ctx, "bar")
	if err != nil {
		t.Fatal(err)
		return
	}

	k, overwrote, err := api.Key().Rename(ctx, "foo", "bar", api.Key().WithForce(true))
	if err != nil {
		t.Fatal(err)
		return
	}

	if !overwrote {
		t.Error("overwrote should be true")
	}

	if k.Name() != "bar" {
		t.Errorf("returned key should be called 'bar', got '%s'", k.Name())
	}

	if k.Path().String() != kfoo.Path().String() {
		t.Errorf("k and kfoo should have equal paths, '%s'!='%s'", k.Path().String(), kfoo.Path().String())
	}
}

func TestRemove(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	k, err := api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	l, err := api.Key().List(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	if len(l) != 2 {
		t.Fatalf("expected to get 2 keys, got %d", len(l))
		return
	}

	p, err := api.Key().Remove(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	if k.Path().String() != p.String() {
		t.Errorf("k and p should have equal paths, '%s'!='%s'", k.Path().String(), p.String())
	}

	l, err = api.Key().List(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	if len(l) != 1 {
		t.Fatalf("expected to get 1 key, got %d", len(l))
		return
	}

	if l[0].Name() != "self" {
		t.Errorf("expected the key to be called 'self', got '%s'", l[0].Name())
	}
}
<commit_msg>fix error in test case<commit_after>package coreapi_test

import (
	"context"
	"strings"
	"testing"

	opts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
)

func TestListSelf(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	keys, err := api.Key().List(ctx)
	if err != nil {
		t.Fatalf("failed to list keys: %s", err)
		return
	}

	if len(keys) != 1 {
		t.Fatalf("there should be 1 key (self), got %d", len(keys))
		return
	}

	if keys[0].Name() != "self" {
		t.Errorf("expected the key to be called 'self', got '%s'", keys[0].Name())
	}

	if keys[0].Path().String() != "/ipns/"+testPeerID {
		t.Errorf("expected the key to have path '/ipns/%s', got '%s'", testPeerID, keys[0].Path().String())
	}
}

func TestRenameSelf(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	_, _, err = api.Key().Rename(ctx, "self", "foo")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot rename key with name 'self'" {
			t.Fatalf("expected error 'cannot rename key with name 'self'', got '%s'", err.Error())
		}
	}

	_, _, err = api.Key().Rename(ctx, "self", "foo", api.Key().WithForce(true))
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot rename key with name 'self'" {
			t.Fatalf("expected error 'cannot rename key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestRemoveSelf(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	_, err = api.Key().Remove(ctx, "self")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot remove key with name 'self'" {
			t.Fatalf("expected error 'cannot remove key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestGenerate(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	k, err := api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	if k.Name() != "foo" {
		t.Errorf("expected the key to be called 'foo', got '%s'", k.Name())
	}

	if !strings.HasPrefix(k.Path().String(), "/ipns/Qm") {
		t.Errorf("expected the key to be prefixed with '/ipns/Qm', got '%s'", k.Path().String())
	}
}

func TestGenerateSize(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	k, err := api.Key().Generate(ctx, "foo", api.Key().WithSize(1024))
	if err != nil {
		t.Fatal(err)
		return
	}

	if k.Name() != "foo" {
		t.Errorf("expected the key to be called 'foo', got '%s'", k.Name())
	}

	if !strings.HasPrefix(k.Path().String(), "/ipns/Qm") {
		t.Errorf("expected the key to be prefixed with '/ipns/Qm', got '%s'", k.Path().String())
	}
}

func TestGenerateType(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	k, err := api.Key().Generate(ctx, "bar", api.Key().WithType(opts.Ed25519Key))
	if err != nil {
		t.Fatal(err)
		return
	}

	if k.Name() != "bar" {
		t.Errorf("expected the key to be called 'foo', got '%s'", k.Name())
	}

	if !strings.HasPrefix(k.Path().String(), "/ipns/Qm") {
		t.Errorf("expected the key to be prefixed with '/ipns/Qm', got '%s'", k.Path().String())
	}
}

func TestGenerateExisting(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "key with name 'foo' already exists" {
			t.Fatalf("expected error 'key with name 'foo' already exists', got '%s'", err.Error())
		}
	}

	_, err = api.Key().Generate(ctx, "self")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot overwrite key with name 'self'" {
			t.Fatalf("expected error 'cannot overwrite key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestList(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	l, err := api.Key().List(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	if len(l) != 2 {
		t.Fatalf("expected to get 2 keys, got %d", len(l))
		return
	}

	if l[0].Name() != "self" {
		t.Fatalf("expected key 0 to be called 'self', got '%s'", l[0].Name())
		return
	}

	if l[1].Name() != "foo" {
		t.Fatalf("expected key 1 to be called 'foo', got '%s'", l[1].Name())
		return
	}

	if !strings.HasPrefix(l[0].Path().String(), "/ipns/Qm") {
		t.Fatalf("expected key 0 to be prefixed with '/ipns/Qm', got '%s'", l[0].Name())
		return
	}

	if !strings.HasPrefix(l[1].Path().String(), "/ipns/Qm") {
		t.Fatalf("expected key 1 to be prefixed with '/ipns/Qm', got '%s'", l[1].Name())
		return
	}
}

func TestRename(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	k, overwrote, err := api.Key().Rename(ctx, "foo", "bar")
	if err != nil {
		t.Fatal(err)
		return
	}

	if overwrote {
		t.Error("overwrote should be false")
	}

	if k.Name() != "bar" {
		t.Errorf("returned key should be called 'bar', got '%s'", k.Name())
	}
}

func TestRenameToSelf(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, _, err = api.Key().Rename(ctx, "foo", "self")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot overwrite key with name 'self'" {
			t.Fatalf("expected error 'cannot overwrite key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestRenameToSelfForce(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, _, err = api.Key().Rename(ctx, "foo", "self", api.Key().WithForce(true))
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "cannot overwrite key with name 'self'" {
			t.Fatalf("expected error 'cannot overwrite key with name 'self'', got '%s'", err.Error())
		}
	}
}

func TestRenameOverwriteNoForce(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	_, err = api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, err = api.Key().Generate(ctx, "bar")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, _, err = api.Key().Rename(ctx, "foo", "bar")
	if err == nil {
		t.Error("expected error to not be nil")
	} else {
		if err.Error() != "key by that name already exists, refusing to overwrite" {
			t.Fatalf("expected error 'key by that name already exists, refusing to overwrite', got '%s'", err.Error())
		}
	}
}

func TestRenameOverwrite(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	kfoo, err := api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	_, err = api.Key().Generate(ctx, "bar")
	if err != nil {
		t.Fatal(err)
		return
	}

	k, overwrote, err := api.Key().Rename(ctx, "foo", "bar", api.Key().WithForce(true))
	if err != nil {
		t.Fatal(err)
		return
	}

	if !overwrote {
		t.Error("overwrote should be true")
	}

	if k.Name() != "bar" {
		t.Errorf("returned key should be called 'bar', got '%s'", k.Name())
	}

	if k.Path().String() != kfoo.Path().String() {
		t.Errorf("k and kfoo should have equal paths, '%s'!='%s'", k.Path().String(), kfoo.Path().String())
	}
}

func TestRemove(t *testing.T) {
	ctx := context.Background()
	_, api, err := makeAPI(ctx)
	if err != nil {
		t.Error(err)
	}

	k, err := api.Key().Generate(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	l, err := api.Key().List(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	if len(l) != 2 {
		t.Fatalf("expected to get 2 keys, got %d", len(l))
		return
	}

	p, err := api.Key().Remove(ctx, "foo")
	if err != nil {
		t.Fatal(err)
		return
	}

	if k.Path().String() != p.String() {
		t.Errorf("k and p should have equal paths, '%s'!='%s'", k.Path().String(), p.String())
	}

	l, err = api.Key().List(ctx)
	if err != nil {
		t.Fatal(err)
		return
	}

	if len(l) != 1 {
		t.Fatalf("expected to get 1 key, got %d", len(l))
		return
	}

	if l[0].Name() != "self" {
		t.Errorf("expected the key to be called 'self', got '%s'", l[0].Name())
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 v1alpha2

// Annotation names for Secrets
const (
	AltNamesAnnotationKey    = "cert-manager.io/alt-names"
	IPSANAnnotationKey       = "cert-manager.io/ip-sans"
	URISANAnnotationKey      = "cert-manager.io/uri-sans"
	CommonNameAnnotationKey  = "cert-manager.io/common-name"
	IssuerNameAnnotationKey  = "cert-manager.io/issuer-name"
	IssuerKindAnnotationKey  = "cert-manager.io/issuer-kind"
	IssuerGroupAnnotationKey = "cert-manager.io/issuer-group"
	CertificateNameKey       = "cert-manager.io/certificate-name"
)

// Deprecated annotation names for Secrets
const (
	DeprecatedIssuerNameAnnotationKey = "certmanager.k8s.io/issuer-name"
	DeprecatedIssuerKindAnnotationKey = "certmanager.k8s.io/issuer-kind"
)

const (
	// issuerNameAnnotation can be used to override the issuer specified on the
	// created Certificate resource.
	IngressIssuerNameAnnotationKey = "cert-manager.io/issuer"
	// clusterIssuerNameAnnotation can be used to override the issuer specified on the
	// created Certificate resource. The Certificate will reference the
	// specified *ClusterIssuer* instead of normal issuer.
	IngressClusterIssuerNameAnnotationKey = "cert-manager.io/cluster-issuer"
	// acmeIssuerHTTP01IngressClassAnnotation can be used to override the http01 ingressClass
	// if the challenge type is set to http01
	IngressACMEIssuerHTTP01IngressClassAnnotationKey = "acme.cert-manager.io/http01-ingress-class"

	// IngressClassAnnotationKey picks a specific "class" for the Ingress. The
	// controller only processes Ingresses with this annotation either unset, or
	// set to either the configured value or the empty string.
	IngressClassAnnotationKey = "kubernetes.io/ingress.class"
)

// Annotation names for CertificateRequests
const (
	CRPrivateKeyAnnotationKey = "cert-manager.io/private-key-secret-name"

	// Annotation to declare the CertificateRequest "revision", beloning to a Certificate Resource
	CertificateRequestRevisionAnnotationKey = "cert-manager.io/certificate-revision"
)

const (
	// IssueTemporaryCertificateAnnotation is an annotation that can be added to
	// Certificate resources.
	// If it is present, a temporary internally signed certificate will be
	// stored in the target Secret resource whilst the real Issuer is processing
	// the certificate request.
	IssueTemporaryCertificateAnnotation = "cert-manager.io/issue-temporary-certificate"
)

const (
	ClusterIssuerKind      = "ClusterIssuer"
	IssuerKind             = "Issuer"
	CertificateKind        = "Certificate"
	CertificateRequestKind = "CertificateRequest"
)

const (
	// WantInjectAnnotation is the annotation that specifies that a particular
	// object wants injection of CAs.  It takes the form of a reference to a certificate
	// as namespace/name.  The certificate is expected to have the is-serving-for annotations.
	WantInjectAnnotation = "cert-manager.io/inject-ca-from"

	// WantInjectAPIServerCAAnnotation, if set to "true", will make the cainjector
	// inject the CA certificate for the Kubernetes apiserver into the resource.
	// It discovers the apiserver's CA by inspecting the service account credentials
	// mounted into the cainjector pod.
	WantInjectAPIServerCAAnnotation = "cert-manager.io/inject-apiserver-ca"

	// WantInjectFromSecretAnnotation is the annotation that specifies that a particular
	// object wants injection of CAs.  It takes the form of a reference to a Secret
	// as namespace/name.
	WantInjectFromSecretAnnotation = "cert-manager.io/inject-ca-from-secret"

	// AllowsInjectionFromSecretAnnotation is an annotation that must be added
	// to Secret resource that want to denote that they can be directly
	// injected into injectables that have a `inject-ca-from-secret` annotation.
	// If an injectable references a Secret that does NOT have this annotation,
	// the cainjector will refuse to inject the secret.
	AllowsInjectionFromSecretAnnotation = "cert-manager.io/allow-direct-injection"
)

// Issuer specific Annotations
const (
	// VenafiCustomFieldsAnnotationKey is the annotation that passes on JSON encoded custom fields to the Venafi issuer
	// This will only work with Venafi TPP v19.3 and higher
	// The value is an array with objects containing the name and value keys
	// for example: `[{"name": "custom-field", "value": "custom-value"}]`
	VenafiCustomFieldsAnnotationKey = "venafi.cert-manager.io/custom-fields"
)

// KeyUsage specifies valid usage contexts for keys.
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
// Valid KeyUsage values are as follows:
// "signing",
// "digital signature",
// "content commitment",
// "key encipherment",
// "key agreement",
// "data encipherment",
// "cert sign",
// "crl sign",
// "encipher only",
// "decipher only",
// "any",
// "server auth",
// "client auth",
// "code signing",
// "email protection",
// "s/mime",
// "ipsec end system",
// "ipsec tunnel",
// "ipsec user",
// "timestamping",
// "ocsp signing",
// "microsoft sgc",
// "netscape sgc"
// +kubebuilder:validation:Enum="signing";"digital signature";"content commitment";"key encipherment";"key agreement";"data encipherment";"cert sign";"crl sign";"encipher only";"decipher only";"any";"server auth";"client auth";"code signing";"email protection";"s/mime";"ipsec end system";"ipsec tunnel";"ipsec user";"timestamping";"ocsp signing";"microsoft sgc";"netscape sgc"
type KeyUsage string

const (
	UsageSigning            KeyUsage = "signing"
	UsageDigitalSignature   KeyUsage = "digital signature"
	UsageContentCommittment KeyUsage = "content commitment"
	UsageKeyEncipherment    KeyUsage = "key encipherment"
	UsageKeyAgreement       KeyUsage = "key agreement"
	UsageDataEncipherment   KeyUsage = "data encipherment"
	UsageCertSign           KeyUsage = "cert sign"
	UsageCRLSign            KeyUsage = "crl sign"
	UsageEncipherOnly       KeyUsage = "encipher only"
	UsageDecipherOnly       KeyUsage = "decipher only"
	UsageAny                KeyUsage = "any"
	UsageServerAuth         KeyUsage = "server auth"
	UsageClientAuth         KeyUsage = "client auth"
	UsageCodeSigning        KeyUsage = "code signing"
	UsageEmailProtection    KeyUsage = "email protection"
	UsageSMIME              KeyUsage = "s/mime"
	UsageIPsecEndSystem     KeyUsage = "ipsec end system"
	UsageIPsecTunnel        KeyUsage = "ipsec tunnel"
	UsageIPsecUser          KeyUsage = "ipsec user"
	UsageTimestamping       KeyUsage = "timestamping"
	UsageOCSPSigning        KeyUsage = "ocsp signing"
	UsageMicrosoftSGC       KeyUsage = "microsoft sgc"
	UsageNetscapeSGC        KeyUsage = "netscape sgc"
)

// DefaultKeyUsages contains the default list of key usages
func DefaultKeyUsages() []KeyUsage {
	// The serverAuth EKU is required as of Mac OS Catalina: https://support.apple.com/en-us/HT210176
	// Without this usage, certificates will _always_ flag a warning in newer Mac OS browsers.
	return []KeyUsage{UsageDigitalSignature, UsageKeyEncipherment, UsageServerAuth}
}
<commit_msg>Add IsNextPrivateKeySecretLabelKey const<commit_after>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 v1alpha2

// Annotation names for Secrets
const (
	AltNamesAnnotationKey          = "cert-manager.io/alt-names"
	IPSANAnnotationKey             = "cert-manager.io/ip-sans"
	URISANAnnotationKey            = "cert-manager.io/uri-sans"
	CommonNameAnnotationKey        = "cert-manager.io/common-name"
	IssuerNameAnnotationKey        = "cert-manager.io/issuer-name"
	IssuerKindAnnotationKey        = "cert-manager.io/issuer-kind"
	IssuerGroupAnnotationKey       = "cert-manager.io/issuer-group"
	CertificateNameKey             = "cert-manager.io/certificate-name"
	IsNextPrivateKeySecretLabelKey = "cert-manager.io/next-private-key"
)

// Deprecated annotation names for Secrets
const (
	DeprecatedIssuerNameAnnotationKey = "certmanager.k8s.io/issuer-name"
	DeprecatedIssuerKindAnnotationKey = "certmanager.k8s.io/issuer-kind"
)

const (
	// issuerNameAnnotation can be used to override the issuer specified on the
	// created Certificate resource.
	IngressIssuerNameAnnotationKey = "cert-manager.io/issuer"
	// clusterIssuerNameAnnotation can be used to override the issuer specified on the
	// created Certificate resource. The Certificate will reference the
	// specified *ClusterIssuer* instead of normal issuer.
	IngressClusterIssuerNameAnnotationKey = "cert-manager.io/cluster-issuer"
	// acmeIssuerHTTP01IngressClassAnnotation can be used to override the http01 ingressClass
	// if the challenge type is set to http01
	IngressACMEIssuerHTTP01IngressClassAnnotationKey = "acme.cert-manager.io/http01-ingress-class"

	// IngressClassAnnotationKey picks a specific "class" for the Ingress. The
	// controller only processes Ingresses with this annotation either unset, or
	// set to either the configured value or the empty string.
	IngressClassAnnotationKey = "kubernetes.io/ingress.class"
)

// Annotation names for CertificateRequests
const (
	CRPrivateKeyAnnotationKey = "cert-manager.io/private-key-secret-name"

	// Annotation to declare the CertificateRequest "revision", beloning to a Certificate Resource
	CertificateRequestRevisionAnnotationKey = "cert-manager.io/certificate-revision"
)

const (
	// IssueTemporaryCertificateAnnotation is an annotation that can be added to
	// Certificate resources.
	// If it is present, a temporary internally signed certificate will be
	// stored in the target Secret resource whilst the real Issuer is processing
	// the certificate request.
	IssueTemporaryCertificateAnnotation = "cert-manager.io/issue-temporary-certificate"
)

const (
	ClusterIssuerKind      = "ClusterIssuer"
	IssuerKind             = "Issuer"
	CertificateKind        = "Certificate"
	CertificateRequestKind = "CertificateRequest"
)

const (
	// WantInjectAnnotation is the annotation that specifies that a particular
	// object wants injection of CAs.  It takes the form of a reference to a certificate
	// as namespace/name.  The certificate is expected to have the is-serving-for annotations.
	WantInjectAnnotation = "cert-manager.io/inject-ca-from"

	// WantInjectAPIServerCAAnnotation, if set to "true", will make the cainjector
	// inject the CA certificate for the Kubernetes apiserver into the resource.
	// It discovers the apiserver's CA by inspecting the service account credentials
	// mounted into the cainjector pod.
	WantInjectAPIServerCAAnnotation = "cert-manager.io/inject-apiserver-ca"

	// WantInjectFromSecretAnnotation is the annotation that specifies that a particular
	// object wants injection of CAs.  It takes the form of a reference to a Secret
	// as namespace/name.
	WantInjectFromSecretAnnotation = "cert-manager.io/inject-ca-from-secret"

	// AllowsInjectionFromSecretAnnotation is an annotation that must be added
	// to Secret resource that want to denote that they can be directly
	// injected into injectables that have a `inject-ca-from-secret` annotation.
	// If an injectable references a Secret that does NOT have this annotation,
	// the cainjector will refuse to inject the secret.
	AllowsInjectionFromSecretAnnotation = "cert-manager.io/allow-direct-injection"
)

// Issuer specific Annotations
const (
	// VenafiCustomFieldsAnnotationKey is the annotation that passes on JSON encoded custom fields to the Venafi issuer
	// This will only work with Venafi TPP v19.3 and higher
	// The value is an array with objects containing the name and value keys
	// for example: `[{"name": "custom-field", "value": "custom-value"}]`
	VenafiCustomFieldsAnnotationKey = "venafi.cert-manager.io/custom-fields"
)

// KeyUsage specifies valid usage contexts for keys.
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
// Valid KeyUsage values are as follows:
// "signing",
// "digital signature",
// "content commitment",
// "key encipherment",
// "key agreement",
// "data encipherment",
// "cert sign",
// "crl sign",
// "encipher only",
// "decipher only",
// "any",
// "server auth",
// "client auth",
// "code signing",
// "email protection",
// "s/mime",
// "ipsec end system",
// "ipsec tunnel",
// "ipsec user",
// "timestamping",
// "ocsp signing",
// "microsoft sgc",
// "netscape sgc"
// +kubebuilder:validation:Enum="signing";"digital signature";"content commitment";"key encipherment";"key agreement";"data encipherment";"cert sign";"crl sign";"encipher only";"decipher only";"any";"server auth";"client auth";"code signing";"email protection";"s/mime";"ipsec end system";"ipsec tunnel";"ipsec user";"timestamping";"ocsp signing";"microsoft sgc";"netscape sgc"
type KeyUsage string

const (
	UsageSigning            KeyUsage = "signing"
	UsageDigitalSignature   KeyUsage = "digital signature"
	UsageContentCommittment KeyUsage = "content commitment"
	UsageKeyEncipherment    KeyUsage = "key encipherment"
	UsageKeyAgreement       KeyUsage = "key agreement"
	UsageDataEncipherment   KeyUsage = "data encipherment"
	UsageCertSign           KeyUsage = "cert sign"
	UsageCRLSign            KeyUsage = "crl sign"
	UsageEncipherOnly       KeyUsage = "encipher only"
	UsageDecipherOnly       KeyUsage = "decipher only"
	UsageAny                KeyUsage = "any"
	UsageServerAuth         KeyUsage = "server auth"
	UsageClientAuth         KeyUsage = "client auth"
	UsageCodeSigning        KeyUsage = "code signing"
	UsageEmailProtection    KeyUsage = "email protection"
	UsageSMIME              KeyUsage = "s/mime"
	UsageIPsecEndSystem     KeyUsage = "ipsec end system"
	UsageIPsecTunnel        KeyUsage = "ipsec tunnel"
	UsageIPsecUser          KeyUsage = "ipsec user"
	UsageTimestamping       KeyUsage = "timestamping"
	UsageOCSPSigning        KeyUsage = "ocsp signing"
	UsageMicrosoftSGC       KeyUsage = "microsoft sgc"
	UsageNetscapeSGC        KeyUsage = "netscape sgc"
)

// DefaultKeyUsages contains the default list of key usages
func DefaultKeyUsages() []KeyUsage {
	// The serverAuth EKU is required as of Mac OS Catalina: https://support.apple.com/en-us/HT210176
	// Without this usage, certificates will _always_ flag a warning in newer Mac OS browsers.
	return []KeyUsage{UsageDigitalSignature, UsageKeyEncipherment, UsageServerAuth}
}
<|endoftext|>


<commit_before>// +build !windows

package chrootarchive

import (
	gotar "archive/tar"
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"testing"

	"github.com/docker/docker/pkg/archive"
	"golang.org/x/sys/unix"
	"gotest.tools/v3/assert"
)

// Test for CVE-2018-15664
// Assures that in the case where an "attacker" controlled path is a symlink to
// some path outside of a container's rootfs that we do not copy data to a
// container path that will actually overwrite data on the host
func TestUntarWithMaliciousSymlinks(t *testing.T) {
	dir, err := ioutil.TempDir("", t.Name())
	assert.NilError(t, err)
	defer os.RemoveAll(dir)

	root := filepath.Join(dir, "root")

	err = os.MkdirAll(root, 0755)
	assert.NilError(t, err)

	// Add a file into a directory above root
	// Ensure that we can't access this file while tarring.
	err = ioutil.WriteFile(filepath.Join(dir, "host-file"), []byte("I am a host file"), 0644)
	assert.NilError(t, err)

	// Create some data which which will be copied into the "container" root into
	// the symlinked path.
	// Before this change, the copy would overwrite the "host" content.
	// With this change it should not.
	data := filepath.Join(dir, "data")
	err = os.MkdirAll(data, 0755)
	assert.NilError(t, err)
	err = ioutil.WriteFile(filepath.Join(data, "local-file"), []byte("pwn3d"), 0644)
	assert.NilError(t, err)

	safe := filepath.Join(root, "safe")
	err = unix.Symlink(dir, safe)
	assert.NilError(t, err)

	rdr, err := archive.TarWithOptions(data, &archive.TarOptions{IncludeFiles: []string{"local-file"}, RebaseNames: map[string]string{"local-file": "host-file"}})
	assert.NilError(t, err)

	// Use tee to test both the good case and the bad case w/o recreating the archive
	bufRdr := bytes.NewBuffer(nil)
	tee := io.TeeReader(rdr, bufRdr)

	err = UntarWithRoot(tee, safe, nil, root)
	assert.Assert(t, err != nil)
	assert.ErrorContains(t, err, "open /safe/host-file: no such file or directory")

	// Make sure the "host" file is still in tact
	// Before the fix the host file would be overwritten
	hostData, err := ioutil.ReadFile(filepath.Join(dir, "host-file"))
	assert.NilError(t, err)
	assert.Equal(t, string(hostData), "I am a host file")

	// Now test by chrooting to an attacker controlled path
	// This should succeed as is and overwrite a "host" file
	// Note that this would be a mis-use of this function.
	err = UntarWithRoot(bufRdr, safe, nil, safe)
	assert.NilError(t, err)

	hostData, err = ioutil.ReadFile(filepath.Join(dir, "host-file"))
	assert.NilError(t, err)
	assert.Equal(t, string(hostData), "pwn3d")
}

// Test for CVE-2018-15664
// Assures that in the case where an "attacker" controlled path is a symlink to
// some path outside of a container's rootfs that we do not unwittingly leak
// host data into the archive.
func TestTarWithMaliciousSymlinks(t *testing.T) {
	dir, err := ioutil.TempDir("", t.Name())
	assert.NilError(t, err)
	// defer os.RemoveAll(dir)
	t.Log(dir)

	root := filepath.Join(dir, "root")

	err = os.MkdirAll(root, 0755)
	assert.NilError(t, err)

	hostFileData := []byte("I am a host file")

	// Add a file into a directory above root
	// Ensure that we can't access this file while tarring.
	err = ioutil.WriteFile(filepath.Join(dir, "host-file"), hostFileData, 0644)
	assert.NilError(t, err)

	safe := filepath.Join(root, "safe")
	err = unix.Symlink(dir, safe)
	assert.NilError(t, err)

	data := filepath.Join(dir, "data")
	err = os.MkdirAll(data, 0755)
	assert.NilError(t, err)

	type testCase struct {
		p        string
		includes []string
	}

	cases := []testCase{
		{p: safe, includes: []string{"host-file"}},
		{p: safe + "/", includes: []string{"host-file"}},
		{p: safe, includes: nil},
		{p: safe + "/", includes: nil},
		{p: root, includes: []string{"safe/host-file"}},
		{p: root, includes: []string{"/safe/host-file"}},
		{p: root, includes: nil},
	}

	maxBytes := len(hostFileData)

	for _, tc := range cases {
		t.Run(path.Join(tc.p+"_"+strings.Join(tc.includes, "_")), func(t *testing.T) {
			// Here if we use archive.TarWithOptions directly or change the "root" parameter
			// to be the same as "safe", data from the host will be leaked into the archive
			var opts *archive.TarOptions
			if tc.includes != nil {
				opts = &archive.TarOptions{
					IncludeFiles: tc.includes,
				}
			}
			rdr, err := Tar(tc.p, opts, root)
			assert.NilError(t, err)
			defer rdr.Close()

			tr := gotar.NewReader(rdr)
			assert.Assert(t, !isDataInTar(t, tr, hostFileData, int64(maxBytes)), "host data leaked to archive")
		})
	}
}

func isDataInTar(t *testing.T, tr *gotar.Reader, compare []byte, maxBytes int64) bool {
	for {
		h, err := tr.Next()
		if err == io.EOF {
			break
		}
		assert.NilError(t, err)

		if h.Size == 0 {
			continue
		}
		assert.Assert(t, h.Size <= maxBytes, "%s: file size exceeds max expected size %d: %d", h.Name, maxBytes, h.Size)

		data := make([]byte, int(h.Size))
		_, err = io.ReadFull(tr, data)
		assert.NilError(t, err)
		if bytes.Contains(data, compare) {
			return true
		}
	}

	return false
}
<commit_msg>pkg/chrootarchive: Skip privileged tests when non-root<commit_after>// +build !windows

package chrootarchive

import (
	gotar "archive/tar"
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"testing"

	"github.com/docker/docker/pkg/archive"
	"golang.org/x/sys/unix"
	"gotest.tools/v3/assert"
	"gotest.tools/v3/skip"
)

// Test for CVE-2018-15664
// Assures that in the case where an "attacker" controlled path is a symlink to
// some path outside of a container's rootfs that we do not copy data to a
// container path that will actually overwrite data on the host
func TestUntarWithMaliciousSymlinks(t *testing.T) {
	skip.If(t, os.Getuid() != 0, "skipping test that requires root")
	dir, err := ioutil.TempDir("", t.Name())
	assert.NilError(t, err)
	defer os.RemoveAll(dir)

	root := filepath.Join(dir, "root")

	err = os.MkdirAll(root, 0755)
	assert.NilError(t, err)

	// Add a file into a directory above root
	// Ensure that we can't access this file while tarring.
	err = ioutil.WriteFile(filepath.Join(dir, "host-file"), []byte("I am a host file"), 0644)
	assert.NilError(t, err)

	// Create some data which which will be copied into the "container" root into
	// the symlinked path.
	// Before this change, the copy would overwrite the "host" content.
	// With this change it should not.
	data := filepath.Join(dir, "data")
	err = os.MkdirAll(data, 0755)
	assert.NilError(t, err)
	err = ioutil.WriteFile(filepath.Join(data, "local-file"), []byte("pwn3d"), 0644)
	assert.NilError(t, err)

	safe := filepath.Join(root, "safe")
	err = unix.Symlink(dir, safe)
	assert.NilError(t, err)

	rdr, err := archive.TarWithOptions(data, &archive.TarOptions{IncludeFiles: []string{"local-file"}, RebaseNames: map[string]string{"local-file": "host-file"}})
	assert.NilError(t, err)

	// Use tee to test both the good case and the bad case w/o recreating the archive
	bufRdr := bytes.NewBuffer(nil)
	tee := io.TeeReader(rdr, bufRdr)

	err = UntarWithRoot(tee, safe, nil, root)
	assert.Assert(t, err != nil)
	assert.ErrorContains(t, err, "open /safe/host-file: no such file or directory")

	// Make sure the "host" file is still in tact
	// Before the fix the host file would be overwritten
	hostData, err := ioutil.ReadFile(filepath.Join(dir, "host-file"))
	assert.NilError(t, err)
	assert.Equal(t, string(hostData), "I am a host file")

	// Now test by chrooting to an attacker controlled path
	// This should succeed as is and overwrite a "host" file
	// Note that this would be a mis-use of this function.
	err = UntarWithRoot(bufRdr, safe, nil, safe)
	assert.NilError(t, err)

	hostData, err = ioutil.ReadFile(filepath.Join(dir, "host-file"))
	assert.NilError(t, err)
	assert.Equal(t, string(hostData), "pwn3d")
}

// Test for CVE-2018-15664
// Assures that in the case where an "attacker" controlled path is a symlink to
// some path outside of a container's rootfs that we do not unwittingly leak
// host data into the archive.
func TestTarWithMaliciousSymlinks(t *testing.T) {
	skip.If(t, os.Getuid() != 0, "skipping test that requires root")
	dir, err := ioutil.TempDir("", t.Name())
	assert.NilError(t, err)
	// defer os.RemoveAll(dir)
	t.Log(dir)

	root := filepath.Join(dir, "root")

	err = os.MkdirAll(root, 0755)
	assert.NilError(t, err)

	hostFileData := []byte("I am a host file")

	// Add a file into a directory above root
	// Ensure that we can't access this file while tarring.
	err = ioutil.WriteFile(filepath.Join(dir, "host-file"), hostFileData, 0644)
	assert.NilError(t, err)

	safe := filepath.Join(root, "safe")
	err = unix.Symlink(dir, safe)
	assert.NilError(t, err)

	data := filepath.Join(dir, "data")
	err = os.MkdirAll(data, 0755)
	assert.NilError(t, err)

	type testCase struct {
		p        string
		includes []string
	}

	cases := []testCase{
		{p: safe, includes: []string{"host-file"}},
		{p: safe + "/", includes: []string{"host-file"}},
		{p: safe, includes: nil},
		{p: safe + "/", includes: nil},
		{p: root, includes: []string{"safe/host-file"}},
		{p: root, includes: []string{"/safe/host-file"}},
		{p: root, includes: nil},
	}

	maxBytes := len(hostFileData)

	for _, tc := range cases {
		t.Run(path.Join(tc.p+"_"+strings.Join(tc.includes, "_")), func(t *testing.T) {
			// Here if we use archive.TarWithOptions directly or change the "root" parameter
			// to be the same as "safe", data from the host will be leaked into the archive
			var opts *archive.TarOptions
			if tc.includes != nil {
				opts = &archive.TarOptions{
					IncludeFiles: tc.includes,
				}
			}
			rdr, err := Tar(tc.p, opts, root)
			assert.NilError(t, err)
			defer rdr.Close()

			tr := gotar.NewReader(rdr)
			assert.Assert(t, !isDataInTar(t, tr, hostFileData, int64(maxBytes)), "host data leaked to archive")
		})
	}
}

func isDataInTar(t *testing.T, tr *gotar.Reader, compare []byte, maxBytes int64) bool {
	for {
		h, err := tr.Next()
		if err == io.EOF {
			break
		}
		assert.NilError(t, err)

		if h.Size == 0 {
			continue
		}
		assert.Assert(t, h.Size <= maxBytes, "%s: file size exceeds max expected size %d: %d", h.Name, maxBytes, h.Size)

		data := make([]byte, int(h.Size))
		_, err = io.ReadFull(tr, data)
		assert.NilError(t, err)
		if bytes.Contains(data, compare) {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package wikifier

type tocBlock struct {
	*parserBlock
}

func newTocBlock(name string, b *parserBlock) block {
	return &tocBlock{b}
}

func (toc *tocBlock) html(page *Page, el element) {

	// don't show the toc if there are <2 on the page
	blocks := page.main.blockContent()
	if len(blocks) < 2 {
		el.hide()
	}

	el.setTag("ul")
	el.addHTML(HTML("
Contents
"))

	// add each top-level section
	for _, child := range blocks {
		if sec, ok := child.(*secBlock); ok {
			tocAdd(sec, el, page)
		}
	}
}

func tocAdd(sec *secBlock, addTo element, page *Page) {

	// create an item for this section
	var subList element
	if !sec.isIntro {
		li := addTo.createChild("li", "")
		a := li.createChild("a", "link-internal")
		a.setAttr("href", "#"+sec.headingID)
		a.addHTML(page.formatTextOpts(sec.title, fmtOpt{pos: sec.openPos}))
		addTo = li
	} else {
		subList = addTo
	}

	// create a sub-list for each section underneath
	for _, child := range sec.blockContent() {
		if secChild, ok := child.(*secBlock); ok {
			if subList == nil {
				subList = addTo.createChild("ul", "")
			}
			tocAdd(secChild, subList, page)
		}
	}
}
<commit_msg>only count sections, not just any block<commit_after>package wikifier

type tocBlock struct {
	*parserBlock
}

func newTocBlock(name string, b *parserBlock) block {
	return &tocBlock{b}
}

func (toc *tocBlock) html(page *Page, el element) {
	secCount := 0
	el.setTag("ul")
	el.addHTML(HTML("
Contents
"))

	// add each top-level section
	for _, child := range page.main.blockContent() {
		if sec, ok := child.(*secBlock); ok {
			tocAdd(sec, el, page)
			secCount++
		}
	}

	// don't show the toc if there are <2 on the page
	if secCount < 2 {
		el.hide()
	}
}

func tocAdd(sec *secBlock, addTo element, page *Page) {

	// create an item for this section
	var subList element
	if !sec.isIntro {
		li := addTo.createChild("li", "")
		a := li.createChild("a", "link-internal")
		a.setAttr("href", "#"+sec.headingID)
		a.addHTML(page.formatTextOpts(sec.title, fmtOpt{pos: sec.openPos}))
		addTo = li
	} else {
		subList = addTo
	}

	// create a sub-list for each section underneath
	for _, child := range sec.blockContent() {
		if secChild, ok := child.(*secBlock); ok {
			if subList == nil {
				subList = addTo.createChild("ul", "")
			}
			tocAdd(secChild, subList, page)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. 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 metrics

import (
	"fmt"
	"testing"
	"time"

	"github.com/NVIDIA/gpu-monitoring-tools/bindings/go/nvml"
	"github.com/prometheus/client_golang/prometheus/testutil"
	//"github.com/golang/glog"
)

func uint64Ptr(u uint64) *uint64 {
	return &u
}

func stringPtr(u string) *string {
	return &u
}

type mockCollector struct{}

func (t *mockCollector) collectGPUDevice(deviceName string) (*nvml.Device, error) {
	return gpuDevicesMock[deviceName], nil
}

func (t *mockCollector) collectStatus(d *nvml.Device) (status *nvml.DeviceStatus, err error) {
	return deviceToStatus[d], nil
}

func (t *mockCollector) collectDutyCycle(uuid string, since time.Duration) (uint, error) {
	dutyCycle, ok := dutyCycleMock[uuid]
	if !ok {
		return 0, fmt.Errorf("duty cycle for %s not found", uuid)
	}
	return dutyCycle, nil
}

var (
	containerDevicesMock = map[ContainerID][]string{
		{
			namespace: "default",
			pod:       "pod1",
			container: "container1",
		}: {
			"q759757",
		},
		{
			namespace: "non-default",
			pod:       "pod2",
			container: "container2",
		}: {
			"afjodaj",
			"7v89zhi",
		},
	}

	device1 = &nvml.Device{
		UUID:   "656547758",
		Model:  stringPtr("model1"),
		Memory: uint64Ptr(200),
	}
	device2 = &nvml.Device{
		UUID:   "850729563",
		Model:  stringPtr("model2"),
		Memory: uint64Ptr(200),
	}
	device3 = &nvml.Device{
		UUID:   "3572375710",
		Model:  stringPtr("model1"),
		Memory: uint64Ptr(350),
	}

	gpuDevicesMock = map[string]*nvml.Device{
		"q759757": device1,
		"afjodaj": device2,
		"7v89zhi": device3,
	}
	deviceToStatus = map[*nvml.Device]*nvml.DeviceStatus{
		device1: &nvml.DeviceStatus{
			Memory: nvml.MemoryInfo{
				Global: nvml.DeviceMemory{
					Used: uint64Ptr(50),
				},
			},
		},
		device2: &nvml.DeviceStatus{
			Memory: nvml.MemoryInfo{
				Global: nvml.DeviceMemory{
					Used: uint64Ptr(150),
				},
			},
		},
		device3: &nvml.DeviceStatus{
			Memory: nvml.MemoryInfo{
				Global: nvml.DeviceMemory{
					Used: uint64Ptr(100),
				},
			},
		},
	}

	dutyCycleMock = map[string]uint{
		"656547758":  78,
		"850729563":  32,
		"3572375710": 13,
	}
)

func TestMetricsUpdate(t *testing.T) {
	g = &mockCollector{}
	ms := MetricServer{}
	ms.updateMetrics(containerDevicesMock)

	if testutil.ToFloat64(
		AcceleratorRequests.WithLabelValues(
			"default", "pod1", "container1", gpuResourceName)) != 1 ||
		testutil.ToFloat64(
			AcceleratorRequests.WithLabelValues(
				"non-default", "pod2", "container2", gpuResourceName)) != 2 {
		t.Fatalf("Wrong Result in AcceleratorRequsets")
	}

	if testutil.ToFloat64(
		DutyCycle.WithLabelValues(
			"default", "pod1", "container1", "nvidia", "656547758", "model1")) != 78 ||
		testutil.ToFloat64(
			DutyCycle.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "850729563", "model2")) != 32 ||
		testutil.ToFloat64(
			DutyCycle.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "3572375710", "model1")) != 13 {
		t.Fatalf("Wrong Result in DutyCycle")
	}

	if testutil.ToFloat64(
		MemoryTotal.WithLabelValues(
			"default", "pod1", "container1", "nvidia", "656547758", "model1")) != 200*1024*1024 ||
		testutil.ToFloat64(
			MemoryTotal.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "850729563", "model2")) != 200*1024*1024 ||
		testutil.ToFloat64(
			MemoryTotal.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "3572375710", "model1")) != 350*1024*1024 {
		t.Fatalf("Wrong Result in MemoryTotal")
	}

	if testutil.ToFloat64(
		MemoryUsed.WithLabelValues(
			"default", "pod1", "container1", "nvidia", "656547758", "model1")) != 50*1024*1024 ||
		testutil.ToFloat64(
			MemoryUsed.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "850729563", "model2")) != 150*1024*1024 ||
		testutil.ToFloat64(
			MemoryUsed.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "3572375710", "model1")) != 100*1024*1024 {
		t.Fatalf("Wrong Result in MemoryTotal")
	}

}
<commit_msg>format<commit_after>// Copyright 2017 Google Inc. 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 metrics

import (
	"fmt"
	"testing"
	"time"

	"github.com/NVIDIA/gpu-monitoring-tools/bindings/go/nvml"
	"github.com/prometheus/client_golang/prometheus/testutil"
	//"github.com/golang/glog"
)

func uint64Ptr(u uint64) *uint64 {
	return &u
}

func stringPtr(u string) *string {
	return &u
}

type mockCollector struct{}

func (t *mockCollector) collectGPUDevice(deviceName string) (*nvml.Device, error) {
	return gpuDevicesMock[deviceName], nil
}

func (t *mockCollector) collectStatus(d *nvml.Device) (status *nvml.DeviceStatus, err error) {
	return deviceToStatus[d], nil
}

func (t *mockCollector) collectDutyCycle(uuid string, since time.Duration) (uint, error) {
	dutyCycle, ok := dutyCycleMock[uuid]
	if !ok {
		return 0, fmt.Errorf("duty cycle for %s not found", uuid)
	}
	return dutyCycle, nil
}

var (
	containerDevicesMock = map[ContainerID][]string{
		{
			namespace: "default",
			pod:       "pod1",
			container: "container1",
		}: {
			"q759757",
		},
		{
			namespace: "non-default",
			pod:       "pod2",
			container: "container2",
		}: {
			"afjodaj",
			"7v89zhi",
		},
	}

	device1 = &nvml.Device{
		UUID:   "656547758",
		Model:  stringPtr("model1"),
		Memory: uint64Ptr(200),
	}
	device2 = &nvml.Device{
		UUID:   "850729563",
		Model:  stringPtr("model2"),
		Memory: uint64Ptr(200),
	}
	device3 = &nvml.Device{
		UUID:   "3572375710",
		Model:  stringPtr("model1"),
		Memory: uint64Ptr(350),
	}

	gpuDevicesMock = map[string]*nvml.Device{
		"q759757": device1,
		"afjodaj": device2,
		"7v89zhi": device3,
	}
	deviceToStatus = map[*nvml.Device]*nvml.DeviceStatus{
		device1: {
			Memory: nvml.MemoryInfo{
				Global: nvml.DeviceMemory{
					Used: uint64Ptr(50),
				},
			},
		},
		device2: {
			Memory: nvml.MemoryInfo{
				Global: nvml.DeviceMemory{
					Used: uint64Ptr(150),
				},
			},
		},
		device3: {
			Memory: nvml.MemoryInfo{
				Global: nvml.DeviceMemory{
					Used: uint64Ptr(100),
				},
			},
		},
	}

	dutyCycleMock = map[string]uint{
		"656547758":  78,
		"850729563":  32,
		"3572375710": 13,
	}
)

func TestMetricsUpdate(t *testing.T) {
	g = &mockCollector{}
	ms := MetricServer{}
	ms.updateMetrics(containerDevicesMock)

	if testutil.ToFloat64(
		AcceleratorRequests.WithLabelValues(
			"default", "pod1", "container1", gpuResourceName)) != 1 ||
		testutil.ToFloat64(
			AcceleratorRequests.WithLabelValues(
				"non-default", "pod2", "container2", gpuResourceName)) != 2 {
		t.Fatalf("Wrong Result in AcceleratorRequsets")
	}

	if testutil.ToFloat64(
		DutyCycle.WithLabelValues(
			"default", "pod1", "container1", "nvidia", "656547758", "model1")) != 78 ||
		testutil.ToFloat64(
			DutyCycle.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "850729563", "model2")) != 32 ||
		testutil.ToFloat64(
			DutyCycle.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "3572375710", "model1")) != 13 {
		t.Fatalf("Wrong Result in DutyCycle")
	}

	if testutil.ToFloat64(
		MemoryTotal.WithLabelValues(
			"default", "pod1", "container1", "nvidia", "656547758", "model1")) != 200*1024*1024 ||
		testutil.ToFloat64(
			MemoryTotal.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "850729563", "model2")) != 200*1024*1024 ||
		testutil.ToFloat64(
			MemoryTotal.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "3572375710", "model1")) != 350*1024*1024 {
		t.Fatalf("Wrong Result in MemoryTotal")
	}

	if testutil.ToFloat64(
		MemoryUsed.WithLabelValues(
			"default", "pod1", "container1", "nvidia", "656547758", "model1")) != 50*1024*1024 ||
		testutil.ToFloat64(
			MemoryUsed.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "850729563", "model2")) != 150*1024*1024 ||
		testutil.ToFloat64(
			MemoryUsed.WithLabelValues(
				"non-default", "pod2", "container2", "nvidia", "3572375710", "model1")) != 100*1024*1024 {
		t.Fatalf("Wrong Result in MemoryTotal")
	}

}
<|endoftext|>


<commit_before>package sql

import (
	"lambda.sx/marcus/lambdago/settings"
	"log"
	"upper.io/db"
	"upper.io/db/mysql"
)

var sqlConn db.Database = nil

func Init() {
	sess, err := db.Open(mysql.Adapter, settings.DBSettings())
	if err != nil {
		log.Fatalf("SQL connection failed! %q\n", err)
		defer Shutdown()
	} else {
		sqlConn = sess
	}
}

func Shutdown() {
	sqlConn.Close()
}

func Connection() db.Database {
	return sqlConn
}
<commit_msg>Create tables on start<commit_after>package sql

import (
	"lambda.sx/marcus/lambdago/settings"
	"log"
	"upper.io/db"
	"upper.io/db/mysql"
)

var sqlConn db.Database = nil

func Init() {
	sess, err := db.Open(mysql.Adapter, settings.DBSettings())
	if err != nil {
		log.Fatalf("SQL connection failed! %q\n", err)
		defer Shutdown()
	} else {
		sqlConn = sess
		createTables()
	}
}

func Shutdown() {
	sqlConn.Close()
}

func Connection() db.Database {
	return sqlConn
}

func createTables() {
	driver = sqlConn.Driver().(*sql.DB)
	driver.Query("CREATE TABLE IF NOT EXISTS users (username VARCHAR(32), password VARCHAR(64), creation_date Date)")
}
<|endoftext|>


<commit_before>// +build cgo,linux

/*
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 cadvisor

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/google/cadvisor/cache/memory"
	cadvisormetrics "github.com/google/cadvisor/container"
	"github.com/google/cadvisor/events"
	cadvisorapi "github.com/google/cadvisor/info/v1"
	cadvisorapiv2 "github.com/google/cadvisor/info/v2"
	"github.com/google/cadvisor/manager"
	"github.com/google/cadvisor/utils/sysfs"
	"k8s.io/klog"
)

type cadvisorClient struct {
	imageFsInfoProvider ImageFsInfoProvider
	rootPath            string
	manager.Manager
}

var _ Interface = new(cadvisorClient)

// TODO(vmarmol): Make configurable.
// The amount of time for which to keep stats in memory.
const statsCacheDuration = 2 * time.Minute
const maxHousekeepingInterval = 15 * time.Second
const defaultHousekeepingInterval = 10 * time.Second
const allowDynamicHousekeeping = true

func init() {
	// Override cAdvisor flag defaults.
	flagOverrides := map[string]string{
		// Override the default cAdvisor housekeeping interval.
		"housekeeping_interval": defaultHousekeepingInterval.String(),
		// Disable event storage by default.
		"event_storage_event_limit": "default=0",
		"event_storage_age_limit":   "default=0",
	}
	for name, defaultValue := range flagOverrides {
		if f := flag.Lookup(name); f != nil {
			f.DefValue = defaultValue
			f.Value.Set(defaultValue)
		} else {
			klog.Errorf("Expected cAdvisor flag %q not found", name)
		}
	}
}

func New(imageFsInfoProvider ImageFsInfoProvider, rootPath string, usingLegacyStats bool) (Interface, error) {
	sysFs := sysfs.NewRealSysFs()

	includedMetrics := cadvisormetrics.MetricSet{
		cadvisormetrics.CpuUsageMetrics:         struct{}{},
		cadvisormetrics.MemoryUsageMetrics:      struct{}{},
		cadvisormetrics.CpuLoadMetrics:          struct{}{},
		cadvisormetrics.DiskIOMetrics:           struct{}{},
		cadvisormetrics.NetworkUsageMetrics:     struct{}{},
		cadvisormetrics.AcceleratorUsageMetrics: struct{}{},
		cadvisormetrics.AppMetrics:              struct{}{},
	}
	if usingLegacyStats {
		includedMetrics[cadvisormetrics.DiskUsageMetrics] = struct{}{}
	}

	// collect metrics for all cgroups
	rawContainerCgroupPathPrefixWhiteList := []string{"/"}
	// Create and start the cAdvisor container manager.
	m, err := manager.New(memory.New(statsCacheDuration, nil), sysFs, maxHousekeepingInterval, allowDynamicHousekeeping, includedMetrics, http.DefaultClient, rawContainerCgroupPathPrefixWhiteList)
	if err != nil {
		return nil, err
	}

	if _, err := os.Stat(rootPath); err != nil {
		if os.IsNotExist(err) {
			if err := os.MkdirAll(path.Clean(rootPath), 0750); err != nil {
				return nil, fmt.Errorf("error creating root directory %q: %v", rootPath, err)
			}
		} else {
			return nil, fmt.Errorf("failed to Stat %q: %v", rootPath, err)
		}
	}

	cadvisorClient := &cadvisorClient{
		imageFsInfoProvider: imageFsInfoProvider,
		rootPath:            rootPath,
		Manager:             m,
	}

	return cadvisorClient, nil
}

func (cc *cadvisorClient) Start() error {
	return cc.Manager.Start()
}

func (cc *cadvisorClient) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) {
	return cc.GetContainerInfo(name, req)
}

func (cc *cadvisorClient) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
	return cc.GetContainerInfoV2(name, options)
}

func (cc *cadvisorClient) VersionInfo() (*cadvisorapi.VersionInfo, error) {
	return cc.GetVersionInfo()
}

func (cc *cadvisorClient) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
	infos, err := cc.SubcontainersInfo(name, req)
	if err != nil && len(infos) == 0 {
		return nil, err
	}

	result := make(map[string]*cadvisorapi.ContainerInfo, len(infos))
	for _, info := range infos {
		result[info.Name] = info
	}
	return result, err
}

func (cc *cadvisorClient) MachineInfo() (*cadvisorapi.MachineInfo, error) {
	return cc.GetMachineInfo()
}

func (cc *cadvisorClient) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
	label, err := cc.imageFsInfoProvider.ImageFsInfoLabel()
	if err != nil {
		return cadvisorapiv2.FsInfo{}, err
	}
	return cc.getFsInfo(label)
}

func (cc *cadvisorClient) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
	return cc.GetDirFsInfo(cc.rootPath)
}

func (cc *cadvisorClient) getFsInfo(label string) (cadvisorapiv2.FsInfo, error) {
	res, err := cc.GetFsInfo(label)
	if err != nil {
		return cadvisorapiv2.FsInfo{}, err
	}
	if len(res) == 0 {
		return cadvisorapiv2.FsInfo{}, fmt.Errorf("failed to find information for the filesystem labeled %q", label)
	}
	// TODO(vmarmol): Handle this better when a label has more than one image filesystem.
	if len(res) > 1 {
		klog.Warningf("More than one filesystem labeled %q: %#v. Only using the first one", label, res)
	}

	return res[0], nil
}

func (cc *cadvisorClient) WatchEvents(request *events.Request) (*events.EventChannel, error) {
	return cc.WatchForEvents(request)
}
<commit_msg>Adjust our use of cadvisor to pull in just runtimes we need<commit_after>// +build cgo,linux

/*
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 cadvisor

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"path"
	"time"

	_ "github.com/google/cadvisor/container/containerd/install"
	_ "github.com/google/cadvisor/container/crio/install"
	_ "github.com/google/cadvisor/container/docker/install"
	_ "github.com/google/cadvisor/container/systemd/install"

	"github.com/google/cadvisor/cache/memory"
	cadvisormetrics "github.com/google/cadvisor/container"
	"github.com/google/cadvisor/events"
	cadvisorapi "github.com/google/cadvisor/info/v1"
	cadvisorapiv2 "github.com/google/cadvisor/info/v2"
	"github.com/google/cadvisor/manager"
	"github.com/google/cadvisor/utils/sysfs"
	"k8s.io/klog"
)

type cadvisorClient struct {
	imageFsInfoProvider ImageFsInfoProvider
	rootPath            string
	manager.Manager
}

var _ Interface = new(cadvisorClient)

// TODO(vmarmol): Make configurable.
// The amount of time for which to keep stats in memory.
const statsCacheDuration = 2 * time.Minute
const maxHousekeepingInterval = 15 * time.Second
const defaultHousekeepingInterval = 10 * time.Second
const allowDynamicHousekeeping = true

func init() {
	// Override cAdvisor flag defaults.
	flagOverrides := map[string]string{
		// Override the default cAdvisor housekeeping interval.
		"housekeeping_interval": defaultHousekeepingInterval.String(),
		// Disable event storage by default.
		"event_storage_event_limit": "default=0",
		"event_storage_age_limit":   "default=0",
	}
	for name, defaultValue := range flagOverrides {
		if f := flag.Lookup(name); f != nil {
			f.DefValue = defaultValue
			f.Value.Set(defaultValue)
		} else {
			klog.Errorf("Expected cAdvisor flag %q not found", name)
		}
	}
}

func New(imageFsInfoProvider ImageFsInfoProvider, rootPath string, usingLegacyStats bool) (Interface, error) {
	sysFs := sysfs.NewRealSysFs()

	includedMetrics := cadvisormetrics.MetricSet{
		cadvisormetrics.CpuUsageMetrics:         struct{}{},
		cadvisormetrics.MemoryUsageMetrics:      struct{}{},
		cadvisormetrics.CpuLoadMetrics:          struct{}{},
		cadvisormetrics.DiskIOMetrics:           struct{}{},
		cadvisormetrics.NetworkUsageMetrics:     struct{}{},
		cadvisormetrics.AcceleratorUsageMetrics: struct{}{},
		cadvisormetrics.AppMetrics:              struct{}{},
	}
	if usingLegacyStats {
		includedMetrics[cadvisormetrics.DiskUsageMetrics] = struct{}{}
	}

	// collect metrics for all cgroups
	rawContainerCgroupPathPrefixWhiteList := []string{"/"}
	// Create and start the cAdvisor container manager.
	m, err := manager.New(memory.New(statsCacheDuration, nil), sysFs, maxHousekeepingInterval, allowDynamicHousekeeping, includedMetrics, http.DefaultClient, rawContainerCgroupPathPrefixWhiteList)
	if err != nil {
		return nil, err
	}

	if _, err := os.Stat(rootPath); err != nil {
		if os.IsNotExist(err) {
			if err := os.MkdirAll(path.Clean(rootPath), 0750); err != nil {
				return nil, fmt.Errorf("error creating root directory %q: %v", rootPath, err)
			}
		} else {
			return nil, fmt.Errorf("failed to Stat %q: %v", rootPath, err)
		}
	}

	cadvisorClient := &cadvisorClient{
		imageFsInfoProvider: imageFsInfoProvider,
		rootPath:            rootPath,
		Manager:             m,
	}

	return cadvisorClient, nil
}

func (cc *cadvisorClient) Start() error {
	return cc.Manager.Start()
}

func (cc *cadvisorClient) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) {
	return cc.GetContainerInfo(name, req)
}

func (cc *cadvisorClient) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
	return cc.GetContainerInfoV2(name, options)
}

func (cc *cadvisorClient) VersionInfo() (*cadvisorapi.VersionInfo, error) {
	return cc.GetVersionInfo()
}

func (cc *cadvisorClient) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
	infos, err := cc.SubcontainersInfo(name, req)
	if err != nil && len(infos) == 0 {
		return nil, err
	}

	result := make(map[string]*cadvisorapi.ContainerInfo, len(infos))
	for _, info := range infos {
		result[info.Name] = info
	}
	return result, err
}

func (cc *cadvisorClient) MachineInfo() (*cadvisorapi.MachineInfo, error) {
	return cc.GetMachineInfo()
}

func (cc *cadvisorClient) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
	label, err := cc.imageFsInfoProvider.ImageFsInfoLabel()
	if err != nil {
		return cadvisorapiv2.FsInfo{}, err
	}
	return cc.getFsInfo(label)
}

func (cc *cadvisorClient) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
	return cc.GetDirFsInfo(cc.rootPath)
}

func (cc *cadvisorClient) getFsInfo(label string) (cadvisorapiv2.FsInfo, error) {
	res, err := cc.GetFsInfo(label)
	if err != nil {
		return cadvisorapiv2.FsInfo{}, err
	}
	if len(res) == 0 {
		return cadvisorapiv2.FsInfo{}, fmt.Errorf("failed to find information for the filesystem labeled %q", label)
	}
	// TODO(vmarmol): Handle this better when a label has more than one image filesystem.
	if len(res) > 1 {
		klog.Warningf("More than one filesystem labeled %q: %#v. Only using the first one", label, res)
	}

	return res[0], nil
}

func (cc *cadvisorClient) WatchEvents(request *events.Request) (*events.EventChannel, error) {
	return cc.WatchForEvents(request)
}
<|endoftext|>


<commit_before>package fs

import (
	"io/ioutil"
	"path/filepath"
	"strings"

	"github.com/dotcloud/docker/pkg/libcontainer/cgroups"
)

type freezerGroup struct {
}

func (s *freezerGroup) Set(d *data) error {
	dir, err := d.join("freezer")
	if err != nil {
		if err != cgroups.ErrNotFound {
			return err
		}
		return nil
	}

	if d.c.Freezer != cgroups.Undefined {
		if err := writeFile(dir, "freezer.state", string(d.c.Freezer)); err != nil {
			return err
		}
	}

	return nil
}

func (s *freezerGroup) Remove(d *data) error {
	return removePath(d.path("freezer"))
}

func getFreezerFileData(path string) (string, error) {
	data, err := ioutil.ReadFile(path)
	return strings.TrimSuffix(string(data), "\n"), err
}

func (s *freezerGroup) GetStats(d *data, stats *cgroups.Stats) error {
	path, err := d.path("freezer")
	if err != nil {
		return err
	}
	var data string
	if data, err = getFreezerFileData(filepath.Join(path, "freezer.parent_freezing")); err != nil {
		return err
	}
	stats.FreezerStats.ParentState = data
	if data, err = getFreezerFileData(filepath.Join(path, "freezer.self_freezing")); err != nil {
		return err
	}
	stats.FreezerStats.SelfState = data

	return nil
}
<commit_msg>Don't rejoin the cgroup each time Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)<commit_after>package fs

import (
	"io/ioutil"
	"path/filepath"
	"strings"

	"github.com/dotcloud/docker/pkg/libcontainer/cgroups"
)

type freezerGroup struct {
}

func (s *freezerGroup) Set(d *data) error {
	switch d.c.Freezer {
	case cgroups.Frozen, cgroups.Thawed:
		dir, err := d.path("freezer")
		if err != nil {
			return err
		}

		if err := writeFile(dir, "freezer.state", string(d.c.Freezer)); err != nil {
			return err
		}
	default:
		if _, err := d.join("freezer"); err != nil && err != cgroups.ErrNotFound {
			return err
		}
	}

	return nil
}

func (s *freezerGroup) Remove(d *data) error {
	return removePath(d.path("freezer"))
}

func getFreezerFileData(path string) (string, error) {
	data, err := ioutil.ReadFile(path)
	return strings.TrimSuffix(string(data), "\n"), err
}

func (s *freezerGroup) GetStats(d *data, stats *cgroups.Stats) error {
	path, err := d.path("freezer")
	if err != nil {
		return err
	}
	var data string
	if data, err = getFreezerFileData(filepath.Join(path, "freezer.parent_freezing")); err != nil {
		return err
	}
	stats.FreezerStats.ParentState = data
	if data, err = getFreezerFileData(filepath.Join(path, "freezer.self_freezing")); err != nil {
		return err
	}
	stats.FreezerStats.SelfState = data

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 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 gcemodel

import (
	"fmt"
	"strings"

	"k8s.io/klog/v2"
	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/model"
	"k8s.io/kops/pkg/model/defaults"
	"k8s.io/kops/pkg/model/iam"
	nodeidentitygce "k8s.io/kops/pkg/nodeidentity/gce"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/cloudup/gce"
	"k8s.io/kops/upup/pkg/fi/cloudup/gce/gcemetadata"
	"k8s.io/kops/upup/pkg/fi/cloudup/gcetasks"
)

const (
	DefaultVolumeType = "pd-standard"
)

// TODO: rework these parts to be more GCE native. ie: Managed Instance Groups > ASGs
// AutoscalingGroupModelBuilder configures AutoscalingGroup objects
type AutoscalingGroupModelBuilder struct {
	*GCEModelContext

	BootstrapScriptBuilder *model.BootstrapScriptBuilder
	Lifecycle              fi.Lifecycle
}

var _ fi.ModelBuilder = &AutoscalingGroupModelBuilder{}

// Build the GCE instance template object for an InstanceGroup
// We are then able to extract out the fields when running with the clusterapi.
func (b *AutoscalingGroupModelBuilder) buildInstanceTemplate(c *fi.ModelBuilderContext, ig *kops.InstanceGroup, subnet *kops.ClusterSubnetSpec) (*gcetasks.InstanceTemplate, error) {
	// Indented to keep diff manageable
	// TODO: Remove spurious indent
	{
		var err error
		name := b.SafeObjectName(ig.ObjectMeta.Name)

		startupScript, err := b.BootstrapScriptBuilder.ResourceNodeUp(c, ig)
		if err != nil {
			return nil, err
		}

		{
			volumeSize := fi.Int32Value(ig.Spec.RootVolumeSize)
			if volumeSize == 0 {
				volumeSize, err = defaults.DefaultInstanceGroupVolumeSize(ig.Spec.Role)
				if err != nil {
					return nil, err
				}
			}
			volumeType := fi.StringValue(ig.Spec.RootVolumeType)
			if volumeType == "" {
				volumeType = DefaultVolumeType
			}

			namePrefix := gce.LimitedLengthName(name, gcetasks.InstanceTemplateNamePrefixMaxLength)
			network, err := b.LinkToNetwork()
			if err != nil {
				return nil, err
			}
			t := &gcetasks.InstanceTemplate{
				Name:           s(name),
				NamePrefix:     s(namePrefix),
				Lifecycle:      b.Lifecycle,
				Network:        network,
				MachineType:    s(ig.Spec.MachineType),
				BootDiskType:   s(volumeType),
				BootDiskSizeGB: i64(int64(volumeSize)),
				BootDiskImage:  s(ig.Spec.Image),

				// TODO: Support preemptible nodes?
				Preemptible: fi.Bool(false),

				HasExternalIP: fi.Bool(b.Cluster.Spec.Topology.Masters == kops.TopologyPublic),

				Scopes: []string{
					"compute-rw",
					"monitoring",
					"logging-write",
				},
				Metadata: map[string]fi.Resource{
					"startup-script": startupScript,
					//"config": resources/config.yaml $nodeset.Name
					gcemetadata.MetadataKeyClusterName:           fi.NewStringResource(b.ClusterName()),
					nodeidentitygce.MetadataKeyInstanceGroupName: fi.NewStringResource(ig.Name),
				},
			}

			nodeRole, err := iam.BuildNodeRoleSubject(ig.Spec.Role, false)
			if err != nil {
				return nil, err
			}

			storagePaths, err := iam.WriteableVFSPaths(b.Cluster, nodeRole)
			if err != nil {
				return nil, err
			}
			if len(storagePaths) == 0 {
				t.Scopes = append(t.Scopes, "storage-ro")
			} else {
				klog.Warningf("enabling storage-rw for etcd backups")
				t.Scopes = append(t.Scopes, "storage-rw")
			}

			if len(b.SSHPublicKeys) > 0 {
				var gFmtKeys []string
				for _, key := range b.SSHPublicKeys {
					gFmtKeys = append(gFmtKeys, fmt.Sprintf("%s: %s", fi.SecretNameSSHPrimary, key))
				}

				t.Metadata["ssh-keys"] = fi.NewStringResource(strings.Join(gFmtKeys, "\n"))
			}

			switch ig.Spec.Role {
			case kops.InstanceGroupRoleMaster:
				// Grant DNS permissions
				// TODO: migrate to IAM permissions instead of oldschool scopes?
				t.Scopes = append(t.Scopes, "https://www.googleapis.com/auth/ndev.clouddns.readwrite")
				t.Tags = append(t.Tags, b.GCETagForRole(kops.InstanceGroupRoleMaster))

			case kops.InstanceGroupRoleNode:
				t.Tags = append(t.Tags, b.GCETagForRole(kops.InstanceGroupRoleNode))
			}
			roleLabel := gce.GceLabelNameRolePrefix + gce.EncodeGCELabel(strings.ToLower(string(ig.Spec.Role)))
			t.Labels = map[string]string{
				gce.GceLabelNameKubernetesCluster: gce.SafeClusterName(b.ClusterName()),
				roleLabel:                         "",
				gce.GceLabelNameInstanceGroup:     name,
			}

			if gce.UsesIPAliases(b.Cluster) {
				t.CanIPForward = fi.Bool(false)

				t.AliasIPRanges = map[string]string{
					b.NameForIPAliasRange("pods"): "/24",
				}
			} else {
				t.CanIPForward = fi.Bool(true)
			}
			t.Subnet = b.LinkToSubnet(subnet)

			t.ServiceAccounts = append(t.ServiceAccounts, b.LinkToServiceAccount(ig))

			//labels, err := b.CloudTagsForInstanceGroup(ig)
			//if err != nil {
			//	return fmt.Errorf("error building cloud tags: %v", err)
			//}
			//t.Labels = labels

			return t, nil
		}
	}
}

func (b *AutoscalingGroupModelBuilder) splitToZones(ig *kops.InstanceGroup) (map[string]int, error) {
	// Indented to keep diff manageable
	// TODO: Remove spurious indent
	{
		// AutoscalingGroup
		zones, err := b.FindZonesForInstanceGroup(ig)
		if err != nil {
			return nil, err
		}

		// TODO: Duplicated from aws - move to defaults?
		minSize := 1
		if ig.Spec.MinSize != nil {
			minSize = int(fi.Int32Value(ig.Spec.MinSize))
		} else if ig.Spec.Role == kops.InstanceGroupRoleNode {
			minSize = 2
		}

		// We have to assign instances to the various zones
		// TODO: Switch to regional managed instance group
		// But we can't yet use RegionInstanceGroups:
		// 1) no support in terraform
		// 2) we can't steer to specific zones AFAICT, only to all zones in the region

		targetSizes := make([]int, len(zones))
		totalSize := 0
		for i := range zones {
			targetSizes[i] = minSize / len(zones)
			totalSize += targetSizes[i]
		}
		i := 0
		for {
			if totalSize >= minSize {
				break
			}
			targetSizes[i]++
			totalSize++

			i++
			if i > len(targetSizes) {
				i = 0
			}
		}

		instanceCountByZone := make(map[string]int)
		for i, zone := range zones {
			instanceCountByZone[zone] = targetSizes[i]
		}
		return instanceCountByZone, nil
	}
}

func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
	for _, ig := range b.InstanceGroups {
		subnets, err := b.GatherSubnets(ig)
		if err != nil {
			return err
		}

		// On GCE, instance groups cannot have multiple subnets.
		// Because subnets are regional on GCE, this should not be limiting.
		// (IGs can in theory support multiple zones, but in practice we don't recommend this)
		if len(subnets) != 1 {
			return fmt.Errorf("instanceGroup %q has multiple subnets", ig.Name)
		}
		subnet := subnets[0]

		instanceTemplate, err := b.buildInstanceTemplate(c, ig, subnet)
		if err != nil {
			return err
		}
		c.AddTask(instanceTemplate)

		instanceCountByZone, err := b.splitToZones(ig)
		if err != nil {
			return err
		}

		for zone, targetSize := range instanceCountByZone {
			name := gce.NameForInstanceGroupManager(b.Cluster, ig, zone)

			t := &gcetasks.InstanceGroupManager{
				Name:             s(name),
				Lifecycle:        b.Lifecycle,
				Zone:             s(zone),
				TargetSize:       fi.Int64(int64(targetSize)),
				BaseInstanceName: s(ig.ObjectMeta.Name),
				InstanceTemplate: instanceTemplate,
			}

			// Attach masters to load balancer if we're using one
			switch ig.Spec.Role {
			case kops.InstanceGroupRoleMaster:
				if b.UseLoadBalancerForAPI() {
					lbSpec := b.Cluster.Spec.API.LoadBalancer
					if lbSpec != nil {
						switch lbSpec.Type {
						case kops.LoadBalancerTypePublic:
							t.TargetPools = append(t.TargetPools, b.LinkToTargetPool("api"))
						case kops.LoadBalancerTypeInternal:
							klog.Warningf("Not hooking the instance group manager up to anything.")
						}
					}
				}
			}

			c.AddTask(t)
		}
	}

	return nil
}
<commit_msg>Limit GCE ASG labels to 63 chars<commit_after>/*
Copyright 2019 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 gcemodel

import (
	"fmt"
	"strings"

	"k8s.io/klog/v2"
	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/model"
	"k8s.io/kops/pkg/model/defaults"
	"k8s.io/kops/pkg/model/iam"
	nodeidentitygce "k8s.io/kops/pkg/nodeidentity/gce"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/cloudup/gce"
	"k8s.io/kops/upup/pkg/fi/cloudup/gce/gcemetadata"
	"k8s.io/kops/upup/pkg/fi/cloudup/gcetasks"
)

const (
	DefaultVolumeType = "pd-standard"
)

// TODO: rework these parts to be more GCE native. ie: Managed Instance Groups > ASGs
// AutoscalingGroupModelBuilder configures AutoscalingGroup objects
type AutoscalingGroupModelBuilder struct {
	*GCEModelContext

	BootstrapScriptBuilder *model.BootstrapScriptBuilder
	Lifecycle              fi.Lifecycle
}

var _ fi.ModelBuilder = &AutoscalingGroupModelBuilder{}

// Build the GCE instance template object for an InstanceGroup
// We are then able to extract out the fields when running with the clusterapi.
func (b *AutoscalingGroupModelBuilder) buildInstanceTemplate(c *fi.ModelBuilderContext, ig *kops.InstanceGroup, subnet *kops.ClusterSubnetSpec) (*gcetasks.InstanceTemplate, error) {
	// Indented to keep diff manageable
	// TODO: Remove spurious indent
	{
		var err error
		name := b.SafeObjectName(ig.ObjectMeta.Name)

		startupScript, err := b.BootstrapScriptBuilder.ResourceNodeUp(c, ig)
		if err != nil {
			return nil, err
		}

		{
			volumeSize := fi.Int32Value(ig.Spec.RootVolumeSize)
			if volumeSize == 0 {
				volumeSize, err = defaults.DefaultInstanceGroupVolumeSize(ig.Spec.Role)
				if err != nil {
					return nil, err
				}
			}
			volumeType := fi.StringValue(ig.Spec.RootVolumeType)
			if volumeType == "" {
				volumeType = DefaultVolumeType
			}

			namePrefix := gce.LimitedLengthName(name, gcetasks.InstanceTemplateNamePrefixMaxLength)
			network, err := b.LinkToNetwork()
			if err != nil {
				return nil, err
			}
			t := &gcetasks.InstanceTemplate{
				Name:           s(name),
				NamePrefix:     s(namePrefix),
				Lifecycle:      b.Lifecycle,
				Network:        network,
				MachineType:    s(ig.Spec.MachineType),
				BootDiskType:   s(volumeType),
				BootDiskSizeGB: i64(int64(volumeSize)),
				BootDiskImage:  s(ig.Spec.Image),

				// TODO: Support preemptible nodes?
				Preemptible: fi.Bool(false),

				HasExternalIP: fi.Bool(b.Cluster.Spec.Topology.Masters == kops.TopologyPublic),

				Scopes: []string{
					"compute-rw",
					"monitoring",
					"logging-write",
				},
				Metadata: map[string]fi.Resource{
					"startup-script": startupScript,
					//"config": resources/config.yaml $nodeset.Name
					gcemetadata.MetadataKeyClusterName:           fi.NewStringResource(b.ClusterName()),
					nodeidentitygce.MetadataKeyInstanceGroupName: fi.NewStringResource(ig.Name),
				},
			}

			nodeRole, err := iam.BuildNodeRoleSubject(ig.Spec.Role, false)
			if err != nil {
				return nil, err
			}

			storagePaths, err := iam.WriteableVFSPaths(b.Cluster, nodeRole)
			if err != nil {
				return nil, err
			}
			if len(storagePaths) == 0 {
				t.Scopes = append(t.Scopes, "storage-ro")
			} else {
				klog.Warningf("enabling storage-rw for etcd backups")
				t.Scopes = append(t.Scopes, "storage-rw")
			}

			if len(b.SSHPublicKeys) > 0 {
				var gFmtKeys []string
				for _, key := range b.SSHPublicKeys {
					gFmtKeys = append(gFmtKeys, fmt.Sprintf("%s: %s", fi.SecretNameSSHPrimary, key))
				}

				t.Metadata["ssh-keys"] = fi.NewStringResource(strings.Join(gFmtKeys, "\n"))
			}

			switch ig.Spec.Role {
			case kops.InstanceGroupRoleMaster:
				// Grant DNS permissions
				// TODO: migrate to IAM permissions instead of oldschool scopes?
				t.Scopes = append(t.Scopes, "https://www.googleapis.com/auth/ndev.clouddns.readwrite")
				t.Tags = append(t.Tags, b.GCETagForRole(kops.InstanceGroupRoleMaster))

			case kops.InstanceGroupRoleNode:
				t.Tags = append(t.Tags, b.GCETagForRole(kops.InstanceGroupRoleNode))
			}
			roleLabel := gce.GceLabelNameRolePrefix + gce.EncodeGCELabel(strings.ToLower(string(ig.Spec.Role)))
			t.Labels = map[string]string{
				gce.GceLabelNameKubernetesCluster: gce.SafeClusterName(b.ClusterName()),
				roleLabel:                         "",
				gce.GceLabelNameInstanceGroup:     ig.ObjectMeta.Name,
			}

			if gce.UsesIPAliases(b.Cluster) {
				t.CanIPForward = fi.Bool(false)

				t.AliasIPRanges = map[string]string{
					b.NameForIPAliasRange("pods"): "/24",
				}
			} else {
				t.CanIPForward = fi.Bool(true)
			}
			t.Subnet = b.LinkToSubnet(subnet)

			t.ServiceAccounts = append(t.ServiceAccounts, b.LinkToServiceAccount(ig))

			//labels, err := b.CloudTagsForInstanceGroup(ig)
			//if err != nil {
			//	return fmt.Errorf("error building cloud tags: %v", err)
			//}
			//t.Labels = labels

			return t, nil
		}
	}
}

func (b *AutoscalingGroupModelBuilder) splitToZones(ig *kops.InstanceGroup) (map[string]int, error) {
	// Indented to keep diff manageable
	// TODO: Remove spurious indent
	{
		// AutoscalingGroup
		zones, err := b.FindZonesForInstanceGroup(ig)
		if err != nil {
			return nil, err
		}

		// TODO: Duplicated from aws - move to defaults?
		minSize := 1
		if ig.Spec.MinSize != nil {
			minSize = int(fi.Int32Value(ig.Spec.MinSize))
		} else if ig.Spec.Role == kops.InstanceGroupRoleNode {
			minSize = 2
		}

		// We have to assign instances to the various zones
		// TODO: Switch to regional managed instance group
		// But we can't yet use RegionInstanceGroups:
		// 1) no support in terraform
		// 2) we can't steer to specific zones AFAICT, only to all zones in the region

		targetSizes := make([]int, len(zones))
		totalSize := 0
		for i := range zones {
			targetSizes[i] = minSize / len(zones)
			totalSize += targetSizes[i]
		}
		i := 0
		for {
			if totalSize >= minSize {
				break
			}
			targetSizes[i]++
			totalSize++

			i++
			if i > len(targetSizes) {
				i = 0
			}
		}

		instanceCountByZone := make(map[string]int)
		for i, zone := range zones {
			instanceCountByZone[zone] = targetSizes[i]
		}
		return instanceCountByZone, nil
	}
}

func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
	for _, ig := range b.InstanceGroups {
		subnets, err := b.GatherSubnets(ig)
		if err != nil {
			return err
		}

		// On GCE, instance groups cannot have multiple subnets.
		// Because subnets are regional on GCE, this should not be limiting.
		// (IGs can in theory support multiple zones, but in practice we don't recommend this)
		if len(subnets) != 1 {
			return fmt.Errorf("instanceGroup %q has multiple subnets", ig.Name)
		}
		subnet := subnets[0]

		instanceTemplate, err := b.buildInstanceTemplate(c, ig, subnet)
		if err != nil {
			return err
		}
		c.AddTask(instanceTemplate)

		instanceCountByZone, err := b.splitToZones(ig)
		if err != nil {
			return err
		}

		for zone, targetSize := range instanceCountByZone {
			name := gce.NameForInstanceGroupManager(b.Cluster, ig, zone)

			t := &gcetasks.InstanceGroupManager{
				Name:             s(name),
				Lifecycle:        b.Lifecycle,
				Zone:             s(zone),
				TargetSize:       fi.Int64(int64(targetSize)),
				BaseInstanceName: s(ig.ObjectMeta.Name),
				InstanceTemplate: instanceTemplate,
			}

			// Attach masters to load balancer if we're using one
			switch ig.Spec.Role {
			case kops.InstanceGroupRoleMaster:
				if b.UseLoadBalancerForAPI() {
					lbSpec := b.Cluster.Spec.API.LoadBalancer
					if lbSpec != nil {
						switch lbSpec.Type {
						case kops.LoadBalancerTypePublic:
							t.TargetPools = append(t.TargetPools, b.LinkToTargetPool("api"))
						case kops.LoadBalancerTypeInternal:
							klog.Warningf("Not hooking the instance group manager up to anything.")
						}
					}
				}
			}

			c.AddTask(t)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package collector

import (
	"time"

	"github.com/prometheus/client_golang/prometheus"
)

var (
	backgroundFlushingflushesTotal = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "flushes_total",
		Help:      "flushes is a counter that collects the number of times the database has flushed all writes to disk. This value will grow as database runs for longer periods of time",
	})
	backgroundFlushingtotalMilliseconds = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "total_milliseconds",
		Help:      "The total_ms value provides the total number of milliseconds (ms) that the mongod processes have spent writing (i.e. flushing) data to disk. Because this is an absolute value, consider the value offlushes and average_ms to provide better context for this datum",
	})
	backgroundFlushingaverageMilliseconds = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "average_milliseconds",
		Help:      `The average_ms value describes the relationship between the number of flushes and the total amount of time that the database has spent writing data to disk. The larger flushes is, the more likely this value is likely to represent a "normal," time; however, abnormal data can skew this value`,
	})
	backgroundFlushinglastMilliseconds = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "last_milliseconds",
		Help:      "The value of the last_ms field is the amount of time, in milliseconds, that the last flush operation took to complete. Use this value to verify that the current performance of the server and is in line with the historical data provided by average_ms and total_ms",
	})
	backgroundFlushinglastFinishedTime = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "last_finished_time",
		Help:      "The last_finished field provides a timestamp of the last completed flush operation in the ISODateformat. If this value is more than a few minutes old relative to your server’s current time and accounting for differences in time zone, restarting the database may result in some data loss",
	})
)

// FlushStats is the flush stats metrics
type FlushStats struct {
	Flushes      float64   `bson:"flushes"`
	TotalMs      float64   `bson:"total_ms"`
	AverageMs    float64   `bson:"average_ms"`
	LastMs       float64   `bson:"last_ms"`
	LastFinished time.Time `bson:"last_finished"`
}

// Export exports the metrics for prometheus.
func (flushStats *FlushStats) Export(ch chan<- prometheus.Metric) {
	backgroundFlushingflushesTotal.Set(flushStats.Flushes)
	backgroundFlushingtotalMilliseconds.Set(flushStats.TotalMs)
	backgroundFlushingaverageMilliseconds.Set(flushStats.AverageMs)
	backgroundFlushinglastMilliseconds.Set(flushStats.LastMs)
	backgroundFlushinglastFinishedTime.Set(float64(flushStats.LastFinished.Unix()))

	backgroundFlushingflushesTotal.Collect(ch)
	backgroundFlushingtotalMilliseconds.Collect(ch)
	backgroundFlushingaverageMilliseconds.Collect(ch)
	backgroundFlushinglastMilliseconds.Collect(ch)
	backgroundFlushinglastFinishedTime.Collect(ch)
}

// Describe describes the metrics for prometheus
func (flushStats *FlushStats) Describe(ch chan<- *prometheus.Desc) {
	backgroundFlushingflushesTotal.Describe(ch)
	backgroundFlushingtotalMilliseconds.Describe(ch)
	backgroundFlushingaverageMilliseconds.Describe(ch)
	backgroundFlushinglastMilliseconds.Describe(ch)
	backgroundFlushinglastFinishedTime.Describe(ch)
}
<commit_msg>fixed unprintable character on /metrics<commit_after>package collector

import (
	"time"

	"github.com/prometheus/client_golang/prometheus"
)

var (
	backgroundFlushingflushesTotal = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "flushes_total",
		Help:      "flushes is a counter that collects the number of times the database has flushed all writes to disk. This value will grow as database runs for longer periods of time",
	})
	backgroundFlushingtotalMilliseconds = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "total_milliseconds",
		Help:      "The total_ms value provides the total number of milliseconds (ms) that the mongod processes have spent writing (i.e. flushing) data to disk. Because this is an absolute value, consider the value offlushes and average_ms to provide better context for this datum",
	})
	backgroundFlushingaverageMilliseconds = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "average_milliseconds",
		Help:      `The average_ms value describes the relationship between the number of flushes and the total amount of time that the database has spent writing data to disk. The larger flushes is, the more likely this value is likely to represent a "normal," time; however, abnormal data can skew this value`,
	})
	backgroundFlushinglastMilliseconds = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "last_milliseconds",
		Help:      "The value of the last_ms field is the amount of time, in milliseconds, that the last flush operation took to complete. Use this value to verify that the current performance of the server and is in line with the historical data provided by average_ms and total_ms",
	})
	backgroundFlushinglastFinishedTime = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: Namespace,
		Subsystem: "background_flushing",
		Name:      "last_finished_time",
		Help:      "The last_finished field provides a timestamp of the last completed flush operation in the ISODateformat. If this value is more than a few minutes old relative to your server's current time and accounting for differences in time zone, restarting the database may result in some data loss",
	})
)

// FlushStats is the flush stats metrics
type FlushStats struct {
	Flushes      float64   `bson:"flushes"`
	TotalMs      float64   `bson:"total_ms"`
	AverageMs    float64   `bson:"average_ms"`
	LastMs       float64   `bson:"last_ms"`
	LastFinished time.Time `bson:"last_finished"`
}

// Export exports the metrics for prometheus.
func (flushStats *FlushStats) Export(ch chan<- prometheus.Metric) {
	backgroundFlushingflushesTotal.Set(flushStats.Flushes)
	backgroundFlushingtotalMilliseconds.Set(flushStats.TotalMs)
	backgroundFlushingaverageMilliseconds.Set(flushStats.AverageMs)
	backgroundFlushinglastMilliseconds.Set(flushStats.LastMs)
	backgroundFlushinglastFinishedTime.Set(float64(flushStats.LastFinished.Unix()))

	backgroundFlushingflushesTotal.Collect(ch)
	backgroundFlushingtotalMilliseconds.Collect(ch)
	backgroundFlushingaverageMilliseconds.Collect(ch)
	backgroundFlushinglastMilliseconds.Collect(ch)
	backgroundFlushinglastFinishedTime.Collect(ch)
}

// Describe describes the metrics for prometheus
func (flushStats *FlushStats) Describe(ch chan<- *prometheus.Desc) {
	backgroundFlushingflushesTotal.Describe(ch)
	backgroundFlushingtotalMilliseconds.Describe(ch)
	backgroundFlushingaverageMilliseconds.Describe(ch)
	backgroundFlushinglastMilliseconds.Describe(ch)
	backgroundFlushinglastFinishedTime.Describe(ch)
}
<|endoftext|>