TUN-528: Move cloudflared into a separate repo

This commit is contained in:
Areg Harutyunyan
2018-05-01 18:45:06 -05:00
parent e8c621a648
commit d06fc520c7
4726 changed files with 1763680 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
// Copyright 2015 RedHat, Inc.
// Copyright 2015 CoreOS, Inc.
//
// 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 sdjournal
import (
"github.com/coreos/pkg/dlopen"
"sync"
"unsafe"
)
var (
// lazy initialized
libsystemdHandle *dlopen.LibHandle
libsystemdMutex = &sync.Mutex{}
libsystemdFunctions = map[string]unsafe.Pointer{}
libsystemdNames = []string{
// systemd < 209
"libsystemd-journal.so.0",
"libsystemd-journal.so",
// systemd >= 209 merged libsystemd-journal into libsystemd proper
"libsystemd.so.0",
"libsystemd.so",
}
)
func getFunction(name string) (unsafe.Pointer, error) {
libsystemdMutex.Lock()
defer libsystemdMutex.Unlock()
if libsystemdHandle == nil {
h, err := dlopen.GetHandle(libsystemdNames)
if err != nil {
return nil, err
}
libsystemdHandle = h
}
f, ok := libsystemdFunctions[name]
if !ok {
var err error
f, err = libsystemdHandle.GetSymbolPointer(name)
if err != nil {
return nil, err
}
libsystemdFunctions[name] = f
}
return f, nil
}

View File

@@ -0,0 +1,36 @@
// Copyright 2015 RedHat, Inc.
// Copyright 2015 CoreOS, Inc.
//
// 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 sdjournal
import "testing"
func TestGetFunction(t *testing.T) {
f, err := getFunction("sd_journal_open")
if err != nil {
t.Errorf("Error getting an existing function: %s", err)
}
if f == nil {
t.Error("Got nil function pointer")
}
_, err = getFunction("non_existent_function")
if err == nil {
t.Error("Expected to get an error, got nil")
}
}

1120
vendor/github.com/coreos/go-systemd/sdjournal/journal.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

508
vendor/github.com/coreos/go-systemd/sdjournal/journal_test.go generated vendored Executable file
View File

