Merge pull request #1391 from weaveworks/1380-k8s-checkpoint-flag

Add kubernetes checkpoint flag
This commit is contained in:
Alfonso Acosta
2016-04-28 15:59:31 +01:00
9 changed files with 261 additions and 83 deletions

View File

@@ -42,7 +42,7 @@ const (
var pluginAPIVersion = "1"
func check() {
func check(flags map[string]string) {
handleResponse := func(r *checkpoint.CheckResponse, err error) {
if err != nil {
log.Errorf("Error checking version: %v", err)
@@ -56,6 +56,7 @@ func check() {
params := checkpoint.CheckParams{
Product: "scope-probe",
Version: version,
Flags: flags,
}
resp, err := checkpoint.Check(&params)
handleResponse(resp, err)
@@ -87,7 +88,11 @@ func probeMain(flags probeFlags) {
)
log.Infof("probe starting, version %s, ID %s", version, probeID)
log.Infof("command line: %v", os.Args)
go check()
checkpointFlags := map[string]string{}
if flags.kubernetesEnabled {
checkpointFlags["kubernetes_enabled"] = "true"
}
go check(checkpointFlags)
var targets = []string{fmt.Sprintf("localhost:%d", xfer.AppPort)}
if len(flag.Args()) > 0 {

View File

@@ -1,24 +1,36 @@
.PHONY: all build test lint
BUILD_IN_CONTAINER ?= true
RM=--rm
BUILD_IMAGE=golang:1.5.3
BUILD_UPTODATE=backend/.image.uptodate
BUILD_IMAGE=checkpoint_build
all: build
$(BUILD_UPTODATE): backend/*
docker build -t $(BUILD_IMAGE) backend
touch $@
ifeq ($(BUILD_IN_CONTAINER),true)
all test:
build test lint: $(BUILD_UPTODATE)
$(SUDO) docker run $(RM) -ti \
-v $(shell pwd):/go/src/github.com/weaveworks/go-checkpoint \
-e GOARCH -e GOOS -e BUILD_IN_CONTAINER=false \
$(BUILD_IMAGE) make -C /go/src/github.com/weaveworks/go-checkpoint $@
$(BUILD_IMAGE) $@
else
all:
build:
go get .
go build .
test:
go get .
go get -t .
go test
lint:
./tools/lint -notestpackage .
endif

View File

@@ -1,22 +1,29 @@
# Go Checkpoint Client
[Checkpoint](http://checkpoint.hashicorp.com) is an internal service at
Hashicorp that we use to check version information, broadcoast security
bulletins, etc.
[![Circle CI](https://circleci.com/gh/weaveworks/go-checkpoint/tree/master.svg?style=shield)](https://circleci.com/gh/weaveworks/go-checkpoint/tree/master)
We understand that software making remote calls over the internet
for any reason can be undesirable. Because of this, Checkpoint can be
disabled in all of our software that includes it. You can view the source
of this client to see that we're not sending any private information.
Checkpoint is an internal service at
[Weaveworks](https://www.weave.works/) to check version information,
broadcast security bulletins, etc. This repository contains the client
code for accessing that service. It is a fork of
[Hashicorp's Go Checkpoint Client](https://github.com/hashicorp/go-checkpoint)
and is embedded in several
[Weaveworks open source projects](https://github.com/weaveworks/) and
proprietary software.
We understand that software making remote calls over the internet for
any reason can be undesirable. Because of this, Checkpoint can be
disabled in all of Weavework's software that includes it. You can view
the source of this client to see that it is not sending any private
information.
To disable checkpoint calls, set the `CHECKPOINT_DISABLE` environment
variable, e.g.
Each Hashicorp application has it's specific configuration option
to disable chekpoint calls, but the `CHECKPOINT_DISABLE` makes
the underlying checkpoint component itself disabled. For example
in the case of packer:
```
CHECKPOINT_DISABLE=1 packer build
export CHECKPOINT_DISABLE=1
```
**Note:** This repository is probably useless outside of internal HashiCorp
use. It is open source for disclosure and because our open source projects
must be able to link to it.
**Note:** This repository is probably useless outside of internal
Weaveworks use. It is open source for disclosure and because
Weaveworks open source projects must be able to link to it.

View File

@@ -0,0 +1,12 @@
FROM golang:1.6.2
RUN apt-get update && \
apt-get install -y python-requests time file sudo && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN go get -tags netgo \
github.com/fzipp/gocyclo \
github.com/golang/lint/golint \
github.com/kisielk/errcheck \
github.com/client9/misspell/cmd/misspell && \
rm -rf /go/pkg/ /go/src/
COPY build.sh /
ENTRYPOINT ["/build.sh"]

View File

@@ -0,0 +1,23 @@
#!/bin/sh
set -eu
SRC=$GOPATH/src/github.com/weaveworks/go-checkpoint
# Mount the checkpoint repo:
# -v $(pwd):/go/src/github.com/weaveworks/checkpoint
# If we run make directly, any files created on the bind mount
# will have awkward ownership. So we switch to a user with the
# same user and group IDs as source directory. We have to set a
# few things up so that sudo works without complaining later on.
uid=$(stat --format="%u" $SRC)
gid=$(stat --format="%g" $SRC)
echo "weave:x:$uid:$gid::$SRC:/bin/sh" >>/etc/passwd
echo "weave:*:::::::" >>/etc/shadow
echo "weave ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
chmod o+rw $GOPATH/src
chmod o+rw $GOPATH/src/github.com
su weave -c "PATH=$PATH make -C $SRC BUILD_IN_CONTAINER=false $*"

View File

@@ -1,5 +1,5 @@
// checkpoint is a package for checking version information and alerts
// for a HashiCorp product.
// Package checkpoint is a package for checking version information and alerts
// for a Weaveworks product.
package checkpoint
import (
@@ -19,12 +19,13 @@ import (
"reflect"
"runtime"
"strings"
"sync"
"time"
"github.com/hashicorp/go-cleanhttp"
)
var magicBytes [4]byte = [4]byte{0x35, 0x77, 0x69, 0xFB}
var magicBytes = [4]byte{0x35, 0x77, 0x69, 0xFB}
// CheckParams are the parameters for configuring a check request.
type CheckParams struct {
@@ -34,6 +35,9 @@ type CheckParams struct {
Product string
Version string
// Generic product flags
Flags map[string]string
// Arch and OS are used to filter alerts potentially only to things
// affecting a specific os/arch combination. If these aren't specified,
// they'll be automatically filled in.
@@ -95,9 +99,16 @@ type CheckAlert struct {
Level string
}
// Checker is a state of a checker.
type Checker struct {
doneCh chan struct{}
nextCheckAt time.Time
nextCheckAtLock sync.RWMutex
}
// Check checks for alerts and new version information.
func Check(p *CheckParams) (*CheckResponse, error) {
if disabled := os.Getenv("CHECKPOINT_DISABLE"); disabled != "" && !p.Force {
if IsCheckDisabled() && !p.Force {
return &CheckResponse{}, nil
}
@@ -138,6 +149,9 @@ func Check(p *CheckParams) (*CheckResponse, error) {
v.Set("arch", p.Arch)
v.Set("os", p.OS)
v.Set("signature", signature)
for flag, value := range p.Flags {
v.Set("flag_"+flag, value)
}
u.Scheme = "https"
u.Host = "checkpoint-api.weave.works"
@@ -193,27 +207,56 @@ func Check(p *CheckParams) (*CheckResponse, error) {
// CheckInterval is used to check for a response on a given interval duration.
// The interval is not exact, and checks are randomized to prevent a thundering
// herd. However, it is expected that on average one check is performed per
// interval. The returned channel may be closed to stop background checks.
func CheckInterval(p *CheckParams, interval time.Duration, cb func(*CheckResponse, error)) chan struct{} {
doneCh := make(chan struct{})
// interval.
// The first check happens immediately after a goroutine which is responsible for
// making checks has been started.
func CheckInterval(p *CheckParams, interval time.Duration,
cb func(*CheckResponse, error)) *Checker {
if disabled := os.Getenv("CHECKPOINT_DISABLE"); disabled != "" {
return doneCh
state := &Checker{
doneCh: make(chan struct{}),
}
if IsCheckDisabled() {
return state
}
go func() {
cb(Check(p))
for {
after := randomStagger(interval)
state.nextCheckAtLock.Lock()
state.nextCheckAt = time.Now().Add(after)
state.nextCheckAtLock.Unlock()
select {
case <-time.After(randomStagger(interval)):
resp, err := Check(p)
cb(resp, err)
case <-doneCh:
case <-time.After(after):
cb(Check(p))
case <-state.doneCh:
return
}
}
}()
return doneCh
return state
}
// NextCheckAt returns at what time next check will happen.
func (c *Checker) NextCheckAt() time.Time {
c.nextCheckAtLock.RLock()
defer c.nextCheckAtLock.RUnlock()
return c.nextCheckAt
}
// Stop stops the checker.
func (c *Checker) Stop() {
close(c.doneCh)
}
// IsCheckDisabled returns true if checks are disabled.
func IsCheckDisabled() bool {
return os.Getenv("CHECKPOINT_DISABLE") != ""
}
// randomStagger returns an interval that is between 3/4 and 5/4 of
@@ -369,7 +412,7 @@ func writeCacheHeader(f io.Writer, v string) error {
}
// Write out our current version length
var length uint32 = uint32(len(v))
var length = uint32(len(v))
if err := binary.Write(f, binary.LittleEndian, length); err != nil {
return err
}

View File

@@ -11,19 +11,47 @@ import (
func TestCheck(t *testing.T) {
expected := &CheckResponse{
Product: "test",
CurrentVersion: "1.0",
CurrentReleaseDate: 0,
CurrentDownloadURL: "http://www.hashicorp.com",
CurrentChangelogURL: "http://www.hashicorp.com",
ProjectWebsite: "http://www.hashicorp.com",
CurrentVersion: "1.0.0",
CurrentReleaseDate: 1460459932, // 2016-04-12 11:18:52
CurrentDownloadURL: "https://test-app.used-for-testing",
CurrentChangelogURL: "https://test-app.used-for-testing",
ProjectWebsite: "https://test-app.used-for-testing",
Outdated: false,
Alerts: []*CheckAlert{},
Alerts: nil,
}
actual, err := Check(&CheckParams{
Product: "test",
Version: "1.0",
Product: "test-app",
Version: "1.0.0",
})
if err != nil {
t.Fatalf("err: %s", err)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
}
}
func TestCheck_flags(t *testing.T) {
expected := &CheckResponse{
CurrentVersion: "1.0.0",
CurrentReleaseDate: 1460459932, // 2016-04-12 11:18:52
CurrentDownloadURL: "https://test-app.used-for-testing",
CurrentChangelogURL: "https://test-app.used-for-testing",
ProjectWebsite: "https://test-app.used-for-testing",
Outdated: false,
Alerts: nil,
}
actual, err := Check(&CheckParams{
Product: "test-app",
Version: "1.0.0",
Flags: map[string]string{
"flag1": "value1",
"flag2": "value2",
},
})
if err != nil {
@@ -42,8 +70,8 @@ func TestCheck_disabled(t *testing.T) {
expected := &CheckResponse{}
actual, err := Check(&CheckParams{
Product: "test",
Version: "1.0",
Product: "test-app",
Version: "1.0.0",
})
if err != nil {
@@ -62,22 +90,21 @@ func TestCheck_cache(t *testing.T) {
}
expected := &CheckResponse{
Product: "test",
CurrentVersion: "1.0",
CurrentReleaseDate: 0,
CurrentDownloadURL: "http://www.hashicorp.com",
CurrentChangelogURL: "http://www.hashicorp.com",
ProjectWebsite: "http://www.hashicorp.com",
CurrentVersion: "1.0.0",
CurrentReleaseDate: 1460459932, // 2016-04-12 11:18:52
CurrentDownloadURL: "https://test-app.used-for-testing",
CurrentChangelogURL: "https://test-app.used-for-testing",
ProjectWebsite: "https://test-app.used-for-testing",
Outdated: false,
Alerts: []*CheckAlert{},
Alerts: nil,
}
var actual *CheckResponse
for i := 0; i < 5; i++ {
var err error
actual, err = Check(&CheckParams{
Product: "test",
Version: "1.0",
Product: "test-app",
Version: "1.0.0",
CacheFile: filepath.Join(dir, "cache"),
})
if err != nil {
@@ -86,7 +113,7 @@ func TestCheck_cache(t *testing.T) {
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
t.Fatalf("bad: %#v %#v", actual, expected)
}
}
@@ -97,22 +124,21 @@ func TestCheck_cacheNested(t *testing.T) {
}
expected := &CheckResponse{
Product: "test",
CurrentVersion: "1.0",
CurrentReleaseDate: 0,
CurrentDownloadURL: "http://www.hashicorp.com",
CurrentChangelogURL: "http://www.hashicorp.com",
ProjectWebsite: "http://www.hashicorp.com",
CurrentVersion: "1.0.0",
CurrentReleaseDate: 1460459932, // 2016-04-12 11:18:52
CurrentDownloadURL: "https://test-app.used-for-testing",
CurrentChangelogURL: "https://test-app.used-for-testing",
ProjectWebsite: "https://test-app.used-for-testing",
Outdated: false,
Alerts: []*CheckAlert{},
Alerts: nil,
}
var actual *CheckResponse
for i := 0; i < 5; i++ {
var err error
actual, err = Check(&CheckParams{
Product: "test",
Version: "1.0",
Product: "test-app",
Version: "1.0.0",
CacheFile: filepath.Join(dir, "nested", "cache"),
})
if err != nil {
@@ -127,19 +153,18 @@ func TestCheck_cacheNested(t *testing.T) {
func TestCheckInterval(t *testing.T) {
expected := &CheckResponse{
Product: "test",
CurrentVersion: "1.0",
CurrentReleaseDate: 0,
CurrentDownloadURL: "http://www.hashicorp.com",
CurrentChangelogURL: "http://www.hashicorp.com",
ProjectWebsite: "http://www.hashicorp.com",
CurrentVersion: "1.0.0",
CurrentReleaseDate: 1460459932, // 2016-04-12 11:18:52
CurrentDownloadURL: "https://test-app.used-for-testing",
CurrentChangelogURL: "https://test-app.used-for-testing",
ProjectWebsite: "https://test-app.used-for-testing",
Outdated: false,
Alerts: []*CheckAlert{},
Alerts: nil,
}
params := &CheckParams{
Product: "test",
Version: "1.0",
Product: "test-app",
Version: "1.0.0",
}
calledCh := make(chan struct{})
@@ -154,8 +179,8 @@ func TestCheckInterval(t *testing.T) {
}
}
doneCh := CheckInterval(params, 500*time.Millisecond, checkFn)
defer close(doneCh)
st := CheckInterval(params, 500*time.Millisecond, checkFn)
defer st.Stop()
select {
case <-calledCh:
@@ -169,8 +194,8 @@ func TestCheckInterval_disabled(t *testing.T) {
defer os.Setenv("CHECKPOINT_DISABLE", "")
params := &CheckParams{
Product: "test",
Version: "1.0",
Product: "test-app",
Version: "1.0.0",
}
calledCh := make(chan struct{})
@@ -178,8 +203,8 @@ func TestCheckInterval_disabled(t *testing.T) {
defer close(calledCh)
}
doneCh := CheckInterval(params, 500*time.Millisecond, checkFn)
defer close(doneCh)
st := CheckInterval(params, 500*time.Millisecond, checkFn)
defer st.Stop()
select {
case <-calledCh:
@@ -188,6 +213,44 @@ func TestCheckInterval_disabled(t *testing.T) {
}
}
func TestCheckInterval_immediate(t *testing.T) {
expected := &CheckResponse{
CurrentVersion: "1.0.0",
CurrentReleaseDate: 1460459932, // 2016-04-12 11:18:52
CurrentDownloadURL: "https://test-app.used-for-testing",
CurrentChangelogURL: "https://test-app.used-for-testing",
ProjectWebsite: "https://test-app.used-for-testing",
Outdated: false,
Alerts: nil,
}
params := &CheckParams{
Product: "test-app",
Version: "1.0.0",
}
calledCh := make(chan struct{})
checkFn := func(actual *CheckResponse, err error) {
defer close(calledCh)
if err != nil {
t.Fatalf("err: %s", err)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
}
}
st := CheckInterval(params, 500*time.Second, checkFn)
defer st.Stop()
select {
case <-calledCh:
case <-time.After(time.Second):
t.Fatalf("timeout")
}
}
func TestRandomStagger(t *testing.T) {
intv := 24 * time.Hour
min := 18 * time.Hour

13
vendor/github.com/weaveworks/go-checkpoint/circle.yml generated vendored Normal file
View File

@@ -0,0 +1,13 @@
machine:
services:
- docker
dependencies:
override:
- git submodule update --init --recursive
test:
override:
- make RM= lint
- make
- make test

2
vendor/manifest vendored
View File

@@ -872,7 +872,7 @@
{
"importpath": "github.com/weaveworks/go-checkpoint",
"repository": "https://github.com/weaveworks/go-checkpoint",
"revision": "d99cc14f13e7845b370a7dc81d47cafb29cdc97f",
"revision": "62324982ab514860761ec81e618664580513ffad",
"branch": "master"
},
{