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

package kmeans_test

import (
	"code.google.com/p/biogo.cluster"
	"code.google.com/p/biogo.cluster/kmeans"
	check "launchpad.net/gocheck"
	"math/rand"
	"strings"
	"testing"
)

func Test(t *testing.T) { check.TestingT(t) }

type S struct{}

func (s *S) TearDownSuite(_ *check.C) { rand.Seed(1) } // Reset the seed for the example test.

var _ = check.Suite(&S{})

var (
	seq = []*Feature{
		{ID: "0", Start: 0, End: 100},
		{ID: "1", Start: 100, End: 200},
		{ID: "2", Start: 200, End: 300},
		{ID: "3", Start: 300, End: 400},
		{ID: "4", Start: 400, End: 500},
		{ID: "5", Start: 500, End: 600},
		{ID: "6", Start: 600, End: 700},
		{ID: "7", Start: 700, End: 800},
		{ID: "8", Start: 800, End: 900},
		{ID: "9", Start: 900, End: 1000},
	}
	tests = []struct {
		set     []*Feature
		epsilon float64
		effort  int

		clusters []cluster.Indices

		// results determined with R
		total  int
		within []float64
	}{
		{
			feats,
			0.15, 5,
			[]cluster.Indices{{0, 1}, {2, 3, 4, 5}, {6, 7}, {8, 9, 10}},
			4747787,
			[]float64{0.5, 15820.75, 2500, 3829.3333333333335},
		},
		{
			feats,
			0.1, 5,
			[]cluster.Indices{{8, 9, 10}, {0, 1}, {6}, {2, 3, 4}, {5}, {7}},
			4747787,
			[]float64{3829.3333333333335, 0.5, 0, 52, 0, 0},
		},
		{
			seq,
			0.2, 5,
			[]cluster.Indices{{3}, {7}, {9}, {1}, {6}, {0}, {5}, {4}, {8}, {2}},
			1650000,
			[]float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		},
		{
			seq,
			1, 5,
			[]cluster.Indices{{4, 5}, {2, 3}, {8, 9}, {0, 1}, {6, 7}},
			1650000,
			[]float64{10000, 10000, 10000, 10000, 10000},
		},
	}
)

// Tests
func (s *S) TestKmeans(c *check.C) {
	for i, t := range tests {
		rand.Seed(1)
		km := ClusterFeatures(t.set, t.epsilon, t.effort)
		clusters := km.Clusters()
		c.Logf("Test %d: epsilon = %.2f effort = %d", i, t.epsilon, t.effort)
		for ci, cl := range clusters {
			c.Logf("Cluster %d:", ci)
			for _, j := range cl {
				f := t.set[j]
				c.Logf("%2s %s%s",
					f.ID,
					strings.Repeat(" ", f.Start/20),
					strings.Repeat("-", f.Len()/20),
				)
			}
		}
		c.Log()
		c.Check(clusters, check.DeepEquals, t.clusters)
		c.Check(int(km.Total()), check.Equals, t.total)
		c.Check(km.Within(), check.DeepEquals, t.within)
	}
}

type bench [][2]float64

func (b bench) Len() int                    { return len(b) }
func (b bench) Values(i int) (x, y float64) { return float64(b[i][0]), float64(b[i][1]) }

var benchData bench = func() bench {
	b := make(bench, 0, 100000)
	for i := 0; i < 20; i++ {
		x, y := float64(rand.Intn(10000)), float64(rand.Intn(10000))
		r := float64(rand.Intn(200))
		for j := 0; j < 5000; j++ {
			b = append(b, [2]float64{x + r*rand.NormFloat64(), y + r*rand.NormFloat64()})
		}
	}
	return b
}()

func Benchmark(b *testing.B) {
	km := kmeans.New(benchData)
	km.Seed(20)
	for i := 0; i < b.N; i++ {
		km.Cluster()
	}
	_ = km.Clusters()
}
<commit_msg>More efficient use of resources<commit_after>// Copyright ©2012 The bíogo.cluster Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package kmeans_test

import (
	"code.google.com/p/biogo.cluster"
	"code.google.com/p/biogo.cluster/kmeans"
	check "launchpad.net/gocheck"
	"math/rand"
	"strings"
	"testing"
)

func Test(t *testing.T) { check.TestingT(t) }

type S struct{}

func (s *S) TearDownSuite(_ *check.C) { rand.Seed(1) } // Reset the seed for the example test.

var _ = check.Suite(&S{})

var (
	seq = []*Feature{
		{ID: "0", Start: 0, End: 100},
		{ID: "1", Start: 100, End: 200},
		{ID: "2", Start: 200, End: 300},
		{ID: "3", Start: 300, End: 400},
		{ID: "4", Start: 400, End: 500},
		{ID: "5", Start: 500, End: 600},
		{ID: "6", Start: 600, End: 700},
		{ID: "7", Start: 700, End: 800},
		{ID: "8", Start: 800, End: 900},
		{ID: "9", Start: 900, End: 1000},
	}
	tests = []struct {
		set     []*Feature
		epsilon float64
		effort  int

		clusters []cluster.Indices

		// results determined with R
		total  int
		within []float64
	}{
		{
			feats,
			0.15, 5,
			[]cluster.Indices{{0, 1}, {2, 3, 4, 5}, {6, 7}, {8, 9, 10}},
			4747787,
			[]float64{0.5, 15820.75, 2500, 3829.3333333333335},
		},
		{
			feats,
			0.1, 5,
			[]cluster.Indices{{8, 9, 10}, {0, 1}, {6}, {2, 3, 4}, {5}, {7}},
			4747787,
			[]float64{3829.3333333333335, 0.5, 0, 52, 0, 0},
		},
		{
			seq,
			0.2, 5,
			[]cluster.Indices{{3}, {7}, {9}, {1}, {6}, {0}, {5}, {4}, {8}, {2}},
			1650000,
			[]float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		},
		{
			seq,
			1, 5,
			[]cluster.Indices{{4, 5}, {2, 3}, {8, 9}, {0, 1}, {6, 7}},
			1650000,
			[]float64{10000, 10000, 10000, 10000, 10000},
		},
	}
)

// Tests
func (s *S) TestKmeans(c *check.C) {
	for i, t := range tests {
		rand.Seed(1)
		km := ClusterFeatures(t.set, t.epsilon, t.effort)
		clusters := km.Clusters()
		c.Logf("Test %d: epsilon = %.2f effort = %d", i, t.epsilon, t.effort)
		for ci, cl := range clusters {
			c.Logf("Cluster %d:", ci)
			for _, j := range cl {
				f := t.set[j]
				c.Logf("%2s %s%s",
					f.ID,
					strings.Repeat(" ", f.Start/20),
					strings.Repeat("-", f.Len()/20),
				)
			}
		}
		c.Log()
		c.Check(clusters, check.DeepEquals, t.clusters)
		c.Check(int(km.Total()), check.Equals, t.total)
		c.Check(km.Within(), check.DeepEquals, t.within)
	}
}

type bench [][2]float64

func (b bench) Len() int                    { return len(b) }
func (b bench) Values(i int) (x, y float64) { return b[i][0], b[i][1] }

var benchData bench = func() bench {
	b := make(bench, 10000)
	for i := 0; i < 20; i++ {
		x, y := float64(rand.Intn(10000)), float64(rand.Intn(10000))
		r := float64(rand.Intn(200))
		for j := range b {
			b[j] = [2]float64{x + r*rand.NormFloat64(), y + r*rand.NormFloat64()}
		}
	}
	return b
}()

func Benchmark(b *testing.B) {
	km := kmeans.New(benchData)
	km.Seed(20)
	for i := 0; i < b.N; i++ {
		km.Cluster()
	}
	_ = km.Clusters()
}
<|endoftext|>


<commit_before>package backend

// IDSet is a set of IDs.
type IDSet map[ID]struct{}

// NewIDSet returns a new IDSet, populated with ids.
func NewIDSet(ids ...ID) IDSet {
	m := make(IDSet)
	for _, id := range ids {
		m[id] = struct{}{}
	}

	return m
}

// Has returns true iff id is contained in the set.
func (s IDSet) Has(id ID) bool {
	_, ok := s[id]
	return ok
}

// Insert adds id to the set.
func (s IDSet) Insert(id ID) {
	s[id] = struct{}{}
}

// Delete removes id from the set.
func (s IDSet) Delete(id ID) {
	delete(s, id)
}

// List returns a slice of all IDs in the set.
func (s IDSet) List() IDs {
	list := make(IDs, 0, len(s))
	for id := range s {
		list = append(list, id)
	}

	return list
}

// Equals returns true iff s equals other.
func (s IDSet) Equals(other IDSet) bool {
	if len(s) != len(other) {
		return false
	}

	for id := range s {
		if _, ok := other[id]; !ok {
			return false
		}
	}

	for id := range other {
		if _, ok := s[id]; !ok {
			return false
		}
	}

	return true
}

func (s IDSet) String() string {
	str := s.List().String()
	if len(str) < 2 {
		return "{}"
	}

	return "{" + str[1:len(str)-2] + "}"
}
<commit_msg>Fix IDSet.String()<commit_after>package backend

// IDSet is a set of IDs.
type IDSet map[ID]struct{}

// NewIDSet returns a new IDSet, populated with ids.
func NewIDSet(ids ...ID) IDSet {
	m := make(IDSet)
	for _, id := range ids {
		m[id] = struct{}{}
	}

	return m
}

// Has returns true iff id is contained in the set.
func (s IDSet) Has(id ID) bool {
	_, ok := s[id]
	return ok
}

// Insert adds id to the set.
func (s IDSet) Insert(id ID) {
	s[id] = struct{}{}
}

// Delete removes id from the set.
func (s IDSet) Delete(id ID) {
	delete(s, id)
}

// List returns a slice of all IDs in the set.
func (s IDSet) List() IDs {
	list := make(IDs, 0, len(s))
	for id := range s {
		list = append(list, id)
	}

	return list
}

// Equals returns true iff s equals other.
func (s IDSet) Equals(other IDSet) bool {
	if len(s) != len(other) {
		return false
	}

	for id := range s {
		if _, ok := other[id]; !ok {
			return false
		}
	}

	for id := range other {
		if _, ok := s[id]; !ok {
			return false
		}
	}

	return true
}

func (s IDSet) String() string {
	str := s.List().String()
	if len(str) < 2 {
		return "{}"
	}

	return "{" + str[1:len(str)-1] + "}"
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 gcp

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"os/exec"
	"strings"
	"sync"
	"time"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/yaml"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/util/jsonpath"
	"k8s.io/klog/v2"
)

func init() {
	if err := restclient.RegisterAuthProviderPlugin("gcp", newGCPAuthProvider); err != nil {
		klog.Fatalf("Failed to register gcp auth plugin: %v", err)
	}
}

var (
	// Stubbable for testing
	execCommand = exec.Command

	// defaultScopes:
	// - cloud-platform is the base scope to authenticate to GCP.
	// - userinfo.email is used to authenticate to GKE APIs with gserviceaccount
	//   email instead of numeric uniqueID.
	defaultScopes = []string{
		"https://www.googleapis.com/auth/cloud-platform",
		"https://www.googleapis.com/auth/userinfo.email"}
)