@@ -0,0 +1,508 @@
// Copyright 2015 RedHat, Inc.
// Copyright 2015 CoreOS, Inc.
//
// 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 sdjournal
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"math/rand"
"os"
"strings"
"testing"
"time"
"github.com/coreos/go-systemd/journal"
)
func TestJournalFollow(t *testing.T) {
r, err := NewJournalReader(JournalReaderConfig{
Since: time.Duration(-15) * time.Second,
Matches: []Match{
{
Field: SD_JOURNAL_FIELD_SYSTEMD_UNIT,
Value: "NetworkManager.service",
},
},
})
if err != nil {
t.Fatalf("Error opening journal: %s", err)
}
if r == nil {
t.Fatal("Got a nil reader")
}
defer r.Close()
// start writing some test entries
done := make(chan struct{}, 1)
errCh := make(chan error, 1)
defer close(done)
go func() {
for {
select {
case <-done:
return
default:
if perr := journal.Print(journal.PriInfo, "test message %s", time.Now()); err != nil {
errCh <- perr
return
}
time.Sleep(time.Second)
}
}
}()
// and follow the reader synchronously
timeout := time.Duration(5) * time.Second
if err = r.Follow(time.After(timeout), os.Stdout); err != ErrExpired {
t.Fatalf("Error during follow: %s", err)
}
select {
case err := <-errCh:
t.Fatalf("Error writing to journal: %s", err)
default:
}
}
func TestJournalWait(t *testing.T) {
id := time.Now().String()
j, err := NewJournal()
if err != nil {
t.Fatalf("Error opening journal: %s", err)
}
if err := j.AddMatch("TEST=TestJournalWait " + id); err != nil {
t.Fatalf("Error adding match: %s", err)
}
if err := j.SeekTail(); err != nil {
t.Fatalf("Error seeking to tail: %s", err)
}
if _, err := j.Next(); err != nil {
t.Fatalf("Error retrieving next entry: %s", err)
}
var t1, t2 time.Time
for ret := -1; ret != SD_JOURNAL_NOP; {
// Wait() might return for reasons other than timeout.
// For example the first call initializes stuff and returns immediately.
t1 = time.Now()
ret = j.Wait(time.Millisecond * 300)
t2 = time.Now()
}
duration := t2.Sub(t1)
if duration > time.Millisecond*325 || duration < time.Millisecond*300 {
t.Errorf("Wait did not wait 300ms. Actually waited %s", duration.String())
}
journal.Send("test message", journal.PriInfo, map[string]string{"TEST": "TestJournalWait " + id})
for ret := -1; ret != SD_JOURNAL_APPEND; {
t1 = time.Now()
ret = j.Wait(time.Millisecond * 300)
t2 = time.Now()
}
duration = t2.Sub(t1)
if duration >= time.Millisecond*300 {
t.Errorf("Wait took longer than 300ms. Actual duration %s", duration.String())
}
}
func TestJournalGetUsage(t *testing.T) {
j, err := NewJournal()
if err != nil {
t.Fatalf("Error opening journal: %s", err)
}
if j == nil {
t.Fatal("Got a nil journal")
}
defer j.Close()
_, err = j.GetUsage()
if err != nil {
t.Fatalf("Error getting journal size: %s", err)
}
}
func TestJournalCursorGetSeekAndTest(t *testing.T) {
j, err := NewJournal()
if err != nil {
t.Fatalf("Error opening journal: %s", err)
}
if j == nil {
t.Fatal("Got a nil journal")
}
defer j.Close()
err = journal.Print(journal.PriInfo, "test message for cursor %s", time.Now())
if err != nil {
t.Fatalf("Error writing to journal: %s", err)
}
if err = waitAndNext(j); err != nil {
t.Fatalf(err.Error())
}
c, err := j.GetCursor()
if err != nil {
t.Fatalf("Error getting cursor from journal: %s", err)
}
err = j.SeekCursor(c)
if err != nil {
t.Fatalf("Error seeking cursor to journal: %s", err)
}
if err = waitAndNext(j); err != nil {
t.Fatalf(err.Error())
}
err = j.TestCursor(c)
if err != nil {
t.Fatalf("Error testing cursor to journal: %s", err)
}
err = journal.Print(journal.PriInfo, "second message %s", time.Now())
if err != nil {
t.Fatalf("Error writing to journal: %s", err)
}
if err = waitAndNext(j); err != nil {
t.Fatalf(err.Error())
}
err = j.TestCursor(c)
if err != ErrNoTestCursor {
t.Fatalf("Error, TestCursor should fail because current cursor has moved from the previous obtained cursor")
}
}
func TestNewJournalFromDir(t *testing.T) {
// test for error handling
dir := "/ClearlyNonExistingPath/"
j, err := NewJournalFromDir(dir)
if err == nil {
defer j.Close()
t.Fatalf("Error expected when opening dummy path (%s)", dir)
}
// test for main code path
dir, err = ioutil.TempDir("", "go-systemd-test")
if err != nil {
t.Fatalf("Error creating tempdir: %s", err)
}
defer os.RemoveAll(dir)
j, err = NewJournalFromDir(dir)
if err != nil {
t.Fatalf("Error opening journal: %s", err)
}
if j == nil {
t.Fatal("Got a nil journal")
}
j.Close()
}
func setupJournalRoundtrip() (*Journal, map[string]string, error) {
j, err := NewJournal()
if err != nil {
return nil, nil, fmt.Errorf("Error opening journal: %s", err)
}
if j == nil {
return nil, nil, fmt.Errorf("Got a nil journal")
}
j.FlushMatches()
matchField := "TESTJOURNALENTRY"
matchValue := fmt.Sprintf("%d", time.Now().UnixNano())
m := Match{Field: matchField, Value: matchValue}
err = j.AddMatch(m.String())
if err != nil {
return nil, nil, fmt.Errorf("Error adding matches to journal: %s", err)
}
msg := fmt.Sprintf("test journal get entry message %s", time.Now())
data := map[string]string{matchField: matchValue}
err = journal.Send(msg, journal.PriInfo, data)
if err != nil {
return nil, nil, fmt.Errorf("Error writing to journal: %s", err)
}
time.Sleep(time.Duration(1) * time.Second)
n, err := j.Next()
if err != nil {
return nil, nil, fmt.Errorf("Error reading from journal: %s", err)
}
if n == 0 {
return nil, nil, fmt.Errorf("Error reading from journal: %s", io.EOF)
}
data["MESSAGE"] = msg
return j, data, nil
}
func TestJournalGetData(t *testing.T) {
j, wantEntry, err := setupJournalRoundtrip()
if err != nil {
t.Fatal(err.Error())
}
defer j.Close()
for k, v := range wantEntry {
data := fmt.Sprintf("%s=%s", k, v)
dataStr, err := j.GetData(k)
if err != nil {
t.Fatalf("GetData() error: %v", err)
}
if dataStr != data {
t.Fatalf("Invalid data for \"%s\": got %s, want %s", k, dataStr, data)
}
dataBytes, err := j.GetDataBytes(k)
if err != nil {
t.Fatalf("GetDataBytes() error: %v", err)
}
if string(dataBytes) != data {
t.Fatalf("Invalid data bytes for \"%s\": got %s, want %s", k, string(dataBytes), data)
}
valStr, err := j.GetDataValue(k)
if err != nil {
t.Fatalf("GetDataValue() error: %v", err)
}
if valStr != v {
t.Fatalf("Invalid data value for \"%s\": got %s, want %s", k, valStr, v)
}
valBytes, err := j.GetDataValueBytes(k)
if err != nil {
t.Fatalf("GetDataValueBytes() error: %v", err)
}
if string(valBytes) != v {
t.Fatalf("Invalid data value bytes for \"%s\": got %s, want %s", k, string(valBytes), v)
}
}
}
func TestJournalGetEntry(t *testing.T) {
j, wantEntry, err := setupJournalRoundtrip()
if err != nil {
t.Fatal(err.Error())
}
defer j.Close()
entry, err := j.GetEntry()
if err != nil {
t.Fatalf("Error getting the entry to journal: %s", err)
}
for k, wantV := range wantEntry {
gotV := entry.Fields[k]
if gotV != wantV {
t.Fatalf("Bad result for entry.Fields[\"%s\"]: got %s, want %s", k, gotV, wantV)
}
}
}
// Check for incorrect read into small buffers,
// see https://github.com/coreos/go-systemd/issues/172
func TestJournalReaderSmallReadBuffer(t *testing.T) {
// Write a long entry ...
delim := "%%%%%%"
longEntry := strings.Repeat("a", 256)
matchField := "TESTJOURNALREADERSMALLBUF"
matchValue := fmt.Sprintf("%d", time.Now().UnixNano())
r, err := NewJournalReader(JournalReaderConfig{
Since: time.Duration(-15) * time.Second,
Matches: []Match{
{
Field: matchField,
Value: matchValue,
},
},
})
if err != nil {
t.Fatalf("Error opening journal: %s", err)
}
if r == nil {
t.Fatal("Got a nil reader")
}
defer r.Close()
want := fmt.Sprintf("%slongentry %s%s", delim, longEntry, delim)
err = journal.Send(want, journal.PriInfo, map[string]string{matchField: matchValue})
if err != nil {
t.Fatal("Error writing to journal", err)
}
time.Sleep(time.Second)
// ... and try to read it back piece by piece via a small buffer
finalBuff := new(bytes.Buffer)
var e error
for c := -1; c != 0 && e == nil; {
smallBuf := make([]byte, 5)
c, e = r.Read(smallBuf)
if c > len(smallBuf) {
t.Fatalf("Got unexpected read length: %d vs %d", c, len(smallBuf))
}
_, _ = finalBuff.Write(smallBuf)
}
b := finalBuff.String()
got := strings.Split(b, delim)
if len(got) != 3 {
t.Fatalf("Got unexpected entry %s", b)
}
if got[1] != strings.Trim(want, delim) {
t.Fatalf("Got unexpected message %s", got[1])
}
}
func TestJournalGetUniqueValues(t *testing.T) {
j, err := NewJournal()
if err != nil {
t.Fatal(err)
}
defer j.Close()
uniqueString := generateRandomField(20)
testEntries := []string{"A", "B", "C", "D"}
for _, v := range testEntries {
err = journal.Send("TEST: "+uniqueString, journal.PriInfo, map[string]string{uniqueString: v})
if err != nil {
t.Fatal(err)
}
}
// TODO: add proper `waitOnMatch` function which should wait for journal entry with filter to commit.
time.Sleep(time.Millisecond * 500)
values, err := j.GetUniqueValues(uniqueString)
if err != nil {
t.Fatal(err)
}
if len(values) != len(testEntries) {
t.Fatalf("Expect %d entries. Got %d", len(testEntries), len(values))
}
if !contains(values, "A") || !contains(values, "B") || !contains(values, "C") || !contains(values, "D") {
t.Fatalf("Expect 4 values for %s field: A,B,C,D. Got %s", uniqueString, values)
}
}
func TestJournalGetCatalog(t *testing.T) {
want := []string{
"Subject: ",
"Defined-By: systemd",
"Support: ",
}
j, err := NewJournal()
if err != nil {
t.Fatalf("Error opening journal: %s", err)
}
if j == nil {
t.Fatal("Got a nil journal")
}
defer j.Close()
if err = j.SeekHead(); err != nil {
t.Fatalf("Seek to head failed: %s", err)
}
matchField := SD_JOURNAL_FIELD_SYSTEMD_UNIT
m := Match{Field: matchField, Value: "systemd-journald.service"}
if err = j.AddMatch(m.String()); err != nil {
t.Fatalf("Error adding matches to journal: %s", err)
}
if err = waitAndNext(j); err != nil {
t.Fatalf(err.Error())
}
catalog, err := j.GetCatalog()
if err != nil {
t.Fatalf("Failed to retrieve catalog entry: %s", err)
}
for _, w := range want {
if !strings.Contains(catalog, w) {
t.Fatalf("Failed to find \"%s\" in \n%s", w, catalog)
}
}
}
func contains(s []string, v string) bool {
for _, entry := range s {
if entry == v {
return true
}
}
return false
}
func generateRandomField(n int) string {
letters := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
s := make([]rune, n)
rand.Seed(time.Now().UnixNano())
for i := range s {
s[i] = letters[rand.Intn(len(letters))]
}
return string(s)
}
func waitAndNext(j *Journal) error {
r := j.Wait(time.Duration(1) * time.Second)
if r < 0 {
return errors.New("Error waiting to journal")
}
n, err := j.Next()
if err != nil {
return fmt.Errorf("Error reading to journal: %s", err)
}
if n == 0 {
return fmt.Errorf("Error reading to journal: %s", io.EOF)
}
return nil
}