// gcpAuthProvider is an auth provider plugin that uses GCP credentials to provide
// tokens for kubectl to authenticate itself to the apiserver. A sample json config
// is provided below with all recognized options described.
//
// {
//   'auth-provider': {
//     # Required
//     "name": "gcp",
//
//     'config': {
//       # Authentication options
//       # These options are used while getting a token.
//
//       # comma-separated list of GCP API scopes. default value of this field
//       # is "https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/userinfo.email".
// 		 # to override the API scopes, specify this field explicitly.
//       "scopes": "https://www.googleapis.com/auth/cloud-platform"
//
//       # Caching options
//
//       # Raw string data representing cached access token.
//       "access-token": "ya29.CjWdA4GiBPTt",
//       # RFC3339Nano expiration timestamp for cached access token.
//       "expiry": "2016-10-31 22:31:9.123",
//
//       # Command execution options
//       # These options direct the plugin to execute a specified command and parse
//       # token and expiry time from the output of the command.
//
//       # Command to execute for access token. Command output will be parsed as JSON.
//       # If "cmd-args" is not present, this value will be split on whitespace, with
//       # the first element interpreted as the command, remaining elements as args.
//       "cmd-path": "/usr/bin/gcloud",
//
//       # Arguments to pass to command to execute for access token.
//       "cmd-args": "config config-helper --output=json"
//
//       # JSONPath to the string field that represents the access token in
//       # command output. If omitted, defaults to "{.access_token}".
//       "token-key": "{.credential.access_token}",
//
//       # JSONPath to the string field that represents expiration timestamp
//       # of the access token in the command output. If omitted, defaults to
//       # "{.token_expiry}"
//       "expiry-key": ""{.credential.token_expiry}",
//
//       # golang reference time in the format that the expiration timestamp uses.
//       # If omitted, defaults to time.RFC3339Nano
//       "time-fmt": "2006-01-02 15:04:05.999999999"
//     }
//   }
// }
//
type gcpAuthProvider struct {
	tokenSource oauth2.TokenSource
	persister   restclient.AuthProviderConfigPersister
}

var warnOnce sync.Once

func newGCPAuthProvider(_ string, gcpConfig map[string]string, persister restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) {
	// deprecated in v1.22, remove in v1.25
	// this should be updated to use klog.Warningf in v1.24 to more actively warn consumers
	warnOnce.Do(func() {
		klog.V(1).Infof(`WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.25+; use gcloud instead.
To learn more, consult https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins`)
	})

	ts, err := tokenSource(isCmdTokenSource(gcpConfig), gcpConfig)
	if err != nil {
		return nil, err
	}
	cts, err := newCachedTokenSource(gcpConfig["access-token"], gcpConfig["expiry"], persister, ts, gcpConfig)
	if err != nil {
		return nil, err
	}
	return &gcpAuthProvider{cts, persister}, nil
}

func isCmdTokenSource(gcpConfig map[string]string) bool {
	_, ok := gcpConfig["cmd-path"]
	return ok
}

func tokenSource(isCmd bool, gcpConfig map[string]string) (oauth2.TokenSource, error) {
	// Command-based token source
	if isCmd {
		cmd := gcpConfig["cmd-path"]
		if len(cmd) == 0 {
			return nil, fmt.Errorf("missing access token cmd")
		}
		if gcpConfig["scopes"] != "" {
			return nil, fmt.Errorf("scopes can only be used when kubectl is using a gcp service account key")
		}
		var args []string
		if cmdArgs, ok := gcpConfig["cmd-args"]; ok {
			args = strings.Fields(cmdArgs)
		} else {
			fields := strings.Fields(cmd)
			cmd = fields[0]
			args = fields[1:]
		}
		return newCmdTokenSource(cmd, args, gcpConfig["token-key"], gcpConfig["expiry-key"], gcpConfig["time-fmt"]), nil
	}

	// Google Application Credentials-based token source
	scopes := parseScopes(gcpConfig)
	ts, err := google.DefaultTokenSource(context.Background(), scopes...)
	if err != nil {
		return nil, fmt.Errorf("cannot construct google default token source: %v", err)
	}
	return ts, nil
}

// parseScopes constructs a list of scopes that should be included in token source
// from the config map.
func parseScopes(gcpConfig map[string]string) []string {
	scopes, ok := gcpConfig["scopes"]
	if !ok {
		return defaultScopes
	}
	if scopes == "" {
		return []string{}
	}
	return strings.Split(gcpConfig["scopes"], ",")
}

func (g *gcpAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper {
	var resetCache map[string]string
	if cts, ok := g.tokenSource.(*cachedTokenSource); ok {
		resetCache = cts.baseCache()
	} else {
		resetCache = make(map[string]string)
	}
	return &conditionalTransport{&oauth2.Transport{Source: g.tokenSource, Base: rt}, g.persister, resetCache}
}

func (g *gcpAuthProvider) Login() error { return nil }

type cachedTokenSource struct {
	lk          sync.Mutex
	source      oauth2.TokenSource
	accessToken string `datapolicy:"token"`
	expiry      time.Time
	persister   restclient.AuthProviderConfigPersister
	cache       map[string]string
}

func newCachedTokenSource(accessToken, expiry string, persister restclient.AuthProviderConfigPersister, ts oauth2.TokenSource, cache map[string]string) (*cachedTokenSource, error) {
	var expiryTime time.Time
	if parsedTime, err := time.Parse(time.RFC3339Nano, expiry); err == nil {
		expiryTime = parsedTime
	}
	if cache == nil {
		cache = make(map[string]string)
	}
	return &cachedTokenSource{
		source:      ts,
		accessToken: accessToken,
		expiry:      expiryTime,
		persister:   persister,
		cache:       cache,
	}, nil
}

func (t *cachedTokenSource) Token() (*oauth2.Token, error) {
	tok := t.cachedToken()
	if tok.Valid() && !tok.Expiry.IsZero() {
		return tok, nil
	}
	tok, err := t.source.Token()
	if err != nil {
		return nil, err
	}
	cache := t.update(tok)
	if t.persister != nil {
		if err := t.persister.Persist(cache); err != nil {
			klog.V(4).Infof("Failed to persist token: %v", err)
		}
	}
	return tok, nil
}

func (t *cachedTokenSource) cachedToken() *oauth2.Token {
	t.lk.Lock()
	defer t.lk.Unlock()
	return &oauth2.Token{
		AccessToken: t.accessToken,
		TokenType:   "Bearer",
		Expiry:      t.expiry,
	}
}

func (t *cachedTokenSource) update(tok *oauth2.Token) map[string]string {
	t.lk.Lock()
	defer t.lk.Unlock()
	t.accessToken = tok.AccessToken
	t.expiry = tok.Expiry
	ret := map[string]string{}
	for k, v := range t.cache {
		ret[k] = v
	}
	ret["access-token"] = t.accessToken
	ret["expiry"] = t.expiry.Format(time.RFC3339Nano)
	return ret
}

// baseCache is the base configuration value for this TokenSource, without any cached ephemeral tokens.
func (t *cachedTokenSource) baseCache() map[string]string {
	t.lk.Lock()
	defer t.lk.Unlock()
	ret := map[string]string{}
	for k, v := range t.cache {
		ret[k] = v
	}
	delete(ret, "access-token")
	delete(ret, "expiry")
	return ret
}

type commandTokenSource struct {
	cmd       string
	args      []string
	tokenKey  string `datapolicy:"token"`
	expiryKey string `datapolicy:"secret-key"`
	timeFmt   string
}

func newCmdTokenSource(cmd string, args []string, tokenKey, expiryKey, timeFmt string) *commandTokenSource {
	if len(timeFmt) == 0 {
		timeFmt = time.RFC3339Nano
	}
	if len(tokenKey) == 0 {
		tokenKey = "{.access_token}"
	}
	if len(expiryKey) == 0 {
		expiryKey = "{.token_expiry}"
	}
	return &commandTokenSource{
		cmd:       cmd,
		args:      args,
		tokenKey:  tokenKey,
		expiryKey: expiryKey,
		timeFmt:   timeFmt,
	}
}

func (c *commandTokenSource) Token() (*oauth2.Token, error) {
	fullCmd := strings.Join(append([]string{c.cmd}, c.args...), " ")
	cmd := execCommand(c.cmd, c.args...)
	var stderr bytes.Buffer
	cmd.Stderr = &stderr
	output, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("error executing access token command %q: err=%v output=%s stderr=%s", fullCmd, err, output, string(stderr.Bytes()))
	}
	token, err := c.parseTokenCmdOutput(output)
	if err != nil {
		return nil, fmt.Errorf("error parsing output for access token command %q: %v", fullCmd, err)
	}
	return token, nil
}

func (c *commandTokenSource) parseTokenCmdOutput(output []byte) (*oauth2.Token, error) {
	output, err := yaml.ToJSON(output)
	if err != nil {
		return nil, err
	}
	var data interface{}
	if err := json.Unmarshal(output, &data); err != nil {
		return nil, err
	}

	accessToken, err := parseJSONPath(data, "token-key", c.tokenKey)
	if err != nil {
		return nil, fmt.Errorf("error parsing token-key %q from %q: %v", c.tokenKey, string(output), err)
	}
	expiryStr, err := parseJSONPath(data, "expiry-key", c.expiryKey)
	if err != nil {
		return nil, fmt.Errorf("error parsing expiry-key %q from %q: %v", c.expiryKey, string(output), err)
	}
	var expiry time.Time
	if t, err := time.Parse(c.timeFmt, expiryStr); err != nil {
		klog.V(4).Infof("Failed to parse token expiry from %s (fmt=%s): %v", expiryStr, c.timeFmt, err)
	} else {
		expiry = t
	}

	return &oauth2.Token{
		AccessToken: accessToken,
		TokenType:   "Bearer",
		Expiry:      expiry,
	}, nil
}

func parseJSONPath(input interface{}, name, template string) (string, error) {
	j := jsonpath.New(name)
	buf := new(bytes.Buffer)
	if err := j.Parse(template); err != nil {
		return "", err
	}
	if err := j.Execute(buf, input); err != nil {
		return "", err
	}
	return buf.String(), nil
}

type conditionalTransport struct {
	oauthTransport *oauth2.Transport
	persister      restclient.AuthProviderConfigPersister
	resetCache     map[string]string
}

var _ net.RoundTripperWrapper = &conditionalTransport{}

func (t *conditionalTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	if len(req.Header.Get("Authorization")) != 0 {
		return t.oauthTransport.Base.RoundTrip(req)
	}

	res, err := t.oauthTransport.RoundTrip(req)

	if err != nil {
		return nil, err
	}

	if res.StatusCode == 401 {
		klog.V(4).Infof("The credentials that were supplied are invalid for the target cluster")
		t.persister.Persist(t.resetCache)
	}

	return res, nil
}