272
vendor/github.com/coreos/go-systemd/sdjournal/read.go generated vendored Normal file
View File

@@ -0,0 +1,272 @@
// Copyright 2015 RedHat, Inc.
// Copyright 2015 CoreOS, Inc.
//
// 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 sdjournal
import (
"errors"
"fmt"
"io"
"log"
"strings"
"sync"
"time"
)
var (
// ErrExpired gets returned when the Follow function runs into the
// specified timeout.
ErrExpired = errors.New("Timeout expired")
)
// JournalReaderConfig represents options to drive the behavior of a JournalReader.
type JournalReaderConfig struct {
// The Since, NumFromTail and Cursor options are mutually exclusive and
// determine where the reading begins within the journal. The order in which
// options are written is exactly the order of precedence.
Since time.Duration // start relative to a Duration from now
NumFromTail uint64 // start relative to the tail
Cursor string // start relative to the cursor
// Show only journal entries whose fields match the supplied values. If
// the array is empty, entries will not be filtered.
Matches []Match
// If not empty, the journal instance will point to a journal residing
// in this directory. The supplied path may be relative or absolute.
Path string
// If not nil, Formatter will be used to translate the resulting entries
// into strings. If not set, the default format (timestamp and message field)
// will be used. If Formatter returns an error, Read will stop and return the error.
Formatter func(entry *JournalEntry) (string, error)
}
// JournalReader is an io.ReadCloser which provides a simple interface for iterating through the
// systemd journal. A JournalReader is not safe for concurrent use by multiple goroutines.
type JournalReader struct {
journal *Journal
msgReader *strings.Reader
formatter func(entry *JournalEntry) (string, error)
}
// NewJournalReader creates a new JournalReader with configuration options that are similar to the
// systemd journalctl tool's iteration and filtering features.
func NewJournalReader(config JournalReaderConfig) (*JournalReader, error) {
// use simpleMessageFormatter as default formatter.
if config.Formatter == nil {
config.Formatter = simpleMessageFormatter
}
r := &JournalReader{
formatter: config.Formatter,
}
// Open the journal
var err error
if config.Path != "" {
r.journal, err = NewJournalFromDir(config.Path)
} else {
r.journal, err = NewJournal()
}
if err != nil {
return nil, err
}
// Add any supplied matches
for _, m := range config.Matches {
if err = r.journal.AddMatch(m.String()); err != nil {
return nil, err
}
}
// Set the start position based on options
if config.Since != 0 {
// Start based on a relative time
start := time.Now().Add(config.Since)
if err := r.journal.SeekRealtimeUsec(uint64(start.UnixNano() / 1000)); err != nil {
return nil, err
}
} else if config.NumFromTail != 0 {
// Start based on a number of lines before the tail
if err := r.journal.SeekTail(); err != nil {
return nil, err
}
// Move the read pointer into position near the tail. Go one further than
// the option so that the initial cursor advancement positions us at the
// correct starting point.
skip, err := r.journal.PreviousSkip(config.NumFromTail + 1)
if err != nil {
return nil, err
}
// If we skipped fewer lines than expected, we have reached journal start.
// Thus, we seek to head so that next invocation can read the first line.
if skip != config.NumFromTail+1 {
if err := r.journal.SeekHead(); err != nil {
return nil, err
}
}
} else if config.Cursor != "" {
// Start based on a custom cursor
if err := r.journal.SeekCursor(config.Cursor); err != nil {
return nil, err
}
}
return r, nil
}
// Read reads entries from the journal. Read follows the Reader interface so
// it must be able to read a specific amount of bytes. Journald on the other
// hand only allows us to read full entries of arbitrary size (without byte
// granularity). JournalReader is therefore internally buffering entries that
// don't fit in the read buffer. Callers should keep calling until 0 and/or an
// error is returned.
func (r *JournalReader) Read(b []byte) (int, error) {
if r.msgReader == nil {
// Advance the journal cursor. It has to be called at least one time
// before reading
c, err := r.journal.Next()
// An unexpected error
if err != nil {
return 0, err
}
// EOF detection
if c == 0 {
return 0, io.EOF
}
entry, err := r.journal.GetEntry()
if err != nil {
return 0, err
}
// Build a message
msg, err := r.formatter(entry)
if err != nil {
return 0, err
}
r.msgReader = strings.NewReader(msg)
}
// Copy and return the message
sz, err := r.msgReader.Read(b)
if err == io.EOF {
// The current entry has been fully read. Don't propagate this
// EOF, so the next entry can be read at the next Read()
// iteration.
r.msgReader = nil
return sz, nil
}
if err != nil {
return sz, err
}
if r.msgReader.Len() == 0 {
r.msgReader = nil
}
return sz, nil
}
// Close closes the JournalReader's handle to the journal.
func (r *JournalReader) Close() error {
return r.journal.Close()
}
// Rewind attempts to rewind the JournalReader to the first entry.
func (r *JournalReader) Rewind() error {
r.msgReader = nil
return r.journal.SeekHead()
}
// Follow synchronously follows the JournalReader, writing each new journal entry to writer. The
// follow will continue until a single time.Time is received on the until channel.
func (r *JournalReader) Follow(until <-chan time.Time, writer io.Writer) error {
// Process journal entries and events. Entries are flushed until the tail or
// timeout is reached, and then we wait for new events or the timeout.
var msg = make([]byte, 64*1<<(10))
var waitCh = make(chan int, 1)
var waitGroup sync.WaitGroup
defer waitGroup.Wait()
process:
for {
c, err := r.Read(msg)
if err != nil && err != io.EOF {
return err
}
select {
case <-until:
return ErrExpired
default:
}
if c > 0 {
if _, err = writer.Write(msg[:c]); err != nil {
return err
}
continue process
}
// We're at the tail, so wait for new events or time out.
// Holds journal events to process. Tightly bounded for now unless there's a
// reason to unblock the journal watch routine more quickly.
for {
waitGroup.Add(1)
go func() {
status := r.journal.Wait(100 * time.Millisecond)
waitCh <- status
waitGroup.Done()
}()
select {
case <-until:
return ErrExpired
case e := <-waitCh:
switch e {
case SD_JOURNAL_NOP:
// the journal did not change since the last invocation
case SD_JOURNAL_APPEND, SD_JOURNAL_INVALIDATE:
continue process
default:
if e < 0 {
return fmt.Errorf("received error event: %d", e)
}
log.Printf("received unknown event: %d\n", e)
}
}
}
}
}
// simpleMessageFormatter is the default formatter.
// It returns a string representing the current journal entry in a simple format which
// includes the entry timestamp and MESSAGE field.
func simpleMessageFormatter(entry *JournalEntry) (string, error) {
msg, ok := entry.Fields["MESSAGE"]
if !ok {
return "", fmt.Errorf("no MESSAGE field present in journal entry")
}
usec := entry.RealtimeTimestamp
timestamp := time.Unix(0, int64(usec)*int64(time.Microsecond))
return fmt.Sprintf("%s %s\n", timestamp, msg), nil
}