func (t *conditionalTransport) WrappedRoundTripper() http.RoundTripper { return t.oauthTransport.Base }
<commit_msg>add better link for gcp auth plugin doc<commit_after>/*
Copyright 2016 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 gcp

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"os/exec"
	"strings"
	"sync"
	"time"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/yaml"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/util/jsonpath"
	"k8s.io/klog/v2"
)

func init() {
	if err := restclient.RegisterAuthProviderPlugin("gcp", newGCPAuthProvider); err != nil {
		klog.Fatalf("Failed to register gcp auth plugin: %v", err)
	}
}

var (
	// Stubbable for testing
	execCommand = exec.Command

	// defaultScopes:
	// - cloud-platform is the base scope to authenticate to GCP.
	// - userinfo.email is used to authenticate to GKE APIs with gserviceaccount
	//   email instead of numeric uniqueID.
	defaultScopes = []string{
		"https://www.googleapis.com/auth/cloud-platform",
		"https://www.googleapis.com/auth/userinfo.email"}
)

// gcpAuthProvider is an auth provider plugin that uses GCP credentials to provide
// tokens for kubectl to authenticate itself to the apiserver. A sample json config
// is provided below with all recognized options described.
//
// {
//   'auth-provider': {
//     # Required
//     "name": "gcp",
//
//     'config': {
//       # Authentication options
//       # These options are used while getting a token.
//
//       # comma-separated list of GCP API scopes. default value of this field
//       # is "https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/userinfo.email".
// 		 # to override the API scopes, specify this field explicitly.
//       "scopes": "https://www.googleapis.com/auth/cloud-platform"
//
//       # Caching options
//
//       # Raw string data representing cached access token.
//       "access-token": "ya29.CjWdA4GiBPTt",
//       # RFC3339Nano expiration timestamp for cached access token.
//       "expiry": "2016-10-31 22:31:9.123",
//
//       # Command execution options
//       # These options direct the plugin to execute a specified command and parse
//       # token and expiry time from the output of the command.
//
//       # Command to execute for access token. Command output will be parsed as JSON.
//       # If "cmd-args" is not present, this value will be split on whitespace, with
//       # the first element interpreted as the command, remaining elements as args.
//       "cmd-path": "/usr/bin/gcloud",
//
//       # Arguments to pass to command to execute for access token.
//       "cmd-args": "config config-helper --output=json"
//
//       # JSONPath to the string field that represents the access token in
//       # command output. If omitted, defaults to "{.access_token}".
//       "token-key": "{.credential.access_token}",
//
//       # JSONPath to the string field that represents expiration timestamp
//       # of the access token in the command output. If omitted, defaults to
//       # "{.token_expiry}"
//       "expiry-key": ""{.credential.token_expiry}",
//
//       # golang reference time in the format that the expiration timestamp uses.
//       # If omitted, defaults to time.RFC3339Nano
//       "time-fmt": "2006-01-02 15:04:05.999999999"
//     }
//   }
// }
//
type gcpAuthProvider struct {
	tokenSource oauth2.TokenSource
	persister   restclient.AuthProviderConfigPersister
}

var warnOnce sync.Once

func newGCPAuthProvider(_ string, gcpConfig map[string]string, persister restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) {
	warnOnce.Do(func() {
		klog.Warningf(`WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.25+; use gcloud instead.
To learn more, consult https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke`)
	})

	ts, err := tokenSource(isCmdTokenSource(gcpConfig), gcpConfig)
	if err != nil {
		return nil, err
	}
	cts, err := newCachedTokenSource(gcpConfig["access-token"], gcpConfig["expiry"], persister, ts, gcpConfig)
	if err != nil {
		return nil, err
	}
	return &gcpAuthProvider{cts, persister}, nil
}

func isCmdTokenSource(gcpConfig map[string]string) bool {
	_, ok := gcpConfig["cmd-path"]
	return ok
}

func tokenSource(isCmd bool, gcpConfig map[string]string) (oauth2.TokenSource, error) {
	// Command-based token source
	if isCmd {
		cmd := gcpConfig["cmd-path"]
		if len(cmd) == 0 {
			return nil, fmt.Errorf("missing access token cmd")
		}
		if gcpConfig["scopes"] != "" {
			return nil, fmt.Errorf("scopes can only be used when kubectl is using a gcp service account key")
		}
		var args []string
		if cmdArgs, ok := gcpConfig["cmd-args"]; ok {
			args = strings.Fields(cmdArgs)
		} else {
			fields := strings.Fields(cmd)
			cmd = fields[0]
			args = fields[1:]
		}
		return newCmdTokenSource(cmd, args, gcpConfig["token-key"], gcpConfig["expiry-key"], gcpConfig["time-fmt"]), nil
	}

	// Google Application Credentials-based token source
	scopes := parseScopes(gcpConfig)
	ts, err := google.DefaultTokenSource(context.Background(), scopes...)
	if err != nil {
		return nil, fmt.Errorf("cannot construct google default token source: %v", err)
	}
	return ts, nil
}

// parseScopes constructs a list of scopes that should be included in token source
// from the config map.
func parseScopes(gcpConfig map[string]string) []string {
	scopes, ok := gcpConfig["scopes"]
	if !ok {
		return defaultScopes
	}
	if scopes == "" {
		return []string{}
	}
	return strings.Split(gcpConfig["scopes"], ",")
}

func (g *gcpAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper {
	var resetCache map[string]string
	if cts, ok := g.tokenSource.(*cachedTokenSource); ok {
		resetCache = cts.baseCache()
	} else {
		resetCache = make(map[string]string)
	}
	return &conditionalTransport{&oauth2.Transport{Source: g.tokenSource, Base: rt}, g.persister, resetCache}
}

func (g *gcpAuthProvider) Login() error { return nil }

type cachedTokenSource struct {
	lk          sync.Mutex
	source      oauth2.TokenSource
	accessToken string `datapolicy:"token"`
	expiry      time.Time
	persister   restclient.AuthProviderConfigPersister
	cache       map[string]string
}

func newCachedTokenSource(accessToken, expiry string, persister restclient.AuthProviderConfigPersister, ts oauth2.TokenSource, cache map[string]string) (*cachedTokenSource, error) {
	var expiryTime time.Time
	if parsedTime, err := time.Parse(time.RFC3339Nano, expiry); err == nil {
		expiryTime = parsedTime
	}
	if cache == nil {
		cache = make(map[string]string)
	}
	return &cachedTokenSource{
		source:      ts,
		accessToken: accessToken,
		expiry:      expiryTime,
		persister:   persister,
		cache:       cache,
	}, nil
}

func (t *cachedTokenSource) Token() (*oauth2.Token, error) {
	tok := t.cachedToken()
	if tok.Valid() && !tok.Expiry.IsZero() {
		return tok, nil
	}
	tok, err := t.source.Token()
	if err != nil {
		return nil, err
	}
	cache := t.update(tok)
	if t.persister != nil {
		if err := t.persister.Persist(cache); err != nil {
			klog.V(4).Infof("Failed to persist token: %v", err)
		}
	}
	return tok, nil
}

func (t *cachedTokenSource) cachedToken() *oauth2.Token {
	t.lk.Lock()
	defer t.lk.Unlock()
	return &oauth2.Token{
		AccessToken: t.accessToken,
		TokenType:   "Bearer",
		Expiry:      t.expiry,
	}
}

func (t *cachedTokenSource) update(tok *oauth2.Token) map[string]string {
	t.lk.Lock()
	defer t.lk.Unlock()
	t.accessToken = tok.AccessToken
	t.expiry = tok.Expiry
	ret := map[string]string{}
	for k, v := range t.cache {
		ret[k] = v
	}
	ret["access-token"] = t.accessToken
	ret["expiry"] = t.expiry.Format(time.RFC3339Nano)
	return ret
}

// baseCache is the base configuration value for this TokenSource, without any cached ephemeral tokens.
func (t *cachedTokenSource) baseCache() map[string]string {
	t.lk.Lock()
	defer t.lk.Unlock()
	ret := map[string]string{}
	for k, v := range t.cache {
		ret[k] = v
	}
	delete(ret, "access-token")
	delete(ret, "expiry")
	return ret
}

type commandTokenSource struct {
	cmd       string
	args      []string
	tokenKey  string `datapolicy:"token"`
	expiryKey string `datapolicy:"secret-key"`
	timeFmt   string
}

func newCmdTokenSource(cmd string, args []string, tokenKey, expiryKey, timeFmt string) *commandTokenSource {
	if len(timeFmt) == 0 {
		timeFmt = time.RFC3339Nano
	}
	if len(tokenKey) == 0 {
		tokenKey = "{.access_token}"
	}
	if len(expiryKey) == 0 {
		expiryKey = "{.token_expiry}"
	}
	return &commandTokenSource{
		cmd:       cmd,
		args:      args,
		tokenKey:  tokenKey,
		expiryKey: expiryKey,
		timeFmt:   timeFmt,
	}
}

func (c *commandTokenSource) Token() (*oauth2.Token, error) {
	fullCmd := strings.Join(append([]string{c.cmd}, c.args...), " ")
	cmd := execCommand(c.cmd, c.args...)
	var stderr bytes.Buffer
	cmd.Stderr = &stderr
	output, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("error executing access token command %q: err=%v output=%s stderr=%s", fullCmd, err, output, string(stderr.Bytes()))
	}
	token, err := c.parseTokenCmdOutput(output)
	if err != nil {
		return nil, fmt.Errorf("error parsing output for access token command %q: %v", fullCmd, err)
	}
	return token, nil
}

func (c *commandTokenSource) parseTokenCmdOutput(output []byte) (*oauth2.Token, error) {
	output, err := yaml.ToJSON(output)
	if err != nil {
		return nil, err
	}
	var data interface{}
	if err := json.Unmarshal(output, &data); err != nil {
		return nil, err
	}

	accessToken, err := parseJSONPath(data, "token-key", c.tokenKey)
	if err != nil {
		return nil, fmt.Errorf("error parsing token-key %q from %q: %v", c.tokenKey, string(output), err)
	}
	expiryStr, err := parseJSONPath(data, "expiry-key", c.expiryKey)
	if err != nil {
		return nil, fmt.Errorf("error parsing expiry-key %q from %q: %v", c.expiryKey, string(output), err)
	}
	var expiry time.Time
	if t, err := time.Parse(c.timeFmt, expiryStr); err != nil {
		klog.V(4).Infof("Failed to parse token expiry from %s (fmt=%s): %v", expiryStr, c.timeFmt, err)
	} else {
		expiry = t
	}

	return &oauth2.Token{
		AccessToken: accessToken,
		TokenType:   "Bearer",
		Expiry:      expiry,
	}, nil
}

func parseJSONPath(input interface{}, name, template string) (string, error) {
	j := jsonpath.New(name)
	buf := new(bytes.Buffer)
	if err := j.Parse(template); err != nil {
		return "", err
	}
	if err := j.Execute(buf, input); err != nil {
		return "", err
	}
	return buf.String(), nil
}

type conditionalTransport struct {
	oauthTransport *oauth2.Transport
	persister      restclient.AuthProviderConfigPersister
	resetCache     map[string]string
}

var _ net.RoundTripperWrapper = &conditionalTransport{}

func (t *conditionalTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	if len(req.Header.Get("Authorization")) != 0 {
		return t.oauthTransport.Base.RoundTrip(req)
	}

	res, err := t.oauthTransport.RoundTrip(req)

	if err != nil {
		return nil, err
	}

	if res.StatusCode == 401 {
		klog.V(4).Infof("The credentials that were supplied are invalid for the target cluster")
		t.persister.Persist(t.resetCache)
	}

	return res, nil
}

func (t *conditionalTransport) WrappedRoundTripper() http.RoundTripper { return t.oauthTransport.Base }
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

func expect(t *testing.T, got interface{}, expected interface{}) {
	if got != expected {
		t.Errorf("Expected %v (type %v) - Got %v (type %v)", expected, reflect.TypeOf(expected), got, reflect.TypeOf(got))
	}
}

func createTestserver(result int, answer string) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(result)
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, answer)
	}))
}

func TestGetMetricMap(t *testing.T) {
	// Test server that always responds with 200 code, and specific payload
	server := createTestserver(200, `{"nonFloat":"bob@example.com","float1":1.23456789101112,"number":2}`)
	defer server.Close()

	config := &rabbitExporterConfig{
		RabbitURL: server.URL,
	}

	overview, _ := getMetricMap(*config, "overview")

	expect(t, len(overview), 2)
	expect(t, overview["float1"], 1.23456789101112)
	expect(t, overview["number"], 2.0)

	//Unknown error Server
	errorServer := createTestserver(500, http.StatusText(500))
	defer errorServer.Close()

	config = &rabbitExporterConfig{
		RabbitURL: errorServer.URL,
	}

	overview, _ = getMetricMap(*config, "overview")

	expect(t, len(overview), 0)
}

func TestQueues(t *testing.T) {
	// Test server that always responds with 200 code, and specific payload
	server := createTestserver(200, `[{"name":"Queue1","nonFloat":"bob@example.com","float1":1.23456789101112,"number":2},{"name":"Queue2","vhost":"Vhost2","nonFloat":"bob@example.com","float1":3.23456789101112,"number":3}]`)
	defer server.Close()

	config := &rabbitExporterConfig{
		RabbitURL: server.URL,
	}

	queues, err := getStatsInfo(*config, "queues")
	expect(t, err, nil)
	expect(t, len(queues), 2)
	expect(t, queues[0].name, "Queue1")
	expect(t, queues[0].vhost, "")
	expect(t, queues[1].name, "Queue2")
	expect(t, queues[1].vhost, "Vhost2")
	expect(t, len(queues[0].metrics), 2)
	expect(t, len(queues[1].metrics), 2)
	expect(t, queues[0].metrics["float1"], 1.23456789101112)
	expect(t, queues[1].metrics["float1"], 3.23456789101112)
	expect(t, queues[0].metrics["number"], 2.0)
	expect(t, queues[1].metrics["number"], 3.0)

	//Unknown error Server
	errorServer := createTestserver(500, http.StatusText(500))
	defer errorServer.Close()

	config = &rabbitExporterConfig{
		RabbitURL: errorServer.URL,
	}

	queues, err = getStatsInfo(*config, "queues")
	if err == nil {
		t.Errorf("Request failed. An error was expected but not found")
	}
	expect(t, len(queues), 0)
}

func TestExchanges(t *testing.T) {

	// Test server that always responds with 200 code, and specific payload
	server := createTestserver(200, exchangeAPIResponse)
	defer server.Close()

	config := &rabbitExporterConfig{
		RabbitURL: server.URL,
	}

	exchanges, err := getStatsInfo(*config, "exchanges")
	expect(t, err, nil)
	expect(t, len(exchanges), 9)
	expect(t, exchanges[0].name, "")
	expect(t, exchanges[0].vhost, "/")
	expect(t, exchanges[1].name, "amq.direct")
	expect(t, exchanges[1].vhost, "/")
	expect(t, len(exchanges[0].metrics), 0)
	expect(t, len(exchanges[1].metrics), 0)

	expect(t, exchanges[8].name, "myExchange")
	expect(t, exchanges[8].vhost, "/")
	expect(t, exchanges[8].metrics["message_stats.confirm"], 5.0)
	expect(t, exchanges[8].metrics["message_stats.publish_in"], 5.0)
	expect(t, exchanges[8].metrics["message_stats.ack"], 0.0)
	expect(t, exchanges[8].metrics["message_stats.return_unroutable"], 5.0)

	//Unknown error Server
	errorServer := createTestserver(500, http.StatusText(500))
	defer errorServer.Close()

	config = &rabbitExporterConfig{
		RabbitURL: errorServer.URL,
	}

	exchanges, err = getStatsInfo(*config, "exchanges")
	if err == nil {
		t.Errorf("Request failed. An error was expected but not found")
	}
	expect(t, len(exchanges), 0)
}
<commit_msg>fixed test (bool support added metrics)<commit_after>package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

func expect(t *testing.T, got interface{}, expected interface{}) {
	if got != expected {
		t.Errorf("Expected %v (type %v) - Got %v (type %v)", expected, reflect.TypeOf(expected), got, reflect.TypeOf(got))
	}
}

func createTestserver(result int, answer string) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(result)
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, answer)
	}))
}

func TestGetMetricMap(t *testing.T) {
	// Test server that always responds with 200 code, and specific payload
	server := createTestserver(200, `{"nonFloat":"bob@example.com","float1":1.23456789101112,"number":2}`)
	defer server.Close()

	config := &rabbitExporterConfig{
		RabbitURL: server.URL,
	}

	overview, _ := getMetricMap(*config, "overview")

	expect(t, len(overview), 2)
	expect(t, overview["float1"], 1.23456789101112)
	expect(t, overview["number"], 2.0)

	//Unknown error Server
	errorServer := createTestserver(500, http.StatusText(500))
	defer errorServer.Close()

	config = &rabbitExporterConfig{
		RabbitURL: errorServer.URL,
	}

	overview, _ = getMetricMap(*config, "overview")

	expect(t, len(overview), 0)
}

func TestQueues(t *testing.T) {
	// Test server that always responds with 200 code, and specific payload
	server := createTestserver(200, `[{"name":"Queue1","nonFloat":"bob@example.com","float1":1.23456789101112,"number":2},{"name":"Queue2","vhost":"Vhost2","nonFloat":"bob@example.com","float1":3.23456789101112,"number":3}]`)
	defer server.Close()

	config := &rabbitExporterConfig{
		RabbitURL: server.URL,
	}

	queues, err := getStatsInfo(*config, "queues")
	expect(t, err, nil)
	expect(t, len(queues), 2)
	expect(t, queues[0].name, "Queue1")
	expect(t, queues[0].vhost, "")
	expect(t, queues[1].name, "Queue2")
	expect(t, queues[1].vhost, "Vhost2")
	expect(t, len(queues[0].metrics), 2)
	expect(t, len(queues[1].metrics), 2)
	expect(t, queues[0].metrics["float1"], 1.23456789101112)
	expect(t, queues[1].metrics["float1"], 3.23456789101112)
	expect(t, queues[0].metrics["number"], 2.0)
	expect(t, queues[1].metrics["number"], 3.0)

	//Unknown error Server
	errorServer := createTestserver(500, http.StatusText(500))
	defer errorServer.Close()

	config = &rabbitExporterConfig{
		RabbitURL: errorServer.URL,
	}

	queues, err = getStatsInfo(*config, "queues")
	if err == nil {
		t.Errorf("Request failed. An error was expected but not found")
	}
	expect(t, len(queues), 0)
}

func TestExchanges(t *testing.T) {

	// Test server that always responds with 200 code, and specific payload
	server := createTestserver(200, exchangeAPIResponse)
	defer server.Close()

	config := &rabbitExporterConfig{
		RabbitURL: server.URL,
	}

	exchanges, err := getStatsInfo(*config, "exchanges")
	expect(t, err, nil)
	expect(t, len(exchanges), 9)
	expect(t, exchanges[0].name, "")
	expect(t, exchanges[0].vhost, "/")
	expect(t, exchanges[1].name, "amq.direct")
	expect(t, exchanges[1].vhost, "/")
	expect(t, len(exchanges[0].metrics), 3)
	expect(t, len(exchanges[1].metrics), 3)

	expect(t, exchanges[8].name, "myExchange")
	expect(t, exchanges[8].vhost, "/")
	expect(t, exchanges[8].metrics["message_stats.confirm"], 5.0)
	expect(t, exchanges[8].metrics["message_stats.publish_in"], 5.0)
	expect(t, exchanges[8].metrics["message_stats.ack"], 0.0)
	expect(t, exchanges[8].metrics["message_stats.return_unroutable"], 5.0)

	//Unknown error Server
	errorServer := createTestserver(500, http.StatusText(500))
	defer errorServer.Close()

	config = &rabbitExporterConfig{
		RabbitURL: errorServer.URL,
	}

	exchanges, err = getStatsInfo(*config, "exchanges")
	if err == nil {
		t.Errorf("Request failed. An error was expected but not found")
	}
	expect(t, len(exchanges), 0)
}
<|endoftext|>


<commit_before>// +build windows

package collector

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

func init() {
	registerCollector("adfs", newADFSCollector)
}

type adfsCollector struct {
	adLoginConnectionFailures        *prometheus.Desc
	certificateAuthentications       *prometheus.Desc
	deviceAuthentications            *prometheus.Desc
	extranetAccountLockouts          *prometheus.Desc
	federatedAuthentications         *prometheus.Desc
	passportAuthentications          *prometheus.Desc
	passiveRequests                  *prometheus.Desc
	passwordChangeFailed             *prometheus.Desc
	passwordChangeSucceeded          *prometheus.Desc
	tokenRequests                    *prometheus.Desc
	windowsIntegratedAuthentications *prometheus.Desc
}

// newADFSCollector constructs a new adfsCollector
func newADFSCollector() (Collector, error) {
	const subsystem = "adfs"

	return &adfsCollector{
		adLoginConnectionFailures: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "ad_login_connection_failures"),
			"Total number of connection failures to an Active Directory domain controller",
			nil,
			nil,
		),
		certificateAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "certificate_authentications"),
			"Total number of User Certificate authentications",
			nil,
			nil,
		),
		deviceAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "device_authentications"),
			"Total number of Device authentications",
			nil,
			nil,
		),
		extranetAccountLockouts: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "extranet_account_lockouts"),
			"Total number of Extranet Account Lockouts",
			nil,
			nil,
		),
		federatedAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "federated_authentications"),
			"Total number of authentications from a federated source",
			nil,
			nil,
		),
		passportAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "passport_authentications"),
			"Total number of Microsoft Passport SSO authentications",
			nil,
			nil,
		),
		passiveRequests: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "passive_requests"),
			"Total number of passive (browser-based) requests",
			nil,
			nil,
		),
		passwordChangeFailed: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "password_change_failed"),
			"Total number of failed password changes",
			nil,
			nil,
		),
		passwordChangeSucceeded: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "password_change_succeeded"),
			"Total number of successful password changes",
			nil,
			nil,
		),
		tokenRequests: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "token_requests"),
			"Total number of token requests",
			nil,
			nil,
		),
		windowsIntegratedAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "windows_integrated_authentications"),
			"Total number of Windows integrated authentications (Kerberos/NTLM)",
			nil,
			nil,
		),
	}, nil
}

type perflibADFS struct {
	AdLoginConnectionFailures        float64 `perflib:"AD login Connection Failures"`
	CertificateAuthentications       float64 `perflib:"Certificate Authentications"`
	DeviceAuthentications            float64 `perflib:"Device Authentications"`
	ExtranetAccountLockouts          float64 `perflib:"Extranet Account Lockouts"`
	FederatedAuthentications         float64 `perflib:"Federated Authentications"`
	PassportAuthentications          float64 `perflib:"Microsoft Passport Authentications"`
	PassiveRequests                  float64 `perflib:"Passive Requests"`
	PasswordChangeFailed             float64 `perflib:"Password Change Failed Requests"`
	PasswordChangeSucceeded          float64 `perflib:"Password Change Successful Requests"`
	TokenRequests                    float64 `perflib:"Token Requests"`
	WindowsIntegratedAuthentications float64 `perflib:"Windows Integrated Authentications"`
}

func (c *adfsCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
	var adfsData []perflibADFS
	err := unmarshalObject(ctx.perfObjects["AD FS"], &adfsData)
	if err != nil {
		return err
	}

	ch <- prometheus.MustNewConstMetric(
		c.adLoginConnectionFailures,
		prometheus.CounterValue,
		adfsData[0].AdLoginConnectionFailures,
	)

	ch <- prometheus.MustNewConstMetric(
		c.certificateAuthentications,
		prometheus.CounterValue,
		adfsData[0].CertificateAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.deviceAuthentications,
		prometheus.CounterValue,
		adfsData[0].DeviceAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.extranetAccountLockouts,
		prometheus.CounterValue,
		adfsData[0].ExtranetAccountLockouts,
	)

	ch <- prometheus.MustNewConstMetric(
		c.federatedAuthentications,
		prometheus.CounterValue,
		adfsData[0].FederatedAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passportAuthentications,
		prometheus.CounterValue,
		adfsData[0].PassportAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passiveRequests,
		prometheus.CounterValue,
		adfsData[0].PassiveRequests,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passwordChangeFailed,
		prometheus.CounterValue,
		adfsData[0].PasswordChangeFailed,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passwordChangeSucceeded,
		prometheus.CounterValue,
		adfsData[0].PasswordChangeSucceeded,
	)

	ch <- prometheus.MustNewConstMetric(
		c.tokenRequests,
		prometheus.CounterValue,
		adfsData[0].TokenRequests,
	)

	ch <- prometheus.MustNewConstMetric(
		c.windowsIntegratedAuthentications,
		prometheus.CounterValue,
		adfsData[0].WindowsIntegratedAuthentications,
	)
	return nil
}
<commit_msg>adfs collector missing dependency<commit_after>// +build windows

package collector

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

func init() {
	registerCollector("adfs", newADFSCollector, "AD FS")
}

type adfsCollector struct {
	adLoginConnectionFailures        *prometheus.Desc
	certificateAuthentications       *prometheus.Desc
	deviceAuthentications            *prometheus.Desc
	extranetAccountLockouts          *prometheus.Desc
	federatedAuthentications         *prometheus.Desc
	passportAuthentications          *prometheus.Desc
	passiveRequests                  *prometheus.Desc
	passwordChangeFailed             *prometheus.Desc
	passwordChangeSucceeded          *prometheus.Desc
	tokenRequests                    *prometheus.Desc
	windowsIntegratedAuthentications *prometheus.Desc
}

// newADFSCollector constructs a new adfsCollector
func newADFSCollector() (Collector, error) {
	const subsystem = "adfs"

	return &adfsCollector{
		adLoginConnectionFailures: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "ad_login_connection_failures"),
			"Total number of connection failures to an Active Directory domain controller",
			nil,
			nil,
		),
		certificateAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "certificate_authentications"),
			"Total number of User Certificate authentications",
			nil,
			nil,
		),
		deviceAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "device_authentications"),
			"Total number of Device authentications",
			nil,
			nil,
		),
		extranetAccountLockouts: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "extranet_account_lockouts"),
			"Total number of Extranet Account Lockouts",
			nil,
			nil,
		),
		federatedAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "federated_authentications"),
			"Total number of authentications from a federated source",
			nil,
			nil,
		),
		passportAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "passport_authentications"),
			"Total number of Microsoft Passport SSO authentications",
			nil,
			nil,
		),
		passiveRequests: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "passive_requests"),
			"Total number of passive (browser-based) requests",
			nil,
			nil,
		),
		passwordChangeFailed: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "password_change_failed"),
			"Total number of failed password changes",
			nil,
			nil,
		),
		passwordChangeSucceeded: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "password_change_succeeded"),
			"Total number of successful password changes",
			nil,
			nil,
		),
		tokenRequests: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "token_requests"),
			"Total number of token requests",
			nil,
			nil,
		),
		windowsIntegratedAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "windows_integrated_authentications"),
			"Total number of Windows integrated authentications (Kerberos/NTLM)",
			nil,
			nil,
		),
	}, nil
}

type perflibADFS struct {
	AdLoginConnectionFailures        float64 `perflib:"AD login Connection Failures"`
	CertificateAuthentications       float64 `perflib:"Certificate Authentications"`
	DeviceAuthentications            float64 `perflib:"Device Authentications"`
	ExtranetAccountLockouts          float64 `perflib:"Extranet Account Lockouts"`
	FederatedAuthentications         float64 `perflib:"Federated Authentications"`
	PassportAuthentications          float64 `perflib:"Microsoft Passport Authentications"`
	PassiveRequests                  float64 `perflib:"Passive Requests"`
	PasswordChangeFailed             float64 `perflib:"Password Change Failed Requests"`
	PasswordChangeSucceeded          float64 `perflib:"Password Change Successful Requests"`
	TokenRequests                    float64 `perflib:"Token Requests"`
	WindowsIntegratedAuthentications float64 `perflib:"Windows Integrated Authentications"`
}

func (c *adfsCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
	var adfsData []perflibADFS
	err := unmarshalObject(ctx.perfObjects["AD FS"], &adfsData)
	if err != nil {
		return err
	}

	ch <- prometheus.MustNewConstMetric(
		c.adLoginConnectionFailures,
		prometheus.CounterValue,
		adfsData[0].AdLoginConnectionFailures,
	)

	ch <- prometheus.MustNewConstMetric(
		c.certificateAuthentications,
		prometheus.CounterValue,
		adfsData[0].CertificateAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.deviceAuthentications,
		prometheus.CounterValue,
		adfsData[0].DeviceAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.extranetAccountLockouts,
		prometheus.CounterValue,
		adfsData[0].ExtranetAccountLockouts,
	)

	ch <- prometheus.MustNewConstMetric(
		c.federatedAuthentications,
		prometheus.CounterValue,
		adfsData[0].FederatedAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passportAuthentications,
		prometheus.CounterValue,
		adfsData[0].PassportAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passiveRequests,
		prometheus.CounterValue,
		adfsData[0].PassiveRequests,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passwordChangeFailed,
		prometheus.CounterValue,
		adfsData[0].PasswordChangeFailed,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passwordChangeSucceeded,
		prometheus.CounterValue,
		adfsData[0].PasswordChangeSucceeded,
	)

	ch <- prometheus.MustNewConstMetric(
		c.tokenRequests,
		prometheus.CounterValue,
		adfsData[0].TokenRequests,
	)

	ch <- prometheus.MustNewConstMetric(
		c.windowsIntegratedAuthentications,
		prometheus.CounterValue,
		adfsData[0].WindowsIntegratedAuthentications,
	)
	return nil
}
<|endoftext|>


<commit_before>// +build windows

package collector

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

func init() {
	Factories["adfs"] = newADFSCollector
}

type adfsCollector struct {
	adLoginConnectionFailures        *prometheus.Desc
	certificateAuthentications       *prometheus.Desc
	deviceAuthentications            *prometheus.Desc
	extranetAccountLockouts          *prometheus.Desc
	federatedAuthentications         *prometheus.Desc
	passportAuthentications          *prometheus.Desc
	passiveRequests                  *prometheus.Desc
	passwordChangeFailed             *prometheus.Desc
	passwordChangeSucceeded          *prometheus.Desc
	tokenRequests                    *prometheus.Desc
	windowsIntegratedAuthentications *prometheus.Desc
}

// newADFSCollector constructs a new adfsCollector
func newADFSCollector() (Collector, error) {
	const subsystem = "adfs"

	return &adfsCollector{
		adLoginConnectionFailures: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "ad_login_connection_failures"),
			"Total number of connection failures to an Active Directory domain controller",
			nil,
			nil,
		),
		certificateAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "certificate_authentications"),
			"Total number of User Certificate authentications",
			nil,
			nil,
		),
		deviceAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "device_authentications"),
			"Total number of Device authentications",
			nil,
			nil,
		),
		extranetAccountLockouts: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "extranet_account_lockouts"),
			"Total number of Extranet Account Lockouts",
			nil,
			nil,
		),
		federatedAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "federated_authentications"),
			"Total number of authentications from a federated source",
			nil,
			nil,
		),
		passportAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "passport_authentications"),
			"Total number of Microsoft Passport SSO authentications",
			nil,
			nil,
		),
		passiveRequests: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "passive_requests"),
			"Total number of passive (browser-based) requests",
			nil,
			nil,
		),
		passwordChangeFailed: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "password_change_failed"),
			"Total number of failed password changes",
			nil,
			nil,
		),
		passwordChangeSucceeded: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "password_change_succeeded"),
			"Total number of successful password changes",
			nil,
			nil,
		),
		tokenRequests: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "token_requests"),
			"Total number of token requests",
			nil,
			nil,
		),
		windowsIntegratedAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "windows_integrated_authentications"),
			"Total number of Windows integrated authentications (Kerberos/NTLM)",
			nil,
			nil,
		),
	}, nil
}

type perflibADFS struct {
	AdLoginConnectionFailures        float64 `perflib:"AD login Connection Failures"`
	CertificateAuthentications       float64 `perflib:"Certificate Authentications"`
	DeviceAuthentications            float64 `perflib:"Device Authentications"`
	ExtranetAccountLockouts          float64 `perflib:"Extranet Account Lockouts"`
	FederatedAuthentications         float64 `perflib:"Federated Authentications"`
	PassportAuthentications          float64 `perflib:"Microsoft Passport Authentications"`
	PassiveRequests                  float64 `perflib:"Passive Requests"`
	PasswordChangeFailed             float64 `perflib:"Password Change Failed Requests"`
	PasswordChangeSucceeded          float64 `perflib:"Password Change Successful Requests"`
	TokenRequests                    float64 `perflib:"Token Requests"`
	WindowsIntegratedAuthentications float64 `perflib:"Windows Integrated Authentications"`
}

func (c *adfsCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
	var adfsData []perflibADFS
	err := unmarshalObject(ctx.perfObjects["AD FS"], &adfsData)
	if err != nil {
		return err
	}

	for _, adfs := range adfsData {
		ch <- prometheus.MustNewConstMetric(
			c.adLoginConnectionFailures,
			prometheus.CounterValue,
			adfs.AdLoginConnectionFailures,
		)

		ch <- prometheus.MustNewConstMetric(
			c.certificateAuthentications,
			prometheus.CounterValue,
			adfs.CertificateAuthentications,
		)

		ch <- prometheus.MustNewConstMetric(
			c.deviceAuthentications,
			prometheus.CounterValue,
			adfs.DeviceAuthentications,
		)

		ch <- prometheus.MustNewConstMetric(
			c.extranetAccountLockouts,
			prometheus.CounterValue,
			adfs.ExtranetAccountLockouts,
		)

		ch <- prometheus.MustNewConstMetric(
			c.federatedAuthentications,
			prometheus.CounterValue,
			adfs.FederatedAuthentications,
		)

		ch <- prometheus.MustNewConstMetric(
			c.passportAuthentications,
			prometheus.CounterValue,
			adfs.PassportAuthentications,
		)

		ch <- prometheus.MustNewConstMetric(
			c.passiveRequests,
			prometheus.CounterValue,
			adfs.PassiveRequests,
		)

		ch <- prometheus.MustNewConstMetric(
			c.passwordChangeFailed,
			prometheus.CounterValue,
			adfs.PasswordChangeFailed,
		)

		ch <- prometheus.MustNewConstMetric(
			c.passwordChangeSucceeded,
			prometheus.CounterValue,
			adfs.PasswordChangeSucceeded,
		)

		ch <- prometheus.MustNewConstMetric(
			c.tokenRequests,
			prometheus.CounterValue,
			adfs.TokenRequests,
		)

		ch <- prometheus.MustNewConstMetric(
			c.windowsIntegratedAuthentications,
			prometheus.CounterValue,
			adfs.WindowsIntegratedAuthentications,
		)
	}
	return nil
}
<commit_msg>Explicitly use first ADFS result<commit_after>// +build windows

package collector

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

func init() {
	Factories["adfs"] = newADFSCollector
}

type adfsCollector struct {
	adLoginConnectionFailures        *prometheus.Desc
	certificateAuthentications       *prometheus.Desc
	deviceAuthentications            *prometheus.Desc
	extranetAccountLockouts          *prometheus.Desc
	federatedAuthentications         *prometheus.Desc
	passportAuthentications          *prometheus.Desc
	passiveRequests                  *prometheus.Desc
	passwordChangeFailed             *prometheus.Desc
	passwordChangeSucceeded          *prometheus.Desc
	tokenRequests                    *prometheus.Desc
	windowsIntegratedAuthentications *prometheus.Desc
}

// newADFSCollector constructs a new adfsCollector
func newADFSCollector() (Collector, error) {
	const subsystem = "adfs"

	return &adfsCollector{
		adLoginConnectionFailures: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "ad_login_connection_failures"),
			"Total number of connection failures to an Active Directory domain controller",
			nil,
			nil,
		),
		certificateAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "certificate_authentications"),
			"Total number of User Certificate authentications",
			nil,
			nil,
		),
		deviceAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "device_authentications"),
			"Total number of Device authentications",
			nil,
			nil,
		),
		extranetAccountLockouts: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "extranet_account_lockouts"),
			"Total number of Extranet Account Lockouts",
			nil,
			nil,
		),
		federatedAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "federated_authentications"),
			"Total number of authentications from a federated source",
			nil,
			nil,
		),
		passportAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "passport_authentications"),
			"Total number of Microsoft Passport SSO authentications",
			nil,
			nil,
		),
		passiveRequests: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "passive_requests"),
			"Total number of passive (browser-based) requests",
			nil,
			nil,
		),
		passwordChangeFailed: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "password_change_failed"),
			"Total number of failed password changes",
			nil,
			nil,
		),
		passwordChangeSucceeded: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "password_change_succeeded"),
			"Total number of successful password changes",
			nil,
			nil,
		),
		tokenRequests: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "token_requests"),
			"Total number of token requests",
			nil,
			nil,
		),
		windowsIntegratedAuthentications: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "windows_integrated_authentications"),
			"Total number of Windows integrated authentications (Kerberos/NTLM)",
			nil,
			nil,
		),
	}, nil
}

type perflibADFS struct {
	AdLoginConnectionFailures        float64 `perflib:"AD login Connection Failures"`
	CertificateAuthentications       float64 `perflib:"Certificate Authentications"`
	DeviceAuthentications            float64 `perflib:"Device Authentications"`
	ExtranetAccountLockouts          float64 `perflib:"Extranet Account Lockouts"`
	FederatedAuthentications         float64 `perflib:"Federated Authentications"`
	PassportAuthentications          float64 `perflib:"Microsoft Passport Authentications"`
	PassiveRequests                  float64 `perflib:"Passive Requests"`
	PasswordChangeFailed             float64 `perflib:"Password Change Failed Requests"`
	PasswordChangeSucceeded          float64 `perflib:"Password Change Successful Requests"`
	TokenRequests                    float64 `perflib:"Token Requests"`
	WindowsIntegratedAuthentications float64 `perflib:"Windows Integrated Authentications"`
}

func (c *adfsCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
	var adfsData []perflibADFS
	err := unmarshalObject(ctx.perfObjects["AD FS"], &adfsData)
	if err != nil {
		return err
	}

	ch <- prometheus.MustNewConstMetric(
		c.adLoginConnectionFailures,
		prometheus.CounterValue,
		adfsData[0].AdLoginConnectionFailures,
	)

	ch <- prometheus.MustNewConstMetric(
		c.certificateAuthentications,
		prometheus.CounterValue,
		adfsData[0].CertificateAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.deviceAuthentications,
		prometheus.CounterValue,
		adfsData[0].DeviceAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.extranetAccountLockouts,
		prometheus.CounterValue,
		adfsData[0].ExtranetAccountLockouts,
	)

	ch <- prometheus.MustNewConstMetric(
		c.federatedAuthentications,
		prometheus.CounterValue,
		adfsData[0].FederatedAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passportAuthentications,
		prometheus.CounterValue,
		adfsData[0].PassportAuthentications,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passiveRequests,
		prometheus.CounterValue,
		adfsData[0].PassiveRequests,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passwordChangeFailed,
		prometheus.CounterValue,
		adfsData[0].PasswordChangeFailed,
	)

	ch <- prometheus.MustNewConstMetric(
		c.passwordChangeSucceeded,
		prometheus.CounterValue,
		adfsData[0].PasswordChangeSucceeded,
	)

	ch <- prometheus.MustNewConstMetric(
		c.tokenRequests,
		prometheus.CounterValue,
		adfsData[0].TokenRequests,
	)

	ch <- prometheus.MustNewConstMetric(
		c.windowsIntegratedAuthentications,
		prometheus.CounterValue,
		adfsData[0].WindowsIntegratedAuthentications,
	)
	return nil
}
<|endoftext|>


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

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

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

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

package collectors

import (
	"context"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
	autoscaling "k8s.io/api/autoscaling/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
)

var (
	descHorizontalPodAutoscalerLabelsName          = "kube_hpa_labels"
	descHorizontalPodAutoscalerLabelsHelp          = "Kubernetes labels converted to Prometheus labels."
	descHorizontalPodAutoscalerLabelsDefaultLabels = []string{"namespace", "hpa"}

	descHorizontalPodAutoscalerMetadataGeneration = prometheus.NewDesc(
		"kube_hpa_metadata_generation",
		"The generation observed by the HorizontalPodAutoscaler controller.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerSpecMaxReplicas = prometheus.NewDesc(
		"kube_hpa_spec_max_replicas",
		"Upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerSpecMinReplicas = prometheus.NewDesc(
		"kube_hpa_spec_min_replicas",
		"Lower limit for the number of pods that can be set by the autoscaler, default 1.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerStatusCurrentReplicas = prometheus.NewDesc(
		"kube_hpa_status_current_replicas",
		"Current number of replicas of pods managed by this autoscaler.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerStatusDesiredReplicas = prometheus.NewDesc(
		"kube_hpa_status_desired_replicas",
		"Desired number of replicas of pods managed by this autoscaler.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerLabels = prometheus.NewDesc(
		descHorizontalPodAutoscalerLabelsName,
		descHorizontalPodAutoscalerLabelsHelp,
		descHorizontalPodAutoscalerLabelsDefaultLabels, nil,
	)
)

type HPALister func() (autoscaling.HorizontalPodAutoscalerList, error)

func (l HPALister) List() (autoscaling.HorizontalPodAutoscalerList, error) {
	return l()
}

func RegisterHorizontalPodAutoScalerCollector(registry prometheus.Registerer, kubeClient kubernetes.Interface, namespace string) {
	client := kubeClient.Autoscaling().RESTClient()
	glog.Infof("collect hpa with %s", client.APIVersion())
	hpalw := cache.NewListWatchFromClient(client, "horizontalpodautoscalers", metav1.NamespaceAll, fields.Everything())
	hpainf := cache.NewSharedInformer(hpalw, &autoscaling.HorizontalPodAutoscaler{}, resyncPeriod)

	hpaLister := HPALister(func() (hpas autoscaling.HorizontalPodAutoscalerList, err error) {
		for _, h := range hpainf.GetStore().List() {
			hpas.Items = append(hpas.Items, *(h.(*autoscaling.HorizontalPodAutoscaler)))
		}
		return hpas, nil
	})

	registry.MustRegister(&hpaCollector{store: hpaLister})
	go hpainf.Run(context.Background().Done())
}

type hpaStore interface {
	List() (hpas autoscaling.HorizontalPodAutoscalerList, err error)
}

// hpaCollector collects metrics about all Horizontal Pod Austoscalers in the cluster.
type hpaCollector struct {
	store hpaStore
}

// Describe implements the prometheus.Collector interface.
func (hc *hpaCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- descHorizontalPodAutoscalerMetadataGeneration
	ch <- descHorizontalPodAutoscalerSpecMaxReplicas
	ch <- descHorizontalPodAutoscalerSpecMinReplicas
	ch <- descHorizontalPodAutoscalerStatusCurrentReplicas
	ch <- descHorizontalPodAutoscalerStatusDesiredReplicas
	ch <- descHorizontalPodAutoscalerLabels
}

// Collect implements the prometheus.Collector interface.
func (hc *hpaCollector) Collect(ch chan<- prometheus.Metric) {
	hpas, err := hc.store.List()
	if err != nil {
		ScrapeErrorTotalMetric.With(prometheus.Labels{"resource": "horizontalpodautoscaler"}).Inc()
		glog.Errorf("listing HorizontalPodAutoscalers failed: %s", err)
		return
	}
	ScrapeErrorTotalMetric.With(prometheus.Labels{"resource": "horizontalpodautoscaler"}).Add(0)

	ResourcesPerScrapeMetric.With(prometheus.Labels{"resource": "horizontalpodautoscaler"}).Observe(float64(len(hpas.Items)))
	for _, h := range hpas.Items {
		hc.collectHPA(ch, h)
	}

	glog.V(4).Infof("collected %d hpas", len(hpas.Items))
}

func hpaLabelsDesc(labelKeys []string) *prometheus.Desc {
	return prometheus.NewDesc(
		descHorizontalPodAutoscalerLabelsName,
		descHorizontalPodAutoscalerLabelsHelp,
		append(descHorizontalPodAutoscalerLabelsDefaultLabels, labelKeys...),
		nil,
	)
}

func (hc *hpaCollector) collectHPA(ch chan<- prometheus.Metric, h autoscaling.HorizontalPodAutoscaler) {
	addGauge := func(desc *prometheus.Desc, v float64, lv ...string) {
		lv = append([]string{h.Namespace, h.Name}, lv...)
		ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, v, lv...)
	}
	labelKeys, labelValues := kubeLabelsToPrometheusLabels(h.Labels)
	addGauge(hpaLabelsDesc(labelKeys), 1, labelValues...)
	addGauge(descHorizontalPodAutoscalerMetadataGeneration, float64(h.ObjectMeta.Generation))
	addGauge(descHorizontalPodAutoscalerSpecMaxReplicas, float64(h.Spec.MaxReplicas))
	addGauge(descHorizontalPodAutoscalerSpecMinReplicas, float64(*h.Spec.MinReplicas))
	addGauge(descHorizontalPodAutoscalerStatusCurrentReplicas, float64(h.Status.CurrentReplicas))
	addGauge(descHorizontalPodAutoscalerStatusDesiredReplicas, float64(h.Status.DesiredReplicas))
}
<commit_msg>Fix namespacing of HPA<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package collectors

import (
	"context"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
	autoscaling "k8s.io/api/autoscaling/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
)

var (
	descHorizontalPodAutoscalerLabelsName          = "kube_hpa_labels"
	descHorizontalPodAutoscalerLabelsHelp          = "Kubernetes labels converted to Prometheus labels."
	descHorizontalPodAutoscalerLabelsDefaultLabels = []string{"namespace", "hpa"}

	descHorizontalPodAutoscalerMetadataGeneration = prometheus.NewDesc(
		"kube_hpa_metadata_generation",
		"The generation observed by the HorizontalPodAutoscaler controller.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerSpecMaxReplicas = prometheus.NewDesc(
		"kube_hpa_spec_max_replicas",
		"Upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerSpecMinReplicas = prometheus.NewDesc(
		"kube_hpa_spec_min_replicas",
		"Lower limit for the number of pods that can be set by the autoscaler, default 1.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerStatusCurrentReplicas = prometheus.NewDesc(
		"kube_hpa_status_current_replicas",
		"Current number of replicas of pods managed by this autoscaler.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerStatusDesiredReplicas = prometheus.NewDesc(
		"kube_hpa_status_desired_replicas",
		"Desired number of replicas of pods managed by this autoscaler.",
		[]string{"namespace", "hpa"}, nil,
	)
	descHorizontalPodAutoscalerLabels = prometheus.NewDesc(
		descHorizontalPodAutoscalerLabelsName,
		descHorizontalPodAutoscalerLabelsHelp,
		descHorizontalPodAutoscalerLabelsDefaultLabels, nil,
	)
)

type HPALister func() (autoscaling.HorizontalPodAutoscalerList, error)

func (l HPALister) List() (autoscaling.HorizontalPodAutoscalerList, error) {
	return l()
}

func RegisterHorizontalPodAutoScalerCollector(registry prometheus.Registerer, kubeClient kubernetes.Interface, namespace string) {
	client := kubeClient.Autoscaling().RESTClient()
	glog.Infof("collect hpa with %s", client.APIVersion())
	hpalw := cache.NewListWatchFromClient(client, "horizontalpodautoscalers", namespace, fields.Everything())
	hpainf := cache.NewSharedInformer(hpalw, &autoscaling.HorizontalPodAutoscaler{}, resyncPeriod)

	hpaLister := HPALister(func() (hpas autoscaling.HorizontalPodAutoscalerList, err error) {
		for _, h := range hpainf.GetStore().List() {
			hpas.Items = append(hpas.Items, *(h.(*autoscaling.HorizontalPodAutoscaler)))
		}
		return hpas, nil
	})

	registry.MustRegister(&hpaCollector{store: hpaLister})
	go hpainf.Run(context.Background().Done())
}

type hpaStore interface {
	List() (hpas autoscaling.HorizontalPodAutoscalerList, err error)
}

// hpaCollector collects metrics about all Horizontal Pod Austoscalers in the cluster.
type hpaCollector struct {
	store hpaStore
}

// Describe implements the prometheus.Collector interface.
func (hc *hpaCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- descHorizontalPodAutoscalerMetadataGeneration
	ch <- descHorizontalPodAutoscalerSpecMaxReplicas
	ch <- descHorizontalPodAutoscalerSpecMinReplicas
	ch <- descHorizontalPodAutoscalerStatusCurrentReplicas
	ch <- descHorizontalPodAutoscalerStatusDesiredReplicas
	ch <- descHorizontalPodAutoscalerLabels
}

// Collect implements the prometheus.Collector interface.
func (hc *hpaCollector) Collect(ch chan<- prometheus.Metric) {
	hpas, err := hc.store.List()
	if err != nil {
		ScrapeErrorTotalMetric.With(prometheus.Labels{"resource": "horizontalpodautoscaler"}).Inc()
		glog.Errorf("listing HorizontalPodAutoscalers failed: %s", err)
		return
	}
	ScrapeErrorTotalMetric.With(prometheus.Labels{"resource": "horizontalpodautoscaler"}).Add(0)

	ResourcesPerScrapeMetric.With(prometheus.Labels{"resource": "horizontalpodautoscaler"}).Observe(float64(len(hpas.Items)))
	for _, h := range hpas.Items {
		hc.collectHPA(ch, h)
	}

	glog.V(4).Infof("collected %d hpas", len(hpas.Items))
}

func hpaLabelsDesc(labelKeys []string) *prometheus.Desc {
	return prometheus.NewDesc(
		descHorizontalPodAutoscalerLabelsName,
		descHorizontalPodAutoscalerLabelsHelp,
		append(descHorizontalPodAutoscalerLabelsDefaultLabels, labelKeys...),
		nil,
	)
}

func (hc *hpaCollector) collectHPA(ch chan<- prometheus.Metric, h autoscaling.HorizontalPodAutoscaler) {
	addGauge := func(desc *prometheus.Desc, v float64, lv ...string) {
		lv = append([]string{h.Namespace, h.Name}, lv...)
		ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, v, lv...)
	}
	labelKeys, labelValues := kubeLabelsToPrometheusLabels(h.Labels)
	addGauge(hpaLabelsDesc(labelKeys), 1, labelValues...)
	addGauge(descHorizontalPodAutoscalerMetadataGeneration, float64(h.ObjectMeta.Generation))
	addGauge(descHorizontalPodAutoscalerSpecMaxReplicas, float64(h.Spec.MaxReplicas))
	addGauge(descHorizontalPodAutoscalerSpecMinReplicas, float64(*h.Spec.MinReplicas))
	addGauge(descHorizontalPodAutoscalerStatusCurrentReplicas, float64(h.Status.CurrentReplicas))
	addGauge(descHorizontalPodAutoscalerStatusDesiredReplicas, float64(h.Status.DesiredReplicas))
}
<|endoftext|>


<commit_before>package linebot

import (
	"fmt"
	"regexp"

	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/pkg/errors"
	"github.com/utahta/momoclo-channel/appengine/lib/googleapi/customsearch"
	"github.com/utahta/momoclo-channel/appengine/lib/log"
	"golang.org/x/net/context"
)

var (
	ErrorHandleOnOffNotMatch = errors.New("handle on off not match.")
	ErrorHandleImageNotMatch = errors.New("handle image not match.")
)

// handle line message events.
func HandleEvents(ctx context.Context, events []*linebot.Event) error {
	for _, event := range events {
		switch event.Type {
		case linebot.EventTypeMessage:
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				if err := textMessageEvent(ctx, message, event); err != nil {
					log.GaeLog(ctx).Error(err)
					continue
				}
			}
		case linebot.EventTypeFollow:
			err := followEvent(ctx, event)
			if err != nil {
				return err
			}
		case linebot.EventTypeUnfollow:
			err := unfollowEvent(ctx, event)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func onMessage(ctx context.Context) string {
	onURL := fmt.Sprintf("%s%s", ctx.Value("baseURL").(string), "/linenotify/on")
	return fmt.Sprintf("通知機能を有効にする場合は、下記URLから設定を行ってください（・Θ・）\n%s", onURL)
}

func helpMessage(ctx context.Context) string {
	helpURL := fmt.Sprintf("%s%s", ctx.Value("baseURL").(string), "/linebot/help")
	return fmt.Sprintf("ヘルプ（・Θ・）\n%s", helpURL)
}

func followEvent(ctx context.Context, event *linebot.Event) error {
	log.GaeLog(ctx).Infof("follow user. event:%v", event)

	message := "友だち追加ありがとうございます。\nこちらは、ももクロちゃんのブログやAE NEWS等を通知する機能との連携を補助したり、画像を返したりするBOTです。"
	return ReplyText(ctx, event.ReplyToken, fmt.Sprintf("%s\n\n%s\n\n%s", message, onMessage(ctx), helpMessage(ctx)))
}

func unfollowEvent(ctx context.Context, event *linebot.Event) error {
	log.GaeLog(ctx).Infof("unfollow user. event:%v", event)
	return nil
}

func textMessageEvent(ctx context.Context, message *linebot.TextMessage, event *linebot.Event) error {
	log.GaeLog(ctx).Infof("handle text content. message:%s", message.Text)

	if err := handleOnOff(ctx, message, event); err != ErrorHandleOnOffNotMatch {
		return err
	}

	if err := handleMemberImage(ctx, message, event); err != ErrorHandleImageNotMatch {
		return err
	}

	return ReplyText(ctx, event.ReplyToken, helpMessage(ctx))
}

func handleOnOff(ctx context.Context, message *linebot.TextMessage, event *linebot.Event) error {
	var (
		matched bool
		err     error
	)
	text := message.Text
	matched, err = regexp.MatchString("^(おん|オン|on)$", text)
	if err != nil {
		return err
	}
	if matched {
		return ReplyText(ctx, event.ReplyToken, onMessage(ctx))
	}

	matched, err = regexp.MatchString("^(おふ|オフ|off)$", text)
	if err != nil {
		return err
	}
	if matched {
		return ReplyText(ctx, event.ReplyToken, "通知機能を無効にする場合は、下記URLから解除を行ってください（・Θ・）\nhttps://notify-bot.line.me/my/")
	}

	return ErrorHandleOnOffNotMatch
}

func handleMemberImage(ctx context.Context, message *linebot.TextMessage, event *linebot.Event) error {
	var (
		matched bool
		err     error
	)
	text := message.Text
	word := ""
	matched, err = regexp.MatchString("玉井|[たタ][まマ][いイ]|[しシ][おオ][りリ][んン]?|詩織|玉さん|[たタ][まマ]さん", text)
	if err != nil {
		return err
	}
	if matched {
		word = "玉井詩織"
	}
	matched, err = regexp.MatchString("百田|[もモ][もモ][たタ]|[夏かカ][菜なナ][子こコ]", text)
	if err != nil {
		return err
	}
	if matched {
		word = "百田夏菜子"
	}
	matched, err = regexp.MatchString("有安|[あア][りリ][やヤ][すス]|[もモ][もモ][かカ]|杏果", text)
	if err != nil {
		return err
	}
	if matched {
		word = "有安杏果"
	}
	matched, err = regexp.MatchString("佐々木|[さサ][さサ][きキ]|[あア][やヤ][かカ]|彩夏|[あア]ー[りリ][んン]", text)
	if err != nil {
		return err
	}
	if matched {
		word = "佐々木彩夏"
	}
	matched, err = regexp.MatchString("高城|[たタ][かカ][ぎギ]|[れレ][にニ]", text)
	if err != nil {
		return err
	}
	if matched {
		word = "高城れに"
	}

	if word == "" {
		return ErrorHandleImageNotMatch
	}

	res, err := customsearch.SearchImage(ctx, word)
	if err != nil {
		log.GaeLog(ctx).Error(err)
		return ReplyText(ctx, event.ReplyToken, "画像がみつかりませんでした（・Θ・）")
	}
	return ReplyImage(ctx, event.ReplyToken, res.Url, res.ThumbnailUrl)
}
<commit_msg>Fix line bot message<commit_after>package linebot

import (
	"fmt"
	"regexp"

	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/pkg/errors"
	"github.com/utahta/momoclo-channel/appengine/lib/googleapi/customsearch"
	"github.com/utahta/momoclo-channel/appengine/lib/log"
	"golang.org/x/net/context"
)

var (
	ErrorHandleOnOffNotMatch = errors.New("handle on off not match.")
	ErrorHandleImageNotMatch = errors.New("handle image not match.")
)

// handle line message events.
func HandleEvents(ctx context.Context, events []*linebot.Event) error {
	for _, event := range events {
		switch event.Type {
		case linebot.EventTypeMessage:
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				if err := textMessageEvent(ctx, message, event); err != nil {
					log.GaeLog(ctx).Error(err)
					continue
				}
			}
		case linebot.EventTypeFollow:
			err := followEvent(ctx, event)
			if err != nil {
				return err
			}
		case linebot.EventTypeUnfollow:
			err := unfollowEvent(ctx, event)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func onMessage(ctx context.Context) string {
	onURL := fmt.Sprintf("%s%s", ctx.Value("baseURL").(string), "/linenotify/on")
	return fmt.Sprintf("通知機能を有効にする場合は、下記URLをクリックしてください（・Θ・）\n%s", onURL)
}

func helpMessage(ctx context.Context) string {
	helpURL := fmt.Sprintf("%s%s", ctx.Value("baseURL").(string), "/linebot/help")
	return fmt.Sprintf("ヘルプ（・Θ・）\n%s", helpURL)
}

func followEvent(ctx context.Context, event *linebot.Event) error {
	log.GaeLog(ctx).Infof("follow user. event:%v", event)

	message := fmt.Sprintf(`友だち追加ありがとうございます。
こちらは、ももクロちゃんのブログやAE NEWS等を通知する機能との連携を補助したり、画像を返したりするBOTです。

%s

%s
`, helpMessage(ctx), onMessage(ctx))
	return ReplyText(ctx, event.ReplyToken, message)
}

func unfollowEvent(ctx context.Context, event *linebot.Event) error {
	log.GaeLog(ctx).Infof("unfollow user. event:%v", event)
	return nil
}

func textMessageEvent(ctx context.Context, message *linebot.TextMessage, event *linebot.Event) error {
	log.GaeLog(ctx).Infof("handle text content. message:%s", message.Text)

	if err := handleOnOff(ctx, message, event); err != ErrorHandleOnOffNotMatch {
		return err
	}

	if err := handleMemberImage(ctx, message, event); err != ErrorHandleImageNotMatch {
		return err
	}

	return ReplyText(ctx, event.ReplyToken, helpMessage(ctx))
}

func handleOnOff(ctx context.Context, message *linebot.TextMessage, event *linebot.Event) error {
	var (
		matched bool
		err     error
	)
	text := message.Text
	matched, err = regexp.MatchString("^(おん|オン|on)$", text)
	if err != nil {
		return err
	}
	if matched {
		return ReplyText(ctx, event.ReplyToken, onMessage(ctx))
	}

	matched, err = regexp.MatchString("^(おふ|オフ|off)$", text)
	if err != nil {
		return err
	}
	if matched {
		return ReplyText(ctx, event.ReplyToken, "通知機能を無効にする場合は、下記URLから解除を行ってください（・Θ・）\nhttps://notify-bot.line.me/my/")
	}

	return ErrorHandleOnOffNotMatch
}

func handleMemberImage(ctx context.Context, message *linebot.TextMessage, event *linebot.Event) error {
	var (
		matched bool
		err     error
	)
	text := message.Text
	word := ""
	matched, err = regexp.MatchString("玉井|[たタ][まマ][いイ]|[しシ][おオ][りリ][んン]?|詩織|玉さん|[たタ][まマ]さん", text)
	if err != nil {
		return err
	}
	if matched {
		word = "玉井詩織"
	}
	matched, err = regexp.MatchString("百田|[もモ][もモ][たタ]|[夏かカ][菜なナ][子こコ]", text)
	if err != nil {
		return err
	}
	if matched {
		word = "百田夏菜子"
	}
	matched, err = regexp.MatchString("有安|[あア][りリ][やヤ][すス]|[もモ][もモ][かカ]|杏果", text)
	if err != nil {
		return err
	}
	if matched {
		word = "有安杏果"
	}
	matched, err = regexp.MatchString("佐々木|[さサ][さサ][きキ]|[あア][やヤ][かカ]|彩夏|[あア]ー[りリ][んン]", text)
	if err != nil {
		return err
	}
	if matched {
		word = "佐々木彩夏"
	}
	matched, err = regexp.MatchString("高城|[たタ][かカ][ぎギ]|[れレ][にニ]", text)
	if err != nil {
		return err
	}
	if matched {
		word = "高城れに"
	}

	if word == "" {
		return ErrorHandleImageNotMatch
	}

	res, err := customsearch.SearchImage(ctx, word)
	if err != nil {
		log.GaeLog(ctx).Error(err)
		return ReplyText(ctx, event.ReplyToken, "画像がみつかりませんでした（・Θ・）")
	}
	return ReplyImage(ctx, event.ReplyToken, res.Url, res.ThumbnailUrl)
}
<|endoftext|>


<commit_before>package ocspStatusWorker

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"crypto/x509"

	"github.com/mozilla/tls-observatory/logger"
	"github.com/mozilla/tls-observatory/worker"
	"golang.org/x/crypto/ocsp"
	"bytes"
	"crypto"
	"crypto/tls"
	"time"
	"encoding/base64"
)

var workerName = "ocspStatusWorker"
var workerDesc = `Determines a certificate's status via OCSP'`

var log = logger.GetLogger()

func init() {
	worker.RegisterWorker(workerName, worker.Info{Runner: new(ocspStatusWorker), Description: workerDesc})
}

type ocspStatusWorker struct {
	status OCSPStatus
}

type OCSPStatus struct {
	Status int `json:"status"`
	RevokedAt time.Time `json:"revoked_at"`

}

type params struct {
}

func (w ocspStatusWorker) Run(in worker.Input, resChan chan worker.Result) {
	res := worker.Result{WorkerName: workerName, Success:false}

	rawCert := base64.DecodeString(worker.Input.CertificateChain.Certs[0])
	certificate := x509.ParseCertificate(rawCert)
	rawIssuerCert := base64.DecodeString(worker.Input.CertificateChain.Certs[1])
	issuerCertificate := x509.ParseCertificate(rawIssuerCert)

	opts := &ocsp.RequestOptions{Hash: crypto.SHA256}
	req, err := ocsp.CreateRequest(certificate, issuerCertificate, opts)
	if err != nil {
		res.Errors = append(res.Errors, err.Error())
		return
	}

	httpResponse, err := http.Post(certificate.OCSPServer[0], "application/ocsp-request", bytes.NewReader(req))
	if err != nil {
		res.Errors = append(res.Errors, err.Error())
		return
	}

	output, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		res.Errors = append(res.Errors, err.Error())
		return
	}

	OCSPResponse, err := ocsp.ParseResponse(output, issuerCertificate)
	if err != nil {
		res.Errors = append(res.Errors, err.Error())
		return
	}

	status := OCSPStatus{ Status:OCSPResponse.Status, RevokedAt:OCSPResponse.RevokedAt }

	out, _ := json.Marshal(status)

	res.Success = true
	res.Result = out

	resChan <- res
}
<commit_msg>Fixed build errors<commit_after>package ocspStatusWorker

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"crypto/x509"

	"github.com/mozilla/tls-observatory/logger"
	"github.com/mozilla/tls-observatory/worker"
	"golang.org/x/crypto/ocsp"
	"bytes"
	"crypto"
	"time"
	"encoding/base64"
)

var workerName = "ocspStatusWorker"
var workerDesc = `Determines a certificate's status via OCSP'`

var log = logger.GetLogger()

func init() {
	worker.RegisterWorker(workerName, worker.Info{Runner: new(ocspStatusWorker), Description: workerDesc})
}

type ocspStatusWorker struct {
	status OCSPStatus
}

type OCSPStatus struct {
	Status int `json:"status"`
	RevokedAt time.Time `json:"revoked_at"`

}

type params struct {
}

func (w ocspStatusWorker) Run(in worker.Input, resChan chan worker.Result) {
	res := worker.Result{WorkerName: workerName, Success:false}

	rawCert, _ := base64.StdEncoding.DecodeString(in.CertificateChain.Certs[0])
	certificate, _ := x509.ParseCertificate(rawCert)
	rawIssuerCert, _ := base64.StdEncoding.DecodeString(in.CertificateChain.Certs[1])
	issuerCertificate, _ := x509.ParseCertificate(rawIssuerCert)

	opts := &ocsp.RequestOptions{Hash: crypto.SHA256}
	req, err := ocsp.CreateRequest(certificate, issuerCertificate, opts)
	if err != nil {
		res.Errors = append(res.Errors, err.Error())
		return
	}

	httpResponse, err := http.Post(certificate.OCSPServer[0], "application/ocsp-request", bytes.NewReader(req))
	if err != nil {
		res.Errors = append(res.Errors, err.Error())
		return
	}

	output, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		res.Errors = append(res.Errors, err.Error())
		return
	}

	OCSPResponse, err := ocsp.ParseResponse(output, issuerCertificate)
	if err != nil {
		res.Errors = append(res.Errors, err.Error())
		return
	}

	status := OCSPStatus{ Status:OCSPResponse.Status, RevokedAt:OCSPResponse.RevokedAt }

	out, _ := json.Marshal(status)

	res.Success = true
	res.Result = out

	resChan <- res
}
<|endoftext|>