<commit_before>package mpb_test

import (
	"bytes"
	"io"
	"io/ioutil"
	"strings"
	"testing"

	"github.com/vbauerster/mpb/v7"
)

const content = `Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
		eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
		veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
		commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit
		esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
		cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
		est laborum.`

type testReader struct {
	io.Reader
	called bool
}

func (r *testReader) Read(p []byte) (n int, err error) {
	r.called = true
	return r.Reader.Read(p)
}

func TestProxyReader(t *testing.T) {
	p := mpb.New(mpb.WithOutput(ioutil.Discard))

	tReader := &testReader{strings.NewReader(content), false}

	bar := p.AddBar(int64(len(content)), mpb.BarFillerTrim())

	var buf bytes.Buffer
	_, err := io.Copy(&buf, bar.ProxyReader(tReader))
	if err != nil {
		t.Errorf("Error copying from reader: %+v\n", err)
	}

	p.Wait()

	if !tReader.called {
		t.Error("Read not called")
	}

	if got := buf.String(); got != content {
		t.Errorf("Expected content: %s, got: %s\n", content, got)
	}
}

type testWriterTo struct {
	io.Reader
	wt     io.WriterTo
	called bool
}

func (wt *testWriterTo) WriteTo(w io.Writer) (n int64, err error) {
	wt.called = true
	return wt.wt.WriteTo(w)
}

func TestProxyWriterTo(t *testing.T) {
	p := mpb.New(mpb.WithOutput(ioutil.Discard))

	var reader io.Reader = strings.NewReader(content)
	tReader := &testWriterTo{reader, reader.(io.WriterTo), false}

	bar := p.AddBar(int64(len(content)), mpb.BarFillerTrim())

	var buf bytes.Buffer
	_, err := io.Copy(&buf, bar.ProxyReader(tReader))
	if err != nil {
		t.Errorf("Error copying from reader: %+v\n", err)
	}

	p.Wait()

	if !tReader.called {
		t.Error("WriteTo not called")
	}

	if got := buf.String(); got != content {
		t.Errorf("Expected content: %s, got: %s\n", content, got)
	}
}
<commit_msg>refactoring proxyreader_test<commit_after>package mpb_test

import (
	"bytes"
	"io"
	"io/ioutil"
	"strings"
	"testing"

	"github.com/vbauerster/mpb/v7"
)

const content = `Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
		eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
		veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
		commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit
		esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
		cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
		est laborum.`

type testReader struct {
	io.Reader
	called bool
}

func (r *testReader) Read(p []byte) (n int, err error) {
	r.called = true
	return r.Reader.Read(p)
}

type testWriterTo struct {
	*testReader
	wt io.WriterTo
}

func (wt testWriterTo) WriteTo(w io.Writer) (n int64, err error) {
	wt.called = true
	return wt.wt.WriteTo(w)
}

func TestProxyReader(t *testing.T) {
	p := mpb.New(mpb.WithOutput(ioutil.Discard))

	tReader := &testReader{strings.NewReader(content), false}

	bar := p.AddBar(int64(len(content)))

	var buf bytes.Buffer
	_, err := io.Copy(&buf, bar.ProxyReader(tReader))
	if err != nil {
		t.Errorf("Error copying from reader: %+v\n", err)
	}

	p.Wait()

	if !tReader.called {
		t.Error("Read not called")
	}

	if got := buf.String(); got != content {
		t.Errorf("Expected content: %s, got: %s\n", content, got)
	}
}

func TestProxyWriterTo(t *testing.T) {
	p := mpb.New(mpb.WithOutput(ioutil.Discard))

	var reader io.Reader = strings.NewReader(content)
	tWriterTo := testWriterTo{&testReader{reader, false}, reader.(io.WriterTo)}

	bar := p.AddBar(int64(len(content)))

	var buf bytes.Buffer
	_, err := io.Copy(&buf, bar.ProxyReader(tWriterTo))
	if err != nil {
		t.Errorf("Error copying from reader: %+v\n", err)
	}

	p.Wait()

	if !tWriterTo.called {
		t.Error("WriteTo not called")
	}

	if got := buf.String(); got != content {
		t.Errorf("Expected content: %s, got: %s\n", content, got)
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 com 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 com

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
)

type NotFoundError struct {
	Message string
}

func (e NotFoundError) Error() string {
	return e.Message
}

type RemoteError struct {
	Host string
	Err  error
}

func (e *RemoteError) Error() string {
	return e.Err.Error()
}

var UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1541.0 Safari/537.36"

// HttpGet gets the specified resource. ErrNotFound is returned if the
// server responds with status 404.
func HttpGet(client *http.Client, url string, header http.Header) (io.ReadCloser, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("User-Agent", UserAgent)
	for k, vs := range header {
		req.Header[k] = vs
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, &RemoteError{req.URL.Host, err}
	}
	if resp.StatusCode == 200 {
		return resp.Body, nil
	}
	resp.Body.Close()
	if resp.StatusCode == 404 { // 403 can be rate limit error.  || resp.StatusCode == 403 {
		err = NotFoundError{"Resource not found: " + url}
	} else {
		err = &RemoteError{req.URL.Host, fmt.Errorf("get %s -> %d", url, resp.StatusCode)}
	}
	return nil, err
}

// HttpGetBytes gets the specified resource. ErrNotFound is returned if the server
// responds with status 404.
func HttpGetBytes(client *http.Client, url string, header http.Header) ([]byte, error) {
	rc, err := HttpGet(client, url, header)
	if err != nil {
		return nil, err
	}
	defer rc.Close()
	return ioutil.ReadAll(rc)
}

// HttpGetJSON gets the specified resource and mapping to struct.
// ErrNotFound is returned if the server responds with status 404.
func HttpGetJSON(client *http.Client, url string, v interface{}) error {
	rc, err := HttpGet(client, url, nil)
	if err != nil {
		return err
	}
	defer rc.Close()
	err = json.NewDecoder(rc).Decode(v)
	if _, ok := err.(*json.SyntaxError); ok {
		err = NotFoundError{"JSON syntax error at " + url}
	}
	return err
}

// A RawFile describes a file that can be downloaded.
type RawFile interface {
	Name() string
	RawUrl() string
	Data() []byte
	SetData([]byte)
}

// FetchFiles fetches files specified by the rawURL field in parallel.
func FetchFiles(client *http.Client, files []RawFile, header http.Header) error {
	ch := make(chan error, len(files))
	for i := range files {
		go func(i int) {
			p, err := HttpGetBytes(client, files[i].RawUrl(), nil)
			if err != nil {
				ch <- err
				return
			}
			files[i].SetData(p)
			ch <- nil
		}(i)
	}
	for _ = range files {
		if err := <-ch; err != nil {
			return err
		}
	}
	return nil
}

// FetchFiles uses command `curl` to fetch files specified by the rawURL field in parallel.
func FetchFilesCurl(files []RawFile, curlOptions ...string) error {
	ch := make(chan error, len(files))
	for i := range files {
		go func(i int) {
			stdout, _, err := ExecCmd("curl", append(curlOptions, files[i].RawUrl())...)
			if err != nil {
				ch <- err
				return
			}

			files[i].SetData([]byte(stdout))
			ch <- nil
		}(i)
	}
	for _ = range files {
		if err := <-ch; err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Add HttpGetToFile<commit_after>// Copyright 2013 com 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 com

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
)

type NotFoundError struct {
	Message string
}

func (e NotFoundError) Error() string {
	return e.Message
}

type RemoteError struct {
	Host string
	Err  error
}

func (e *RemoteError) Error() string {
	return e.Err.Error()
}

var UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1541.0 Safari/537.36"

// HttpGet gets the specified resource. ErrNotFound is returned if the
// server responds with status 404.
func HttpGet(client *http.Client, url string, header http.Header) (io.ReadCloser, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("User-Agent", UserAgent)
	for k, vs := range header {
		req.Header[k] = vs
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, &RemoteError{req.URL.Host, err}
	}
	if resp.StatusCode == 200 {
		return resp.Body, nil
	}
	resp.Body.Close()
	if resp.StatusCode == 404 { // 403 can be rate limit error.  || resp.StatusCode == 403 {
		err = NotFoundError{"Resource not found: " + url}
	} else {
		err = &RemoteError{req.URL.Host, fmt.Errorf("get %s -> %d", url, resp.StatusCode)}
	}
	return nil, err
}

// HttpGetToFile gets the specified resource and writes to file.
// ErrNotFound is returned if the server responds with status 404.
func HttpGetToFile(client *http.Client, url string, header http.Header, fileName string) error {
	rc, err := HttpGet(client, url, header)
	if err != nil {
		return err
	}
	defer rc.Close()

	os.MkdirAll(path.Dir(fileName), os.ModePerm)
	f, err := os.Create(fileName)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = io.Copy(f, rc)
	return err
}

// HttpGetBytes gets the specified resource. ErrNotFound is returned if the server
// responds with status 404.
func HttpGetBytes(client *http.Client, url string, header http.Header) ([]byte, error) {
	rc, err := HttpGet(client, url, header)
	if err != nil {
		return nil, err
	}
	defer rc.Close()
	return ioutil.ReadAll(rc)
}

// HttpGetJSON gets the specified resource and mapping to struct.
// ErrNotFound is returned if the server responds with status 404.
func HttpGetJSON(client *http.Client, url string, v interface{}) error {
	rc, err := HttpGet(client, url, nil)
	if err != nil {
		return err
	}
	defer rc.Close()
	err = json.NewDecoder(rc).Decode(v)
	if _, ok := err.(*json.SyntaxError); ok {
		err = NotFoundError{"JSON syntax error at " + url}
	}
	return err
}

// A RawFile describes a file that can be downloaded.
type RawFile interface {
	Name() string
	RawUrl() string
	Data() []byte
	SetData([]byte)
}

// FetchFiles fetches files specified by the rawURL field in parallel.
func FetchFiles(client *http.Client, files []RawFile, header http.Header) error {
	ch := make(chan error, len(files))
	for i := range files {
		go func(i int) {
			p, err := HttpGetBytes(client, files[i].RawUrl(), nil)
			if err != nil {
				ch <- err
				return
			}
			files[i].SetData(p)
			ch <- nil
		}(i)
	}
	for _ = range files {
		if err := <-ch; err != nil {
			return err
		}
	}
	return nil
}

// FetchFiles uses command `curl` to fetch files specified by the rawURL field in parallel.
func FetchFilesCurl(files []RawFile, curlOptions ...string) error {
	ch := make(chan error, len(files))
	for i := range files {
		go func(i int) {
			stdout, _, err := ExecCmd("curl", append(curlOptions, files[i].RawUrl())...)
			if err != nil {
				ch <- err
				return
			}

			files[i].SetData([]byte(stdout))
			ch <- nil
		}(i)
	}
	for _ = range files {
		if err := <-ch; err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package adaptor

import (
	"errors"
	"reflect"
	"testing"

	"github.com/compose/transporter/pkg/pipe"
)

// a random type that adaptorements the adaptor interface
type Testadaptor struct {
	value string
}

func NewTestadaptor(p *pipe.Pipe, path string, extra Config) (StopStartListener, error) {
	val, ok := extra["value"]
	if !ok {
		return nil, errors.New("this is an error")
	}
	return &Testadaptor{value: val.(string)}, nil
}

func (s *Testadaptor) Start() error {
	return nil
}

func (s *Testadaptor) Stop() error {
	return nil
}

func (s *Testadaptor) Listen() error {
	return nil
}

func TestCreateadaptor(t *testing.T) {
	Register("testadaptor", "description", NewTestadaptor, struct{}{})

	data := []struct {
		kind  string
		extra Config
		out   *Testadaptor
		err   string
	}{
		{
			"testadaptor",
			Config{"value": "rockettes"},
			&Testadaptor{value: "rockettes"},
			"",
		},
		{
			"testadaptor",
			Config{"blah": "rockettes"},
			&Testadaptor{},
			"this is an error",
		},
		{
			"notasource",
			Config{"blah": "rockettes"},
			nil,
			"adaptor 'notasource' not found in registry",
		},
	}
	for _, v := range data {
		adaptor, err := Createadaptor(v.kind, "a/b/c", v.extra, pipe.NewPipe(nil, "some name"))

		if err != nil && err.Error() != v.err {
			t.Errorf("\nexpected error: `%v`\ngot error: `%v`\n", v.err, err.Error())
			t.FailNow()
		}
		if !reflect.DeepEqual(v.out, adaptor) && err == nil {
			t.Errorf("expected:\n%+v\ngot:\n%+v\n", v.out, adaptor)
		}
	}
}
<commit_msg>update test<commit_after>package adaptor

import (
	"errors"
	"reflect"
	"testing"

	"github.com/compose/transporter/pkg/pipe"
)

// a random type that adaptorements the adaptor interface
type Testadaptor struct {
	value string
}

func NewTestadaptor(p *pipe.Pipe, path string, extra Config) (StopStartListener, error) {
	val, ok := extra["value"]
	if !ok {
		return nil, errors.New("this is an error")
	}
	return &Testadaptor{value: val.(string)}, nil
}

func (s *Testadaptor) Start() error {
	return nil
}

func (s *Testadaptor) Stop() error {
	return nil
}

func (s *Testadaptor) Listen() error {
	return nil
}

func TestCreateadaptor(t *testing.T) {
	Register("testadaptor", "description", NewTestadaptor, struct{}{})

	data := []struct {
		kind  string
		extra Config
		out   *Testadaptor
		err   string
	}{
		{
			"testadaptor",
			Config{"value": "rockettes"},
			&Testadaptor{value: "rockettes"},
			"",
		},
		{
			"testadaptor",
			Config{"blah": "rockettes"},
			&Testadaptor{},
			"cannot create testadaptor adaptor (a/b/c). this is an error",
		},
		{
			"notasource",
			Config{"blah": "rockettes"},
			nil,
			"adaptor 'notasource' not found in registry",
		},
	}
	for _, v := range data {
		adaptor, err := Createadaptor(v.kind, "a/b/c", v.extra, pipe.NewPipe(nil, "some name"))

		if err != nil && err.Error() != v.err {
			t.Errorf("\nexpected error: `%v`\ngot error: `%v`\n", v.err, err.Error())
			t.FailNow()
		}
		if !reflect.DeepEqual(v.out, adaptor) && err == nil {
			t.Errorf("expected:\n%+v\ngot:\n%+v\n", v.out, adaptor)
		}
	}
}
<|endoftext|>


<commit_before>package apptest

import (
	"os"
	"reflect"
	"sync"
	"testing"
	"time"

	"github.com/elves/elvish/pkg/cli"
	"github.com/elves/elvish/pkg/cli/term"
)

const (
	// Maximum number of buffer updates FakeTTY expect to see.
	fakeTTYBufferUpdates = 4096
	// Maximum number of events FakeTTY produces.
	fakeTTYEvents = 4096
	// Maximum number of signals FakeTTY produces.
	fakeTTYSignals = 4096
)

// An implementation of the cli.TTY interface that is useful in tests.
type fakeTTY struct {
	setup func() (func(), error)
	// Channel that StartRead returns. Can be used to inject additional events.
	eventCh chan term.Event
	// Channel for publishing updates of the main buffer and notes buffer.
	bufCh, notesBufCh chan *term.Buffer
	// Records history of the main buffer and notes buffer.
	bufs, notesBufs []*term.Buffer
	// Channel that NotifySignals returns. Can be used to inject signals.
	sigCh chan os.Signal
	// Argument that SetRawInput got.
	raw int

	sizeMutex sync.RWMutex
	// Predefined sizes.
	height, width int
}

// Initial size of fake TTY.
const (
	FakeTTYHeight = 20
	FakeTTYWidth  = 50
)

// NewFakeTTY creates a new FakeTTY and a handle for controlling it. The initial
// size of the terminal is FakeTTYHeight and FakeTTYWidth.
func NewFakeTTY() (cli.TTY, TTYCtrl) {
	tty := &fakeTTY{
		eventCh:    make(chan term.Event, fakeTTYEvents),
		sigCh:      make(chan os.Signal, fakeTTYSignals),
		bufCh:      make(chan *term.Buffer, fakeTTYBufferUpdates),
		notesBufCh: make(chan *term.Buffer, fakeTTYBufferUpdates),
		height:     FakeTTYHeight, width: FakeTTYWidth,
	}
	return tty, TTYCtrl{tty}
}

// Delegates to the setup function specified using the SetSetup method of
// TTYCtrl, or return a nop function and a nil error.
func (t *fakeTTY) Setup() (func(), error) {
	if t.setup == nil {
		return func() {}, nil
	}
	return t.setup()
}

// Returns the size specified by using the SetSize method of TTYCtrl.
func (t *fakeTTY) Size() (h, w int) {
	t.sizeMutex.RLock()
	defer t.sizeMutex.RUnlock()
	return t.height, t.width
}

// Returns next event from t.eventCh.
func (t *fakeTTY) ReadEvent() (term.Event, error) {
	return <-t.eventCh, nil
}

// Nop.
func (t *fakeTTY) SetRawInput(n int) {
	t.raw = n
}

// Closes t.eventCh.
func (t *fakeTTY) StopInput() { close(t.eventCh) }

// Returns the last recorded buffer.
func (t *fakeTTY) Buffer() *term.Buffer { return t.bufs[len(t.bufs)-1] }

// Records a nil buffer.
func (t *fakeTTY) ResetBuffer() { t.recordBuf(nil) }

// UpdateBuffer records a new pair of buffers, i.e. sending them to their
// respective channels and appending them to their respective slices.
func (t *fakeTTY) UpdateBuffer(bufNotes, buf *term.Buffer, _ bool) error {
	t.recordNotesBuf(bufNotes)
	t.recordBuf(buf)
	return nil
}

func (t *fakeTTY) NotifySignals() <-chan os.Signal { return t.sigCh }

func (t *fakeTTY) StopSignals() { close(t.sigCh) }

func (t *fakeTTY) recordBuf(buf *term.Buffer) {
	t.bufs = append(t.bufs, buf)
	t.bufCh <- buf
}

func (t *fakeTTY) recordNotesBuf(buf *term.Buffer) {
	t.notesBufs = append(t.notesBufs, buf)
	t.notesBufCh <- buf
}

// TTYCtrl is an interface for controlling a fake terminal.
type TTYCtrl struct{ *fakeTTY }

// GetTTYCtrl takes a TTY and returns a TTYCtrl and true, if the TTY is a fake
// terminal. Otherwise it returns an invalid TTYCtrl and false.
func GetTTYCtrl(t cli.TTY) (TTYCtrl, bool) {
	fake, ok := t.(*fakeTTY)
	return TTYCtrl{fake}, ok
}

// SetSetup sets the return values of the Setup method of the fake terminal.
func (t TTYCtrl) SetSetup(restore func(), err error) {
	t.setup = func() (func(), error) {
		return restore, err
	}
}

// SetSize sets the size of the fake terminal.
func (t TTYCtrl) SetSize(h, w int) {
	t.sizeMutex.Lock()
	defer t.sizeMutex.Unlock()
	t.height, t.width = h, w
}

// Inject injects events to the fake terminal.
func (t TTYCtrl) Inject(events ...term.Event) {
	for _, event := range events {
		t.eventCh <- event
	}
}

// EventCh returns the underlying channel for delivering events.
func (t TTYCtrl) EventCh() chan term.Event {
	return t.eventCh
}

// InjectSignal injects signals.
func (t TTYCtrl) InjectSignal(sigs ...os.Signal) {
	for _, sig := range sigs {
		t.sigCh <- sig
	}
}

// RawInput returns the argument in the last call to the SetRawInput method of
// the TTY.
func (t TTYCtrl) RawInput() int {
	return t.raw
}

// TestBuffer verifies that a buffer will appear within the timeout of 4
// seconds, and fails the test if it doesn't
func (t TTYCtrl) TestBuffer(tt *testing.T, b *term.Buffer) {
	tt.Helper()
	ok := testBuffer(tt, b, t.bufCh)
	if !ok {
		lastBuf := t.LastBuffer()
		tt.Logf("Last buffer: %s", lastBuf.TTYString())
		if lastBuf == nil {
			bufs := t.BufferHistory()
			for i := len(bufs) - 1; i >= 0; i-- {
				if bufs[i] != nil {
					tt.Logf("Last non-nil buffer: %s", bufs[i].TTYString())
					return
				}
			}
		}
	}
}

// TestNotesBuffer verifies that a notes buffer will appear within the timeout of 4
// seconds, and fails the test if it doesn't
func (t TTYCtrl) TestNotesBuffer(tt *testing.T, b *term.Buffer) {
	tt.Helper()
	ok := testBuffer(tt, b, t.notesBufCh)
	if !ok {
		bufs := t.NotesBufferHistory()
		tt.Logf("There has been %d notes buffers. None-nil ones are:", len(bufs))
		for i, buf := range bufs {
			if buf != nil {
				tt.Logf("#%d:\n%s", i, buf.TTYString())
			}
		}
	}
}

// BufferHistory returns a slice of all buffers that have appeared.
func (t TTYCtrl) BufferHistory() []*term.Buffer { return t.bufs }

// LastBuffer returns the last buffer that has appeared.
func (t TTYCtrl) LastBuffer() *term.Buffer {
	if len(t.bufs) == 0 {
		return nil
	}
	return t.bufs[len(t.bufs)-1]
}

// NotesBufferHistory returns a slice of all notes buffers that have appeared.
func (t TTYCtrl) NotesBufferHistory() []*term.Buffer { return t.notesBufs }

func (t TTYCtrl) LastNotesBuffer() *term.Buffer {
	if len(t.notesBufs) == 0 {
		return nil
	}
	return t.notesBufs[len(t.notesBufs)-1]
}

// Tests that an expected buffer will appear within the timeout.
func testBuffer(t *testing.T, want *term.Buffer, ch <-chan *term.Buffer) bool {
	t.Helper()

	timeout := time.After(getUITestTimeout())
	for {
		select {
		case buf := <-ch:
			if reflect.DeepEqual(buf, want) {
				return true
			}
		case <-timeout:
			t.Errorf("Wanted buffer not shown")
			t.Logf("Want: %s", want.TTYString())
			return false
		}
	}
}

const uiTimeoutEnvName = "ELVISH_TEST_UI_TIMEOUT"

var uiTimeoutDefault = 100 * time.Millisecond

func getUITestTimeout() time.Duration {
	if d, err := time.ParseDuration(os.Getenv(uiTimeoutEnvName)); err == nil {
		return d
	}
	return uiTimeoutDefault
}
<commit_msg>pkg/cli/apptest: Fix race when accessing eventCh.<commit_after>package apptest

import (
	"os"
	"reflect"
	"sync"
	"testing"
	"time"

	"github.com/elves/elvish/pkg/cli"
	"github.com/elves/elvish/pkg/cli/term"
)

const (
	// Maximum number of buffer updates FakeTTY expect to see.
	fakeTTYBufferUpdates = 4096
	// Maximum number of events FakeTTY produces.
	fakeTTYEvents = 4096
	// Maximum number of signals FakeTTY produces.
	fakeTTYSignals = 4096
)

// An implementation of the cli.TTY interface that is useful in tests.
type fakeTTY struct {
	setup func() (func(), error)
	// Channel that StartRead returns. Can be used to inject additional events.
	eventCh chan term.Event
	// Whether eventCh has been closed.
	eventChClosed bool
	// Mutex for synchronizing writing and closing eventCh.
	eventChMutex sync.Mutex
	// Channel for publishing updates of the main buffer and notes buffer.
	bufCh, notesBufCh chan *term.Buffer
	// Records history of the main buffer and notes buffer.
	bufs, notesBufs []*term.Buffer
	// Channel that NotifySignals returns. Can be used to inject signals.
	sigCh chan os.Signal
	// Argument that SetRawInput got.
	raw int

	sizeMutex sync.RWMutex
	// Predefined sizes.
	height, width int
}

// Initial size of fake TTY.
const (
	FakeTTYHeight = 20
	FakeTTYWidth  = 50
)

// NewFakeTTY creates a new FakeTTY and a handle for controlling it. The initial
// size of the terminal is FakeTTYHeight and FakeTTYWidth.
func NewFakeTTY() (cli.TTY, TTYCtrl) {
	tty := &fakeTTY{
		eventCh:    make(chan term.Event, fakeTTYEvents),
		sigCh:      make(chan os.Signal, fakeTTYSignals),
		bufCh:      make(chan *term.Buffer, fakeTTYBufferUpdates),
		notesBufCh: make(chan *term.Buffer, fakeTTYBufferUpdates),
		height:     FakeTTYHeight, width: FakeTTYWidth,
	}
	return tty, TTYCtrl{tty}
}

// Delegates to the setup function specified using the SetSetup method of
// TTYCtrl, or return a nop function and a nil error.
func (t *fakeTTY) Setup() (func(), error) {
	if t.setup == nil {
		return func() {}, nil
	}
	return t.setup()
}

// Returns the size specified by using the SetSize method of TTYCtrl.
func (t *fakeTTY) Size() (h, w int) {
	t.sizeMutex.RLock()
	defer t.sizeMutex.RUnlock()
	return t.height, t.width
}

// Returns next event from t.eventCh.
func (t *fakeTTY) ReadEvent() (term.Event, error) {
	return <-t.eventCh, nil
}

// Records the argument.
func (t *fakeTTY) SetRawInput(n int) {
	t.raw = n
}

// Closes eventCh.
func (t *fakeTTY) StopInput() {
	t.eventChMutex.Lock()
	defer t.eventChMutex.Unlock()
	close(t.eventCh)
	t.eventChClosed = true
}

// Returns the last recorded buffer.
func (t *fakeTTY) Buffer() *term.Buffer { return t.bufs[len(t.bufs)-1] }

// Records a nil buffer.
func (t *fakeTTY) ResetBuffer() { t.recordBuf(nil) }

// UpdateBuffer records a new pair of buffers, i.e. sending them to their
// respective channels and appending them to their respective slices.
func (t *fakeTTY) UpdateBuffer(bufNotes, buf *term.Buffer, _ bool) error {
	t.recordNotesBuf(bufNotes)
	t.recordBuf(buf)
	return nil
}

func (t *fakeTTY) NotifySignals() <-chan os.Signal { return t.sigCh }

func (t *fakeTTY) StopSignals() { close(t.sigCh) }

func (t *fakeTTY) recordBuf(buf *term.Buffer) {
	t.bufs = append(t.bufs, buf)
	t.bufCh <- buf
}

func (t *fakeTTY) recordNotesBuf(buf *term.Buffer) {
	t.notesBufs = append(t.notesBufs, buf)
	t.notesBufCh <- buf
}

// TTYCtrl is an interface for controlling a fake terminal.
type TTYCtrl struct{ *fakeTTY }

// GetTTYCtrl takes a TTY and returns a TTYCtrl and true, if the TTY is a fake
// terminal. Otherwise it returns an invalid TTYCtrl and false.
func GetTTYCtrl(t cli.TTY) (TTYCtrl, bool) {
	fake, ok := t.(*fakeTTY)
	return TTYCtrl{fake}, ok
}

// SetSetup sets the return values of the Setup method of the fake terminal.
func (t TTYCtrl) SetSetup(restore func(), err error) {
	t.setup = func() (func(), error) {
		return restore, err
	}
}

// SetSize sets the size of the fake terminal.
func (t TTYCtrl) SetSize(h, w int) {
	t.sizeMutex.Lock()
	defer t.sizeMutex.Unlock()
	t.height, t.width = h, w
}

// Inject injects events to the fake terminal.
func (t TTYCtrl) Inject(events ...term.Event) {
	for _, event := range events {
		t.inject(event)
	}
}

func (t TTYCtrl) inject(event term.Event) {
	t.eventChMutex.Lock()
	defer t.eventChMutex.Unlock()
	if !t.eventChClosed {
		t.eventCh <- event
	}
}

// EventCh returns the underlying channel for delivering events.
func (t TTYCtrl) EventCh() chan term.Event {
	return t.eventCh
}

// InjectSignal injects signals.
func (t TTYCtrl) InjectSignal(sigs ...os.Signal) {
	for _, sig := range sigs {
		t.sigCh <- sig
	}
}

// RawInput returns the argument in the last call to the SetRawInput method of
// the TTY.
func (t TTYCtrl) RawInput() int {
	return t.raw
}

// TestBuffer verifies that a buffer will appear within the timeout of 4
// seconds, and fails the test if it doesn't
func (t TTYCtrl) TestBuffer(tt *testing.T, b *term.Buffer) {
	tt.Helper()
	ok := testBuffer(tt, b, t.bufCh)
	if !ok {
		lastBuf := t.LastBuffer()
		tt.Logf("Last buffer: %s", lastBuf.TTYString())
		if lastBuf == nil {
			bufs := t.BufferHistory()
			for i := len(bufs) - 1; i >= 0; i-- {
				if bufs[i] != nil {
					tt.Logf("Last non-nil buffer: %s", bufs[i].TTYString())
					return
				}
			}
		}
	}
}

// TestNotesBuffer verifies that a notes buffer will appear within the timeout of 4
// seconds, and fails the test if it doesn't
func (t TTYCtrl) TestNotesBuffer(tt *testing.T, b *term.Buffer) {
	tt.Helper()
	ok := testBuffer(tt, b, t.notesBufCh)
	if !ok {
		bufs := t.NotesBufferHistory()
		tt.Logf("There has been %d notes buffers. None-nil ones are:", len(bufs))
		for i, buf := range bufs {
			if buf != nil {
				tt.Logf("#%d:\n%s", i, buf.TTYString())
			}
		}
	}
}

// BufferHistory returns a slice of all buffers that have appeared.
func (t TTYCtrl) BufferHistory() []*term.Buffer { return t.bufs }

// LastBuffer returns the last buffer that has appeared.
func (t TTYCtrl) LastBuffer() *term.Buffer {
	if len(t.bufs) == 0 {
		return nil
	}
	return t.bufs[len(t.bufs)-1]
}

// NotesBufferHistory returns a slice of all notes buffers that have appeared.
func (t TTYCtrl) NotesBufferHistory() []*term.Buffer { return t.notesBufs }

func (t TTYCtrl) LastNotesBuffer() *term.Buffer {
	if len(t.notesBufs) == 0 {
		return nil
	}
	return t.notesBufs[len(t.notesBufs)-1]
}

// Tests that an expected buffer will appear within the timeout.
func testBuffer(t *testing.T, want *term.Buffer, ch <-chan *term.Buffer) bool {
	t.Helper()

	timeout := time.After(getUITestTimeout())
	for {
		select {
		case buf := <-ch:
			if reflect.DeepEqual(buf, want) {
				return true
			}
		case <-timeout:
			t.Errorf("Wanted buffer not shown")
			t.Logf("Want: %s", want.TTYString())
			return false
		}
	}
}

const uiTimeoutEnvName = "ELVISH_TEST_UI_TIMEOUT"

var uiTimeoutDefault = 100 * time.Millisecond

func getUITestTimeout() time.Duration {
	if d, err := time.ParseDuration(os.Getenv(uiTimeoutEnvName)); err == nil {
		return d
	}
	return uiTimeoutDefault
}
<|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 csr

import (
	"crypto/x509/pkix"
	"fmt"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	certutil "k8s.io/client-go/util/cert"
	certificates "k8s.io/kubernetes/pkg/apis/certificates/v1beta1"
	certificatesclient "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/certificates/v1beta1"
)

// RequestNodeCertificate will create a certificate signing request and send it to API server,
// then it will watch the object's status, once approved by API server, it will return the API
// server's issued certificate (pem-encoded). If there is any errors, or the watch timeouts,
// it will return an error. This is intended for use on nodes (kubelet and kubeadm).
func RequestNodeCertificate(client certificatesclient.CertificateSigningRequestInterface, privateKeyData []byte, nodeName types.NodeName) (certData []byte, err error) {
	subject := &pkix.Name{
		Organization: []string{"system:nodes"},
		CommonName:   fmt.Sprintf("system:node:%s", nodeName),
	}

	privateKey, err := certutil.ParsePrivateKeyPEM(privateKeyData)
	if err != nil {
		return nil, fmt.Errorf("invalid private key for certificate request: %v", err)
	}
	csr, err := certutil.MakeCSR(privateKey, subject, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("unable to generate certificate request: %v", err)
	}

	req, err := client.Create(&certificates.CertificateSigningRequest{
		// Username, UID, Groups will be injected by API server.
		TypeMeta:   metav1.TypeMeta{Kind: "CertificateSigningRequest"},
		ObjectMeta: metav1.ObjectMeta{GenerateName: "csr-"},

		Spec: certificates.CertificateSigningRequestSpec{
			Request: csr,
			Usages: []certificates.KeyUsage{
				certificates.UsageDigitalSignature,
				certificates.UsageKeyEncipherment,
				certificates.UsageClientAuth,
			},
		},
	})
	if err != nil {
		return nil, fmt.Errorf("cannot create certificate signing request: %v", err)

	}

	// Make a default timeout = 3600s.
	var defaultTimeoutSeconds int64 = 3600
	resultCh, err := client.Watch(metav1.ListOptions{
		Watch:          true,
		TimeoutSeconds: &defaultTimeoutSeconds,
		FieldSelector:  fields.OneTermEqualSelector("metadata.name", req.Name).String(),
	})
	if err != nil {
		return nil, fmt.Errorf("cannot watch on the certificate signing request: %v", err)
	}

	var status certificates.CertificateSigningRequestStatus
	ch := resultCh.ResultChan()

	for {
		event, ok := <-ch
		if !ok {
			break
		}

		if event.Type == watch.Modified || event.Type == watch.Added {
			if event.Object.(*certificates.CertificateSigningRequest).UID != req.UID {
				continue
			}
			status = event.Object.(*certificates.CertificateSigningRequest).Status
			for _, c := range status.Conditions {
				if c.Type == certificates.CertificateDenied {
					return nil, fmt.Errorf("certificate signing request is not approved, reason: %v, message: %v", c.Reason, c.Message)
				}
				if c.Type == certificates.CertificateApproved && status.Certificate != nil {
					return status.Certificate, nil
				}
			}
		}
	}

	return nil, fmt.Errorf("watch channel closed")
}
<commit_msg>Release API watch resources when done.<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 csr

import (
	"crypto/x509/pkix"
	"fmt"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	certutil "k8s.io/client-go/util/cert"
	certificates "k8s.io/kubernetes/pkg/apis/certificates/v1beta1"
	certificatesclient "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/certificates/v1beta1"
)

// RequestNodeCertificate will create a certificate signing request and send it to API server,
// then it will watch the object's status, once approved by API server, it will return the API
// server's issued certificate (pem-encoded). If there is any errors, or the watch timeouts,
// it will return an error. This is intended for use on nodes (kubelet and kubeadm).
func RequestNodeCertificate(client certificatesclient.CertificateSigningRequestInterface, privateKeyData []byte, nodeName types.NodeName) (certData []byte, err error) {
	subject := &pkix.Name{
		Organization: []string{"system:nodes"},
		CommonName:   fmt.Sprintf("system:node:%s", nodeName),
	}

	privateKey, err := certutil.ParsePrivateKeyPEM(privateKeyData)
	if err != nil {
		return nil, fmt.Errorf("invalid private key for certificate request: %v", err)
	}
	csr, err := certutil.MakeCSR(privateKey, subject, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("unable to generate certificate request: %v", err)
	}

	req, err := client.Create(&certificates.CertificateSigningRequest{
		// Username, UID, Groups will be injected by API server.
		TypeMeta:   metav1.TypeMeta{Kind: "CertificateSigningRequest"},
		ObjectMeta: metav1.ObjectMeta{GenerateName: "csr-"},

		Spec: certificates.CertificateSigningRequestSpec{
			Request: csr,
			Usages: []certificates.KeyUsage{
				certificates.UsageDigitalSignature,
				certificates.UsageKeyEncipherment,
				certificates.UsageClientAuth,
			},
		},
	})
	if err != nil {
		return nil, fmt.Errorf("cannot create certificate signing request: %v", err)
	}

	// Make a default timeout = 3600s.
	var defaultTimeoutSeconds int64 = 3600
	certWatch, err := client.Watch(metav1.ListOptions{
		Watch:          true,
		TimeoutSeconds: &defaultTimeoutSeconds,
		FieldSelector:  fields.OneTermEqualSelector("metadata.name", req.Name).String(),
	})
	if err != nil {
		return nil, fmt.Errorf("cannot watch on the certificate signing request: %v", err)
	}
	defer certWatch.Stop()
	ch := certWatch.ResultChan()

	for {
		event, ok := <-ch
		if !ok {
			break
		}

		if event.Type == watch.Modified || event.Type == watch.Added {
			if event.Object.(*certificates.CertificateSigningRequest).UID != req.UID {
				continue
			}
			status := event.Object.(*certificates.CertificateSigningRequest).Status
			for _, c := range status.Conditions {
				if c.Type == certificates.CertificateDenied {
					return nil, fmt.Errorf("certificate signing request is not approved, reason: %v, message: %v", c.Reason, c.Message)
				}
				if c.Type == certificates.CertificateApproved && status.Certificate != nil {
					return status.Certificate, nil
				}
			}
		}
	}

	return nil, fmt.Errorf("watch channel closed")
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package ipcache

import (
	"errors"
	"fmt"
	"net"
	"sync"
	"unsafe"

	"golang.org/x/sys/unix"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/option"
	"github.com/cilium/cilium/pkg/types"
)

var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "map-ipcache")

const (
	// MaxEntries is the maximum number of keys that can be present in the
	// RemoteEndpointMap.
	MaxEntries = 512000

	// Name is the canonical name for the IPCache map on the filesystem.
	Name = "cilium_ipcache"

	// maxPrefixLengths is an approximation of how many different CIDR
	// prefix lengths may be supported by the BPF datapath without causing
	// BPF code generation to exceed the verifier instruction limit.
	// It applies to Linux versions that lack support for LPM, ie < v4.11.
	//
	// This is based upon the defines in bpf/ep_config.h, which in turn
	// are derived by building the bpf/ directory and running the script
	// test/bpf/verifier-test.sh, then adjusting the number of unique
	// prefix lengths until the script passes.
	maxPrefixLengths6 = 4
	maxPrefixLengths4 = 18
)

// Key implements the bpf.MapKey interface.
//
// Must be in sync with struct ipcache_key in <bpf/lib/maps.h>
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey
type Key struct {
	Prefixlen uint32 `align:"lpm_key"`
	Pad1      uint16 `align:"pad1"`
	Pad2      uint8  `align:"pad2"`
	Family    uint8  `align:"family"`
	// represents both IPv6 and IPv4 (in the lowest four bytes)
	IP types.IPv6 `align:"$union0"`
}

// GetKeyPtr returns the unsafe pointer to the BPF key
func (k *Key) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }

// NewValue returns a new empty instance of the structure representing the BPF
// map value
func (k Key) NewValue() bpf.MapValue { return &RemoteEndpointInfo{} }

func getStaticPrefixBits() uint32 {
	staticMatchSize := unsafe.Sizeof(Key{})
	staticMatchSize -= unsafe.Sizeof(Key{}.Prefixlen)
	staticMatchSize -= unsafe.Sizeof(Key{}.IP)
	return uint32(staticMatchSize) * 8
}

func (k Key) String() string {
	prefixLen := k.Prefixlen - getStaticPrefixBits()
	switch k.Family {
	case bpf.EndpointKeyIPv4:
		ipStr := net.IP(k.IP[:net.IPv4len]).String()
		return fmt.Sprintf("%s/%d", ipStr, prefixLen)
	case bpf.EndpointKeyIPv6:
		ipStr := k.IP.String()
		return fmt.Sprintf("%s/%d", ipStr, prefixLen)
	}
	return "<unknown>"
}

func (k Key) IPNet() *net.IPNet {
	cidr := &net.IPNet{}
	prefixLen := k.Prefixlen - getStaticPrefixBits()
	switch k.Family {
	case bpf.EndpointKeyIPv4:
		cidr.IP = net.IP(k.IP[:net.IPv4len])
		cidr.Mask = net.CIDRMask(int(prefixLen), 32)
	case bpf.EndpointKeyIPv6:
		cidr.IP = net.IP(k.IP[:net.IPv6len])
		cidr.Mask = net.CIDRMask(int(prefixLen), 128)
	}
	return cidr
}

// getPrefixLen determines the length that should be set inside the Key so that
// the lookup prefix is correct in the BPF map key. The specified 'prefixBits'
// indicates the number of bits in the IP that must match to match the entry in
// the BPF ipcache.
func getPrefixLen(prefixBits int) uint32 {
	return getStaticPrefixBits() + uint32(prefixBits)
}

// NewKey returns an Key based on the provided IP address and mask. The address
// family is automatically detected
func NewKey(ip net.IP, mask net.IPMask) Key {
	result := Key{}

	ones, _ := mask.Size()
	if ip4 := ip.To4(); ip4 != nil {
		if mask == nil {
			ones = net.IPv4len * 8
		}
		result.Prefixlen = getPrefixLen(ones)
		result.Family = bpf.EndpointKeyIPv4
		copy(result.IP[:], ip4)
	} else {
		if mask == nil {
			ones = net.IPv6len * 8
		}
		result.Prefixlen = getPrefixLen(ones)
		result.Family = bpf.EndpointKeyIPv6
		copy(result.IP[:], ip)
	}

	return result
}

// RemoteEndpointInfo implements the bpf.MapValue interface. It contains the
// security identity of a remote endpoint.
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapValue
type RemoteEndpointInfo struct {
	SecurityIdentity uint32     `align:"sec_label"`
	TunnelEndpoint   types.IPv4 `align:"tunnel_endpoint"`
	Key              uint8      `align:"key"`
}

func (v *RemoteEndpointInfo) String() string {
	return fmt.Sprintf("identity=%d encryptkey=%d tunnelendpoint=%s",
		v.SecurityIdentity, v.Key, v.TunnelEndpoint)
}

// GetValuePtr returns the unsafe pointer to the BPF value.
func (v *RemoteEndpointInfo) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v) }

// Map represents an IPCache BPF map.
type Map struct {
	bpf.Map

	// detectDeleteSupport is used to initialize 'supportsDelete' the first
	// time that a delete is issued from the datapath.
	detectDeleteSupport sync.Once

	// deleteSupport is set to 'true' initially, then is updated to set
	// whether the underlying kernel supports delete operations on the map
	// the first time that supportsDelete() is called.
	deleteSupport bool
}

func newIPCacheMap(name string) *bpf.Map {
	return bpf.NewMap(
		name,
		bpf.MapTypeLPMTrie,
		&Key{},
		int(unsafe.Sizeof(Key{})),
		&RemoteEndpointInfo{},
		int(unsafe.Sizeof(RemoteEndpointInfo{})),
		MaxEntries,
		bpf.BPF_F_NO_PREALLOC, 0,
		bpf.ConvertKeyValue)
}

// NewMap instantiates a Map.
func NewMap(name string) *Map {
	return &Map{
		Map: *newIPCacheMap(name).WithCache().WithPressureMetric().
			WithEvents(option.Config.GetEventBufferConfig(name)),
		deleteSupport: true,
	}
}

// delete removes a key from the ipcache BPF map, and returns whether the
// kernel supports the delete operation (true) or not (false), and any error
// that may have occurred while attempting to delete the entry.
//
// If "overwrite" is true, then if delete is not supported the entry's value
// will be overwritten with zeroes to signify that it's an invalid entry.
func (m *Map) delete(k bpf.MapKey, overwrite bool) (bool, error) {
	err := m.Delete(k)
	var errno unix.Errno
	if ok := errors.As(err, &errno); ok && errno == unix.ENOSYS {
		if overwrite {
			// Older kernels do not support deletion of LPM map entries so zero out
			// the entry instead of attempting a deletion
			return false, m.Update(k, &RemoteEndpointInfo{})
		}
		return false, nil
	}
	return true, err
}

// DeleteWithOverwrite removes a key from the ipcache BPF map.
// If delete is not supported, the entry's value will be overwritten with
// zeroes to signify that it's an invalid entry.
func (m *Map) DeleteWithOverwrite(k bpf.MapKey) error {
	_, err := m.delete(k, true)
	return err
}

// GetMaxPrefixLengths determines how many unique prefix lengths are supported
// simultaneously based on the underlying BPF map type in use.
func (m *Map) GetMaxPrefixLengths() (ipv6, ipv4 int) {
	if BackedByLPM() {
		return net.IPv6len*8 + 1, net.IPv4len*8 + 1
	}
	return maxPrefixLengths6, maxPrefixLengths4
}

func (m *Map) supportsDelete() bool {
	m.detectDeleteSupport.Do(func() {
		// Create a separate map for the probing since this map may not have been created yet.
		probeMap := newIPCacheMap(m.Name() + "_probe")
		err := probeMap.CreateUnpinned()
		if err != nil {
			log.WithError(err).Warn("Failed to open IPCache map for feature probing, assuming delete and dump unsupported")
			m.deleteSupport = false
			return
		}
		defer probeMap.Close()

		// Entry is invalid because IPCache needs a family specified.
		invalidEntry := &Key{}
		err = probeMap.Delete(invalidEntry)
		var errno unix.Errno
		if ok := errors.As(err, &errno); ok && errno == unix.ENOSYS {
			m.deleteSupport = false
		} else {
			m.deleteSupport = true
		}
		log.Debugf("Detected IPCache delete operation support: %t", m.deleteSupport)

		// Detect dump support
		err = probeMap.Dump(map[string][]string{})
		dumpSupport := err == nil
		log.Debugf("Detected IPCache dump operation support: %t", dumpSupport)

		// In addition to delete support, ability to dump the map is
		// also required in order to run the garbage collector which
		// will iterate over the map and delete entries.
		m.deleteSupport = m.deleteSupport && dumpSupport

		if !m.deleteSupport {
			log.Infof("Periodic IPCache map swap will occur due to lack of kernel support for LPM delete operation. Upgrade to Linux 4.15 or higher to avoid this.")
		}
	})
	return m.deleteSupport
}

// SupportsDelete determines whether the underlying kernel map type supports
// the delete operation.
func SupportsDelete() bool {
	return IPCacheMap().supportsDelete()
}

// BackedByLPM returns true if the IPCache is backed by a proper LPM
// implementation (provided by Linux kernels 4.11 or later), false otherwise.
func BackedByLPM() bool {
	return IPCacheMap().MapType == bpf.MapTypeLPMTrie
}

var (
	// IPCache is a mapping of all endpoint IPs in the cluster which this
	// Cilium agent is a part of to their corresponding security identities.
	// It is a singleton; there is only one such map per agent.
	ipcache *Map
	once    = &sync.Once{}
)

// IPCacheMap gets the ipcache Map singleton. If it has not already been done,
// this also initializes the Map.
func IPCacheMap() *Map {
	once.Do(func() {
		ipcache = NewMap(Name)
	})
	return ipcache
}

// Reopen attempts to close and re-open the IPCache map at the standard path
// on the filesystem.
func Reopen() error {
	return IPCacheMap().Reopen()
}
<commit_msg>maps/ipcache: add key.Prefix<commit_after>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package ipcache

import (
	"errors"
	"fmt"
	"net"
	"net/netip"
	"sync"
	"unsafe"

	"golang.org/x/sys/unix"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/option"
	"github.com/cilium/cilium/pkg/types"
)

var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "map-ipcache")

const (
	// MaxEntries is the maximum number of keys that can be present in the
	// RemoteEndpointMap.
	MaxEntries = 512000

	// Name is the canonical name for the IPCache map on the filesystem.
	Name = "cilium_ipcache"

	// maxPrefixLengths is an approximation of how many different CIDR
	// prefix lengths may be supported by the BPF datapath without causing
	// BPF code generation to exceed the verifier instruction limit.
	// It applies to Linux versions that lack support for LPM, ie < v4.11.
	//
	// This is based upon the defines in bpf/ep_config.h, which in turn
	// are derived by building the bpf/ directory and running the script
	// test/bpf/verifier-test.sh, then adjusting the number of unique
	// prefix lengths until the script passes.
	maxPrefixLengths6 = 4
	maxPrefixLengths4 = 18
)

// Key implements the bpf.MapKey interface.
//
// Must be in sync with struct ipcache_key in <bpf/lib/maps.h>
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey
type Key struct {
	Prefixlen uint32 `align:"lpm_key"`
	Pad1      uint16 `align:"pad1"`
	Pad2      uint8  `align:"pad2"`
	Family    uint8  `align:"family"`
	// represents both IPv6 and IPv4 (in the lowest four bytes)
	IP types.IPv6 `align:"$union0"`
}

// GetKeyPtr returns the unsafe pointer to the BPF key
func (k *Key) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }

// NewValue returns a new empty instance of the structure representing the BPF
// map value
func (k Key) NewValue() bpf.MapValue { return &RemoteEndpointInfo{} }

func getStaticPrefixBits() uint32 {
	staticMatchSize := unsafe.Sizeof(Key{})
	staticMatchSize -= unsafe.Sizeof(Key{}.Prefixlen)
	staticMatchSize -= unsafe.Sizeof(Key{}.IP)
	return uint32(staticMatchSize) * 8
}

func (k Key) String() string {
	prefixLen := k.Prefixlen - getStaticPrefixBits()
	switch k.Family {
	case bpf.EndpointKeyIPv4:
		ipStr := net.IP(k.IP[:net.IPv4len]).String()
		return fmt.Sprintf("%s/%d", ipStr, prefixLen)
	case bpf.EndpointKeyIPv6:
		ipStr := k.IP.String()
		return fmt.Sprintf("%s/%d", ipStr, prefixLen)
	}
	return "<unknown>"
}

func (k Key) IPNet() *net.IPNet {
	cidr := &net.IPNet{}
	prefixLen := k.Prefixlen - getStaticPrefixBits()
	switch k.Family {
	case bpf.EndpointKeyIPv4:
		cidr.IP = net.IP(k.IP[:net.IPv4len])
		cidr.Mask = net.CIDRMask(int(prefixLen), 32)
	case bpf.EndpointKeyIPv6:
		cidr.IP = net.IP(k.IP[:net.IPv6len])
		cidr.Mask = net.CIDRMask(int(prefixLen), 128)
	}
	return cidr
}

func (k Key) Prefix() netip.Prefix {
	var addr netip.Addr
	prefixLen := int(k.Prefixlen - getStaticPrefixBits())
	switch k.Family {
	case bpf.EndpointKeyIPv4:
		addr = netip.AddrFrom4(*(*[4]byte)(k.IP[:4]))
	case bpf.EndpointKeyIPv6:
		addr = netip.AddrFrom16(k.IP)
	}
	return netip.PrefixFrom(addr, prefixLen)
}

// getPrefixLen determines the length that should be set inside the Key so that
// the lookup prefix is correct in the BPF map key. The specified 'prefixBits'
// indicates the number of bits in the IP that must match to match the entry in
// the BPF ipcache.
func getPrefixLen(prefixBits int) uint32 {
	return getStaticPrefixBits() + uint32(prefixBits)
}

// NewKey returns an Key based on the provided IP address and mask. The address
// family is automatically detected
func NewKey(ip net.IP, mask net.IPMask) Key {
	result := Key{}

	ones, _ := mask.Size()
	if ip4 := ip.To4(); ip4 != nil {
		if mask == nil {
			ones = net.IPv4len * 8
		}
		result.Prefixlen = getPrefixLen(ones)
		result.Family = bpf.EndpointKeyIPv4
		copy(result.IP[:], ip4)
	} else {
		if mask == nil {
			ones = net.IPv6len * 8
		}
		result.Prefixlen = getPrefixLen(ones)
		result.Family = bpf.EndpointKeyIPv6
		copy(result.IP[:], ip)
	}

	return result
}

// RemoteEndpointInfo implements the bpf.MapValue interface. It contains the
// security identity of a remote endpoint.
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapValue
type RemoteEndpointInfo struct {
	SecurityIdentity uint32     `align:"sec_label"`
	TunnelEndpoint   types.IPv4 `align:"tunnel_endpoint"`
	Key              uint8      `align:"key"`
}

func (v *RemoteEndpointInfo) String() string {
	return fmt.Sprintf("identity=%d encryptkey=%d tunnelendpoint=%s",
		v.SecurityIdentity, v.Key, v.TunnelEndpoint)
}

// GetValuePtr returns the unsafe pointer to the BPF value.
func (v *RemoteEndpointInfo) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v) }

// Map represents an IPCache BPF map.
type Map struct {
	bpf.Map

	// detectDeleteSupport is used to initialize 'supportsDelete' the first
	// time that a delete is issued from the datapath.
	detectDeleteSupport sync.Once

	// deleteSupport is set to 'true' initially, then is updated to set
	// whether the underlying kernel supports delete operations on the map
	// the first time that supportsDelete() is called.
	deleteSupport bool
}

func newIPCacheMap(name string) *bpf.Map {
	return bpf.NewMap(
		name,
		bpf.MapTypeLPMTrie,
		&Key{},
		int(unsafe.Sizeof(Key{})),
		&RemoteEndpointInfo{},
		int(unsafe.Sizeof(RemoteEndpointInfo{})),
		MaxEntries,
		bpf.BPF_F_NO_PREALLOC, 0,
		bpf.ConvertKeyValue)
}

// NewMap instantiates a Map.
func NewMap(name string) *Map {
	return &Map{
		Map: *newIPCacheMap(name).WithCache().WithPressureMetric().
			WithEvents(option.Config.GetEventBufferConfig(name)),
		deleteSupport: true,
	}
}

// delete removes a key from the ipcache BPF map, and returns whether the
// kernel supports the delete operation (true) or not (false), and any error
// that may have occurred while attempting to delete the entry.
//
// If "overwrite" is true, then if delete is not supported the entry's value
// will be overwritten with zeroes to signify that it's an invalid entry.
func (m *Map) delete(k bpf.MapKey, overwrite bool) (bool, error) {
	err := m.Delete(k)
	var errno unix.Errno
	if ok := errors.As(err, &errno); ok && errno == unix.ENOSYS {
		if overwrite {
			// Older kernels do not support deletion of LPM map entries so zero out
			// the entry instead of attempting a deletion
			return false, m.Update(k, &RemoteEndpointInfo{})
		}
		return false, nil
	}
	return true, err
}

// DeleteWithOverwrite removes a key from the ipcache BPF map.
// If delete is not supported, the entry's value will be overwritten with
// zeroes to signify that it's an invalid entry.
func (m *Map) DeleteWithOverwrite(k bpf.MapKey) error {
	_, err := m.delete(k, true)
	return err
}

// GetMaxPrefixLengths determines how many unique prefix lengths are supported
// simultaneously based on the underlying BPF map type in use.
func (m *Map) GetMaxPrefixLengths() (ipv6, ipv4 int) {
	if BackedByLPM() {
		return net.IPv6len*8 + 1, net.IPv4len*8 + 1
	}
	return maxPrefixLengths6, maxPrefixLengths4
}

func (m *Map) supportsDelete() bool {
	m.detectDeleteSupport.Do(func() {
		// Create a separate map for the probing since this map may not have been created yet.
		probeMap := newIPCacheMap(m.Name() + "_probe")
		err := probeMap.CreateUnpinned()
		if err != nil {
			log.WithError(err).Warn("Failed to open IPCache map for feature probing, assuming delete and dump unsupported")
			m.deleteSupport = false
			return
		}
		defer probeMap.Close()

		// Entry is invalid because IPCache needs a family specified.
		invalidEntry := &Key{}
		err = probeMap.Delete(invalidEntry)
		var errno unix.Errno
		if ok := errors.As(err, &errno); ok && errno == unix.ENOSYS {
			m.deleteSupport = false
		} else {
			m.deleteSupport = true
		}
		log.Debugf("Detected IPCache delete operation support: %t", m.deleteSupport)

		// Detect dump support
		err = probeMap.Dump(map[string][]string{})
		dumpSupport := err == nil
		log.Debugf("Detected IPCache dump operation support: %t", dumpSupport)

		// In addition to delete support, ability to dump the map is
		// also required in order to run the garbage collector which
		// will iterate over the map and delete entries.
		m.deleteSupport = m.deleteSupport && dumpSupport

		if !m.deleteSupport {
			log.Infof("Periodic IPCache map swap will occur due to lack of kernel support for LPM delete operation. Upgrade to Linux 4.15 or higher to avoid this.")
		}
	})
	return m.deleteSupport
}

// SupportsDelete determines whether the underlying kernel map type supports
// the delete operation.
func SupportsDelete() bool {
	return IPCacheMap().supportsDelete()
}

// BackedByLPM returns true if the IPCache is backed by a proper LPM
// implementation (provided by Linux kernels 4.11 or later), false otherwise.
func BackedByLPM() bool {
	return IPCacheMap().MapType == bpf.MapTypeLPMTrie
}

var (
	// IPCache is a mapping of all endpoint IPs in the cluster which this
	// Cilium agent is a part of to their corresponding security identities.
	// It is a singleton; there is only one such map per agent.
	ipcache *Map
	once    = &sync.Once{}
)

// IPCacheMap gets the ipcache Map singleton. If it has not already been done,
// this also initializes the Map.
func IPCacheMap() *Map {
	once.Do(func() {
		ipcache = NewMap(Name)
	})
	return ipcache
}

// Reopen attempts to close and re-open the IPCache map at the standard path
// on the filesystem.
func Reopen() error {
	return IPCacheMap().Reopen()
}
<|endoftext|>


<commit_before>// Copyright 2017 Cisco Systems, 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 metadata

import (
	"net"

	"github.com/noironetworks/aci-containers/pkg/ipam"
)

// An opflex security or endpoint group
// Tenant is an alias for policy space and will override policyspace
// If AppProfile is not set the Name is interpreted as AppProfile|Name
type OpflexGroup struct {
	Tenant      string `json:"tenant,omitempty"`
	PolicySpace string `json:"policy-space,omitempty"`
	AppProfile  string `json:"app-profile,omitempty"`
	Name        string `json:"name,omitempty"`
}

// annotation type for service endpoint information
type ServiceEndpoint struct {
	Mac  string `json:"mac,omitempty"`
	Ipv4 net.IP `json:"ipv4,omitempty"`
	Ipv6 net.IP `json:"ipv6,omitempty"`
}

// annotation type for IPs allocation chunks
type NetIps struct {
	V4 []ipam.IpRange `json:"V4,omitempty"`
	V6 []ipam.IpRange `json:"V6,omitempty"`
}

// annotatation type for kubernetes
// net.beta.kubernetes.io/network-policy annotation
type NetworkPolicy struct {
	Ingress *NetworkPolicyIngress `json:"ingress,omitempty"`
}

// The ingress object in the network policy annotation
type NetworkPolicyIngress struct {
	// the isolation level for ingress.  Possible values are:
	// "DefaultDeny": Pods in the namespace will be inaccessible from any source except the
	// pod’s local node
	Isolation string `json:"isolation,omitempty"`
}

// Service endpoint annotation
const ServiceEpAnnotation = "opflex.cisco.com/service-endpoint"

// List of IP address ranges for use by the pod network
const PodNetworkRangeAnnotation = "opflex.cisco.com/pod-network-ranges"

// Annotation for endpoint group designation for pod, deployment, etc.
const EgAnnotation = "opflex.cisco.com/endpoint-group"

// Annotation for security group designation for pod, deployment, etc.
const SgAnnotation = "opflex.cisco.com/security-group"

// Computed endpoint group for pod
const CompEgAnnotation = "opflex.cisco.com/computed-endpoint-group"

// Computed security groups for pod
const CompSgAnnotation = "opflex.cisco.com/computed-security-group"
<commit_msg>Remove vestigial definition.<commit_after>// Copyright 2017 Cisco Systems, 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 metadata

import (
	"net"

	"github.com/noironetworks/aci-containers/pkg/ipam"
)

// An opflex security or endpoint group
// Tenant is an alias for policy space and will override policyspace
// If AppProfile is not set the Name is interpreted as AppProfile|Name
type OpflexGroup struct {
	Tenant      string `json:"tenant,omitempty"`
	PolicySpace string `json:"policy-space,omitempty"`
	AppProfile  string `json:"app-profile,omitempty"`
	Name        string `json:"name,omitempty"`
}

// annotation type for service endpoint information
type ServiceEndpoint struct {
	Mac  string `json:"mac,omitempty"`
	Ipv4 net.IP `json:"ipv4,omitempty"`
	Ipv6 net.IP `json:"ipv6,omitempty"`
}

// annotation type for IPs allocation chunks
type NetIps struct {
	V4 []ipam.IpRange `json:"V4,omitempty"`
	V6 []ipam.IpRange `json:"V6,omitempty"`
}

// Service endpoint annotation
const ServiceEpAnnotation = "opflex.cisco.com/service-endpoint"

// List of IP address ranges for use by the pod network
const PodNetworkRangeAnnotation = "opflex.cisco.com/pod-network-ranges"

// Annotation for endpoint group designation for pod, deployment, etc.
const EgAnnotation = "opflex.cisco.com/endpoint-group"

// Annotation for security group designation for pod, deployment, etc.
const SgAnnotation = "opflex.cisco.com/security-group"

// Computed endpoint group for pod
const CompEgAnnotation = "opflex.cisco.com/computed-endpoint-group"

// Computed security groups for pod
const CompSgAnnotation = "opflex.cisco.com/computed-security-group"
<|endoftext|>


<commit_before>/*
Copyright 2020 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 node

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/host"
	"github.com/golang/glog"
	"github.com/spf13/viper"
	cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
	"k8s.io/minikube/pkg/minikube/bootstrapper"
	"k8s.io/minikube/pkg/minikube/cluster"
	"k8s.io/minikube/pkg/minikube/config"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/minikube/cruntime"
	"k8s.io/minikube/pkg/minikube/driver"
	"k8s.io/minikube/pkg/minikube/exit"
	"k8s.io/minikube/pkg/minikube/kubeconfig"
	"k8s.io/minikube/pkg/minikube/localpath"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/util/lock"
)

var (
	// DockerEnv contains the environment variables
	DockerEnv []string
	// DockerOpt contains the option parameters
	DockerOpt []string
	// ExtraOptions contains extra options (if any)
	ExtraOptions config.ExtraOptionSlice
	// AddonList contains the list of addons
	AddonList []string
)

// configureRuntimes does what needs to happen to get a runtime going.
func configureRuntimes(runner cruntime.CommandRunner, drvName string, k8s config.KubernetesConfig) cruntime.Manager {
	config := cruntime.Config{Type: viper.GetString(containerRuntime), Runner: runner, ImageRepository: k8s.ImageRepository, KubernetesVersion: k8s.KubernetesVersion}
	cr, err := cruntime.New(config)
	if err != nil {
		exit.WithError("Failed runtime", err)
	}

	disableOthers := true
	if driver.BareMetal(drvName) {
		disableOthers = false
	}
	if !driver.IsKIC(drvName) {
		if err := cr.Preload(k8s.KubernetesVersion); err != nil {
			glog.Infof("Failed to preload container runtime %s: %v", cr.Name(), err)
		}
	}

	err = cr.Enable(disableOthers)
	if err != nil {
		exit.WithError("Failed to enable container runtime", err)
	}

	return cr
}

func showVersionInfo(k8sVersion string, cr cruntime.Manager) {
	version, _ := cr.Version()
	out.T(cr.Style(), "Preparing Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}} ...", out.V{"k8sVersion": k8sVersion, "runtime": cr.Name(), "runtimeVersion": version})
	for _, v := range DockerOpt {
		out.T(out.Option, "opt {{.docker_option}}", out.V{"docker_option": v})
	}
	for _, v := range DockerEnv {
		out.T(out.Option, "env {{.docker_env}}", out.V{"docker_env": v})
	}
}

// setupKubeAdm adds any requested files into the VM before Kubernetes is started
func setupKubeAdm(mAPI libmachine.API, cfg config.ClusterConfig, node config.Node) bootstrapper.Bootstrapper {
	bs, err := cluster.Bootstrapper(mAPI, viper.GetString(cmdcfg.Bootstrapper), cfg, node)
	if err != nil {
		exit.WithError("Failed to get bootstrapper", err)
	}
	for _, eo := range ExtraOptions {
		out.T(out.Option, "{{.extra_option_component_name}}.{{.key}}={{.value}}", out.V{"extra_option_component_name": eo.Component, "key": eo.Key, "value": eo.Value})
	}
	// Loads cached images, generates config files, download binaries
	if err := bs.UpdateCluster(cfg); err != nil {
		exit.WithError("Failed to update cluster", err)
	}
	if err := bs.SetupCerts(cfg.KubernetesConfig, node); err != nil {
		exit.WithError("Failed to setup certs", err)
	}
	return bs
}

func setupKubeconfig(h *host.Host, c *config.ClusterConfig, n *config.Node, clusterName string) (*kubeconfig.Settings, error) {
	addr, err := h.Driver.GetURL()
	if err != nil {
		exit.WithError("Failed to get driver URL", err)
	}
	if !driver.IsKIC(h.DriverName) {
		addr = strings.Replace(addr, "tcp://", "https://", -1)
		addr = strings.Replace(addr, ":2376", ":"+strconv.Itoa(n.Port), -1)
	}

	if c.KubernetesConfig.APIServerName != constants.APIServerName {
		addr = strings.Replace(addr, n.IP, c.KubernetesConfig.APIServerName, -1)
	}
	kcs := &kubeconfig.Settings{
		ClusterName:          clusterName,
		ClusterServerAddress: addr,
		ClientCertificate:    localpath.MakeMiniPath("client.crt"),
		ClientKey:            localpath.MakeMiniPath("client.key"),
		CertificateAuthority: localpath.MakeMiniPath("ca.crt"),
		KeepContext:          viper.GetBool(keepContext),
		EmbedCerts:           viper.GetBool(embedCerts),
	}

	kcs.SetPath(kubeconfig.PathFromEnv())
	if err := kubeconfig.Update(kcs); err != nil {
		return kcs, err
	}
	return kcs, nil
}

// configureMounts configures any requested filesystem mounts
func configureMounts() {
	if !viper.GetBool(createMount) {
		return
	}

	out.T(out.Mounting, "Creating mount {{.name}} ...", out.V{"name": viper.GetString(mountString)})
	path := os.Args[0]
	mountDebugVal := 0
	if glog.V(8) {
		mountDebugVal = 1
	}
	mountCmd := exec.Command(path, "mount", fmt.Sprintf("--v=%d", mountDebugVal), viper.GetString(mountString))
	mountCmd.Env = append(os.Environ(), constants.IsMinikubeChildProcess+"=true")
	if glog.V(8) {
		mountCmd.Stdout = os.Stdout
		mountCmd.Stderr = os.Stderr
	}
	if err := mountCmd.Start(); err != nil {
		exit.WithError("Error starting mount", err)
	}
	if err := lock.WriteFile(filepath.Join(localpath.MiniPath(), constants.MountProcessFileName), []byte(strconv.Itoa(mountCmd.Process.Pid)), 0644); err != nil {
		exit.WithError("Error writing mount pid", err)
	}
}
<commit_msg>fall back to caching images if preload fails<commit_after>/*
Copyright 2020 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 node

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/host"
	"github.com/golang/glog"
	"github.com/spf13/viper"
	cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
	"k8s.io/minikube/pkg/minikube/bootstrapper"
	"k8s.io/minikube/pkg/minikube/cluster"
	"k8s.io/minikube/pkg/minikube/config"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/minikube/cruntime"
	"k8s.io/minikube/pkg/minikube/driver"
	"k8s.io/minikube/pkg/minikube/exit"
	"k8s.io/minikube/pkg/minikube/kubeconfig"
	"k8s.io/minikube/pkg/minikube/localpath"
	"k8s.io/minikube/pkg/minikube/machine"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/util/lock"
)

var (
	// DockerEnv contains the environment variables
	DockerEnv []string
	// DockerOpt contains the option parameters
	DockerOpt []string
	// ExtraOptions contains extra options (if any)
	ExtraOptions config.ExtraOptionSlice
	// AddonList contains the list of addons
	AddonList []string
)

// configureRuntimes does what needs to happen to get a runtime going.
func configureRuntimes(runner cruntime.CommandRunner, drvName string, k8s config.KubernetesConfig) cruntime.Manager {
	config := cruntime.Config{Type: viper.GetString(containerRuntime), Runner: runner, ImageRepository: k8s.ImageRepository, KubernetesVersion: k8s.KubernetesVersion}
	cr, err := cruntime.New(config)
	if err != nil {
		exit.WithError("Failed runtime", err)
	}

	disableOthers := true
	if driver.BareMetal(drvName) {
		disableOthers = false
	}
	if !driver.IsKIC(drvName) {
		if err := cr.Preload(k8s.KubernetesVersion); err != nil {
			glog.Infof("Failed to preload container runtime %s: %v, falling back to caching images", cr.Name(), err)
			if err := machine.CacheImagesForBootstrapper(k8s.ImageRepository, k8s.KubernetesVersion, viper.GetString(cmdcfg.Bootstrapper)); err != nil {
				exit.WithError("Failed to cache images", err)
			}
		}
	}

	err = cr.Enable(disableOthers)
	if err != nil {
		exit.WithError("Failed to enable container runtime", err)
	}

	return cr
}

func showVersionInfo(k8sVersion string, cr cruntime.Manager) {
	version, _ := cr.Version()
	out.T(cr.Style(), "Preparing Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}} ...", out.V{"k8sVersion": k8sVersion, "runtime": cr.Name(), "runtimeVersion": version})
	for _, v := range DockerOpt {
		out.T(out.Option, "opt {{.docker_option}}", out.V{"docker_option": v})
	}
	for _, v := range DockerEnv {
		out.T(out.Option, "env {{.docker_env}}", out.V{"docker_env": v})
	}
}

// setupKubeAdm adds any requested files into the VM before Kubernetes is started
func setupKubeAdm(mAPI libmachine.API, cfg config.ClusterConfig, node config.Node) bootstrapper.Bootstrapper {
	bs, err := cluster.Bootstrapper(mAPI, viper.GetString(cmdcfg.Bootstrapper), cfg, node)
	if err != nil {
		exit.WithError("Failed to get bootstrapper", err)
	}
	for _, eo := range ExtraOptions {
		out.T(out.Option, "{{.extra_option_component_name}}.{{.key}}={{.value}}", out.V{"extra_option_component_name": eo.Component, "key": eo.Key, "value": eo.Value})
	}
	// Loads cached images, generates config files, download binaries
	if err := bs.UpdateCluster(cfg); err != nil {
		exit.WithError("Failed to update cluster", err)
	}
	if err := bs.SetupCerts(cfg.KubernetesConfig, node); err != nil {
		exit.WithError("Failed to setup certs", err)
	}
	return bs
}

func setupKubeconfig(h *host.Host, c *config.ClusterConfig, n *config.Node, clusterName string) (*kubeconfig.Settings, error) {
	addr, err := h.Driver.GetURL()
	if err != nil {
		exit.WithError("Failed to get driver URL", err)
	}
	if !driver.IsKIC(h.DriverName) {
		addr = strings.Replace(addr, "tcp://", "https://", -1)
		addr = strings.Replace(addr, ":2376", ":"+strconv.Itoa(n.Port), -1)
	}

	if c.KubernetesConfig.APIServerName != constants.APIServerName {
		addr = strings.Replace(addr, n.IP, c.KubernetesConfig.APIServerName, -1)
	}
	kcs := &kubeconfig.Settings{
		ClusterName:          clusterName,
		ClusterServerAddress: addr,
		ClientCertificate:    localpath.MakeMiniPath("client.crt"),
		ClientKey:            localpath.MakeMiniPath("client.key"),
		CertificateAuthority: localpath.MakeMiniPath("ca.crt"),
		KeepContext:          viper.GetBool(keepContext),
		EmbedCerts:           viper.GetBool(embedCerts),
	}

	kcs.SetPath(kubeconfig.PathFromEnv())
	if err := kubeconfig.Update(kcs); err != nil {
		return kcs, err
	}
	return kcs, nil
}

// configureMounts configures any requested filesystem mounts
func configureMounts() {
	if !viper.GetBool(createMount) {
		return
	}

	out.T(out.Mounting, "Creating mount {{.name}} ...", out.V{"name": viper.GetString(mountString)})
	path := os.Args[0]
	mountDebugVal := 0
	if glog.V(8) {
		mountDebugVal = 1
	}
	mountCmd := exec.Command(path, "mount", fmt.Sprintf("--v=%d", mountDebugVal), viper.GetString(mountString))
	mountCmd.Env = append(os.Environ(), constants.IsMinikubeChildProcess+"=true")
	if glog.V(8) {
		mountCmd.Stdout = os.Stdout
		mountCmd.Stderr = os.Stderr
	}
	if err := mountCmd.Start(); err != nil {
		exit.WithError("Error starting mount", err)
	}
	if err := lock.WriteFile(filepath.Join(localpath.MiniPath(), constants.MountProcessFileName), []byte(strconv.Itoa(mountCmd.Process.Pid)), 0644); err != nil {
		exit.WithError("Error writing mount pid", err)
	}
}
<|endoftext|>


<commit_before>package namespace

import (
	"fmt"

	kubeModels "github.com/containerum/kube-client/pkg/model"
)

type NamespaceList []Namespace

func NamespaceListFromKube(kubeList kubeModels.NamespacesList) NamespaceList {
	var list NamespaceList = make([]Namespace, 0, len(kubeList.Namespaces))
	for _, namespace := range kubeList.Namespaces {
		list = append(list, NamespaceFromKube(namespace).Copy())
	}
	return list
}

func (list NamespaceList) New() NamespaceList {
	return make(NamespaceList, 0, len(list))
}

func (list NamespaceList) Copy() NamespaceList {
	var cp = list.New()
	for _, namespace := range list {
		cp = append(cp, namespace.Copy())
	}
	return cp
}

func (list NamespaceList) ToKube() kubeModels.NamespacesList {
	var namespaces = make([]kubeModels.Namespace, 0, len(list))
	for _, namespace := range list {
		namespaces = append(namespaces, namespace.ToKube())
	}
	return kubeModels.NamespacesList{
		Namespaces: namespaces,
	}
}

func (list NamespaceList) Len() int {
	return len(list)
}

func (list NamespaceList) Labels() []string {
	var labels = make([]string, 0, list.Len())
	for _, namespace := range list {
		labels = append(labels, namespace.Label)
	}
	return labels
}

func (list NamespaceList) IDs() []string {
	var IDs = make([]string, 0, list.Len())
	for _, namespace := range list {
		IDs = append(IDs, namespace.ID)
	}
	return IDs
}

func (list NamespaceList) LabelsAndIDs() []string {
	var lines = make([]string, 0, list.Len())
	for _, namespace := range list {
		lines = append(lines, fmt.Sprintf("%s %s", namespace.Label, namespace.ID))
	}
	return lines
}
<commit_msg>add methods Filter, GetByUserFriendlyID and GetByLabelAndOwner<commit_after>package namespace

import (
	"fmt"
	"strings"

	kubeModels "github.com/containerum/kube-client/pkg/model"
)

type NamespaceList []Namespace

func NamespaceListFromKube(kubeList kubeModels.NamespacesList) NamespaceList {
	var list NamespaceList = make([]Namespace, 0, len(kubeList.Namespaces))
	for _, namespace := range kubeList.Namespaces {
		list = append(list, NamespaceFromKube(namespace).Copy())
	}
	return list
}

func (list NamespaceList) New() NamespaceList {
	return make(NamespaceList, 0, len(list))
}

func (list NamespaceList) Copy() NamespaceList {
	var cp = list.New()
	for _, namespace := range list {
		cp = append(cp, namespace.Copy())
	}
	return cp
}

func (list NamespaceList) ToKube() kubeModels.NamespacesList {
	var namespaces = make([]kubeModels.Namespace, 0, len(list))
	for _, namespace := range list {
		namespaces = append(namespaces, namespace.ToKube())
	}
	return kubeModels.NamespacesList{
		Namespaces: namespaces,
	}
}

func (list NamespaceList) Len() int {
	return len(list)
}

func (list NamespaceList) GetDefault(i int, defaultNs Namespace) (Namespace, bool) {
	if i >= 0 && i < list.Len() {
		return list.Get(i), true
	}
	return defaultNs, false
}

func (list NamespaceList) Get(i int) Namespace {
	return list[i].Copy()
}

func (list NamespaceList) Head() (Namespace, bool) {
	return list.GetDefault(0, Namespace{})
}

func (list NamespaceList) Labels() []string {
	var labels = make([]string, 0, list.Len())
	for _, namespace := range list {
		labels = append(labels, namespace.Label)
	}
	return labels
}

func (list NamespaceList) IDs() []string {
	var IDs = make([]string, 0, list.Len())
	for _, namespace := range list {
		IDs = append(IDs, namespace.ID)
	}
	return IDs
}

func (list NamespaceList) LabelsAndIDs() []string {
	var lines = make([]string, 0, list.Len())
	for _, namespace := range list {
		lines = append(lines, fmt.Sprintf("%s %s", namespace.Label, namespace.ID))
	}
	return lines
}

func (list NamespaceList) Filter(pred func(Namespace) bool) NamespaceList {
	var filtered = list.New()
	for _, namespace := range list {
		if pred(namespace.Copy()) {
			filtered = append(filtered, namespace.Copy())
		}
	}
	return filtered
}

// get Namespace by string $LABEL or $OWNER_LOGIN/$LABEL
func (list NamespaceList) GetByUserFriendlyID(label string) (Namespace, bool) {
	var tokens = strings.SplitN(label, "/", 2)
	if len(tokens) == 2 {
		return list.GetByLabelAndOwner(tokens[0], tokens[1])
	}
	return list.Filter(func(namespace Namespace) bool {
		return namespace.Label == label
	}).Head()
}

func (list NamespaceList) GetByLabelAndOwner(owner, label string) (Namespace, bool) {
	return list.Filter(func(namespace Namespace) bool {
		return namespace.OwnerLogin == owner && namespace.Label == label
	}).Head()
}
<|endoftext|>


<commit_before>package netiq

import (
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/versent/saml2aws/pkg/cfg"
	"github.com/versent/saml2aws/pkg/creds"
	"github.com/versent/saml2aws/pkg/page"
	"github.com/versent/saml2aws/pkg/prompter"
	"github.com/versent/saml2aws/pkg/provider"
	"net/http"
	"net/url"
	"regexp"
	"strings"
)

var logger = logrus.WithField("provider", "NetIQ")

type Client struct {
	client *provider.HTTPClient
}

// New creates a new external client
func New(idpAccount *cfg.IDPAccount) (*Client, error) {
	tr := provider.NewDefaultTransport(idpAccount.SkipVerify)
	client, err := provider.NewHTTPClient(tr, provider.BuildHttpClientOpts(idpAccount))
	if err != nil {
		return nil, errors.Wrap(err, "Error building HTTP client")
	}
	return &Client{client: client}, nil

}

const samlURL = "/nidp/saml2/idpsend?PID=STSPv8a5kc"

func (nc *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) {
	req, err := http.NewRequest("GET", loginDetails.URL+samlURL, nil)
	if err != nil {
		return "", errors.Wrap(err, "Error building request")
	}
	return nc.follow(req, loginDetails)
}

func (nc *Client) follow(req *http.Request, loginDetails *creds.LoginDetails) (string, error) {
	resp, err := nc.client.Do(req)
	if err != nil {
		return "", errors.Wrap(err, "Failed to perform http request to "+req.URL.String())
	}
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return "", errors.Wrap(err, "failed to build document from response")
	}
	if isSAMLResponse(doc) {
		return extractSAMLAssertion(doc)
	} else if resourcePath, isGetToContext := extractGetToContentUrl(doc); isGetToContext {
		newReq, err := buildGetToContentRequest(loginDetails.URL + resourcePath + "&uiDestination=contentDiv")
		if err != nil {
			return "", errors.Wrap(err, "Error building request")
		}
		return nc.follow(newReq, loginDetails)
	} else if resourceURL, isWinLocHref := extractWinLocHrefURL(doc); isWinLocHref {
		newReq, err := buildGetToContentRequest(resourceURL)
		if err != nil {
			return "", errors.Wrap(err, "Error building request")
		}
		return nc.follow(newReq, loginDetails)
	} else if form, isIDPLoginPass := extractIDPLoginPass(doc); isIDPLoginPass {
		form.Values.Set("Ecom_User_ID", loginDetails.Username)
		form.Values.Set("Ecom_Password", loginDetails.Password)
		newReq, err := form.BuildRequest()
		if err != nil {
			return "", errors.Wrap(err, "Error building request")
		}
		return nc.follow(newReq, loginDetails)
	} else if form, isIDPLoginRsa := extractIDPLoginRsa(doc); isIDPLoginRsa {
		token := prompter.StringRequired("Enter concatenated pin and token")
		form.Values.Set("Ecom_User_ID", loginDetails.Username)
		form.Values.Set("Ecom_Token", token)
		newReq, err := form.BuildRequest()
		if err != nil {
			return "", errors.Wrap(err, "Error building request")
		}
		return nc.follow(newReq, loginDetails)
	} else {
		return "", fmt.Errorf("unknown document type")
	}
}

//func (nc *Client) Do(req *http.Request) (*http.Response, error) {
//	var resp *http.Response
//	err := retry.Do(
//		func() error {
//			clientResp, err := nc.client.Do(req)
//			if err != nil {
//				return err
//			}
//			resp = clientResp
//			return nil
//		},
//		retry.Attempts(5),
//		retry.OnRetry(
//			func(n uint, err error) {
//				fmt.Printf("Retrying http call #%d: %s\n", n, err)
//			}),
//	)
//	return resp, err
//}

func isSAMLResponse(doc *goquery.Document) bool {
	return doc.Find("input[name=\"SAMLResponse\"]").Size() == 1
}

func extractSAMLAssertion(doc *goquery.Document) (string, error) {
	samlAssertion, ok := doc.Find("input[name=\"SAMLResponse\"]").Attr("value")
	if !ok {
		return "", fmt.Errorf("no SAML assertion in response")
	}
	logDocDetected("samlResponse", samlAssertion)
	return samlAssertion, nil
}

func extractGetToContentUrl(doc *goquery.Document) (string, bool) {
	script := doc.Find("body script:contains('getToContent')")
	if script.Size() != 1 {
		return "", false
	}
	re := regexp.MustCompile(`getToContent\('(.*)',.*\);`)
	match := re.FindStringSubmatch(strings.TrimSpace(script.Text()))
	if len(match) == 2 {
		logDocDetected("getToContent", match[1])
		return match[1], true
	} else {
		return "", false
	}
}

func extractWinLocHrefURL(doc *goquery.Document) (string, bool) {
	script := doc.Find("body script:contains('window.location.href')")
	if script.Size() != 1 {
		return "", false
	}
	re := regexp.MustCompile(`window.location.href='(.*)';`)
	match := re.FindStringSubmatch(strings.TrimSpace(script.Text()))
	if len(match) == 2 {
		logDocDetected("winLocHref", match[1])
		return match[1], true
	} else {
		return "", false
	}
}

func extractIDPLoginPass(doc *goquery.Document) (*page.Form, bool) {
	idpPoginForm := doc.Find("body form:has(input[name=\"Ecom_Password\"])")
	if idpPoginForm.Size() != 1 {
		return nil, false
	}
	action, exists := idpPoginForm.Attr("action")
	if !exists {
		return nil, false
	}
	logDocDetected("idpLoginPass", action)
	form := &page.Form{
		URL:    action,
		Method: "POST",
		Values: &url.Values{},
	}
	return form, true
}

func extractIDPLoginRsa(doc *goquery.Document) (*page.Form, bool) {
	idpPoginForm := doc.Find("body form:has(input[name=\"Ecom_Token\"])")
	if idpPoginForm.Size() != 1 {
		return nil, false
	}
	action, exists := idpPoginForm.Attr("action")
	if !exists {
		return nil, false
	}
	logDocDetected("idpLoginRsa", action)
	form := &page.Form{
		URL:    action,
		Method: "POST",
		Values: &url.Values{},
	}
	return form, true
}

func buildGetToContentRequest(resourceURL string) (*http.Request, error) {
	return http.NewRequest("GET", resourceURL, nil)
}

func logDocDetected(docType string, data string) {
	logDetect := logger
	if data != "" {
		logDetect = logDetect.WithField("docType", docType)
	}
	if data != "" {
		logDetect = logDetect.WithField("data", data)
	}
	logDetect.Debug("doc detect")
}
<commit_msg>Clean up NetIQ provider code<commit_after>package netiq

import (
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/versent/saml2aws/pkg/cfg"
	"github.com/versent/saml2aws/pkg/creds"
	"github.com/versent/saml2aws/pkg/page"
	"github.com/versent/saml2aws/pkg/prompter"
	"github.com/versent/saml2aws/pkg/provider"
	"net/http"
	"net/url"
	"regexp"
	"strings"
)

var logger = logrus.WithField("provider", "NetIQ")

type Client struct {
	client *provider.HTTPClient
}

// New creates a new external client
func New(idpAccount *cfg.IDPAccount) (*Client, error) {
	tr := provider.NewDefaultTransport(idpAccount.SkipVerify)
	client, err := provider.NewHTTPClient(tr, provider.BuildHttpClientOpts(idpAccount))
	if err != nil {
		return nil, errors.Wrap(err, "Error building HTTP client")
	}
	return &Client{client: client}, nil

}

const samlURL = "/nidp/saml2/idpsend?PID=STSPv8a5kc"

func (nc *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) {
	req, err := http.NewRequest("GET", loginDetails.URL+samlURL, nil)
	if err != nil {
		return "", errors.Wrap(err, "Error building request")
	}
	return nc.follow(req, loginDetails)
}

func (nc *Client) follow(req *http.Request, loginDetails *creds.LoginDetails) (string, error) {
	resp, err := nc.client.Do(req)
	if err != nil {
		return "", errors.Wrap(err, "Failed to perform http request to "+req.URL.String())
	}
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return "", errors.Wrap(err, "failed to build document from response")
	}
	if isSAMLResponse(doc) {
		return extractSAMLAssertion(doc)
	} else if resourcePath, isGetToContext := extractGetToContentUrl(doc); isGetToContext {
		newReq, err := buildGetToContentRequest(loginDetails.URL + resourcePath + "&uiDestination=contentDiv")
		if err != nil {
			return "", errors.Wrap(err, "Error building request")
		}
		return nc.follow(newReq, loginDetails)
	} else if resourceURL, isWinLocHref := extractWinLocHrefURL(doc); isWinLocHref {
		newReq, err := buildGetToContentRequest(resourceURL)
		if err != nil {
			return "", errors.Wrap(err, "Error building request")
		}
		return nc.follow(newReq, loginDetails)
	} else if form, isIDPLoginPass := extractIDPLoginPass(doc); isIDPLoginPass {
		form.Values.Set("Ecom_User_ID", loginDetails.Username)
		form.Values.Set("Ecom_Password", loginDetails.Password)
		newReq, err := form.BuildRequest()
		if err != nil {
			return "", errors.Wrap(err, "Error building request")
		}
		return nc.follow(newReq, loginDetails)
	} else if form, isIDPLoginRsa := extractIDPLoginRsa(doc); isIDPLoginRsa {
		token := prompter.StringRequired("Enter concatenated pin and token")
		form.Values.Set("Ecom_User_ID", loginDetails.Username)
		form.Values.Set("Ecom_Token", token)
		newReq, err := form.BuildRequest()
		if err != nil {
			return "", errors.Wrap(err, "Error building request")
		}
		return nc.follow(newReq, loginDetails)
	} else {
		return "", fmt.Errorf("unknown document type")
	}
}

func isSAMLResponse(doc *goquery.Document) bool {
	return doc.Find("input[name=\"SAMLResponse\"]").Size() == 1
}

func extractSAMLAssertion(doc *goquery.Document) (string, error) {
	samlAssertion, ok := doc.Find("input[name=\"SAMLResponse\"]").Attr("value")
	if !ok {
		return "", fmt.Errorf("no SAML assertion in response")
	}
	logDocDetected("samlResponse", samlAssertion)
	return samlAssertion, nil
}

func extractGetToContentUrl(doc *goquery.Document) (string, bool) {
	script := doc.Find("body script:contains('getToContent')")
	if script.Size() != 1 {
		return "", false
	}
	re := regexp.MustCompile(`getToContent\('(.*)',.*\);`)
	match := re.FindStringSubmatch(strings.TrimSpace(script.Text()))
	if len(match) == 2 {
		logDocDetected("getToContent", match[1])
		return match[1], true
	} else {
		return "", false
	}
}

func extractWinLocHrefURL(doc *goquery.Document) (string, bool) {
	script := doc.Find("body script:contains('window.location.href')")
	if script.Size() != 1 {
		return "", false
	}
	re := regexp.MustCompile(`window.location.href='(.*)';`)
	match := re.FindStringSubmatch(strings.TrimSpace(script.Text()))
	if len(match) == 2 {
		logDocDetected("winLocHref", match[1])
		return match[1], true
	} else {
		return "", false
	}
}

func extractIDPLoginPass(doc *goquery.Document) (*page.Form, bool) {
	idpPoginForm := doc.Find("body form:has(input[name=\"Ecom_Password\"])")
	if idpPoginForm.Size() != 1 {
		return nil, false
	}
	action, exists := idpPoginForm.Attr("action")
	if !exists {
		return nil, false
	}
	logDocDetected("idpLoginPass", action)
	form := &page.Form{
		URL:    action,
		Method: "POST",
		Values: &url.Values{},
	}
	return form, true
}

func extractIDPLoginRsa(doc *goquery.Document) (*page.Form, bool) {
	idpPoginForm := doc.Find("body form:has(input[name=\"Ecom_Token\"])")
	if idpPoginForm.Size() != 1 {
		return nil, false
	}
	action, exists := idpPoginForm.Attr("action")
	if !exists {
		return nil, false
	}
	logDocDetected("idpLoginRsa", action)
	form := &page.Form{
		URL:    action,
		Method: "POST",
		Values: &url.Values{},
	}
	return form, true
}

func buildGetToContentRequest(resourceURL string) (*http.Request, error) {
	return http.NewRequest("GET", resourceURL, nil)
}

func logDocDetected(docType string, data string) {
	logDetect := logger
	if data != "" {
		logDetect = logDetect.WithField("docType", docType)
	}
	if data != "" {
		logDetect = logDetect.WithField("data", data)
	}
	logDetect.Debug("doc detect")
}
<|endoftext|>


<commit_before>package storkctl

import (
	"fmt"
	"io"
	"reflect"
	"strings"

	storkv1 "github.com/libopenstorage/stork/pkg/apis/stork/v1alpha1"
	"github.com/portworx/sched-ops/k8s"
	"github.com/spf13/cobra"
	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
	"k8s.io/kubernetes/pkg/printers"
)

const (
	clusterPairSubcommand = "clusterpair"
	cmdPathKey            = "cmd-path"
	gcloudPath            = "./google-cloud-sdk/bin/gcloud"
	gcloudBinaryName      = "gcloud"
)

var clusterPairColumns = []string{"NAME", "STORAGE-STATUS", "SCHEDULER-STATUS", "CREATED"}

func newGetClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	var err error
	getClusterPairCommand := &cobra.Command{
		Use:     clusterPairSubcommand,
		Aliases: []string{"cp"},
		Short:   "Get cluster pair resources",
		Run: func(c *cobra.Command, args []string) {
			var clusterPairs *storkv1.ClusterPairList
			if len(args) > 0 {
				clusterPairs = new(storkv1.ClusterPairList)
				for _, pairName := range args {
					pair, err := k8s.Instance().GetClusterPair(pairName)
					if err != nil {
						handleError(err, ioStreams.ErrOut)
					}
					clusterPairs.Items = append(clusterPairs.Items, *pair)
				}
			} else {
				clusterPairs, err = k8s.Instance().ListClusterPairs()
				if err != nil {
					handleError(err, ioStreams.ErrOut)
				}
			}

			if len(clusterPairs.Items) == 0 {
				handleEmptyList(ioStreams.Out)
				return
			}

			outputFormat, err := cmdFactory.GetOutputFormat()
			if err != nil {
				handleError(err, ioStreams.ErrOut)
			}

			if err := printObjects(c, clusterPairs, outputFormat, clusterPairColumns, clusterPairPrinter, ioStreams.Out); err != nil {
				handleError(err, ioStreams.ErrOut)
			}
		},
	}

	return getClusterPairCommand
}

func clusterPairPrinter(clusterPairList *storkv1.ClusterPairList, writer io.Writer, options printers.PrintOptions) error {
	if clusterPairList == nil {
		return nil
	}
	for _, clusterPair := range clusterPairList.Items {
		name := printers.FormatResourceName(options.Kind, clusterPair.Name, options.WithKind)

		creationTime := toTimeString(clusterPair.CreationTimestamp)
		if _, err := fmt.Fprintf(writer, "%v\t%v\t%v\t%v\n",
			name,
			clusterPair.Status.StorageStatus,
			clusterPair.Status.SchedulerStatus,
			creationTime); err != nil {
			return err
		}
	}
	return nil
}

func newGenerateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	generateClusterPairCommand := &cobra.Command{
		Use:   clusterPairSubcommand,
		Short: "Generate a spec to be used for cluster pairing from a remote cluster",
		Run: func(c *cobra.Command, args []string) {
			config, err := cmdFactory.RawConfig()
			if err != nil {
				handleError(err, ioStreams.ErrOut)
			}

			// Prune out all but the current-context and related
			// info
			currentContext := config.CurrentContext
			for context := range config.Contexts {
				if context != currentContext {
					delete(config.Contexts, context)
				}
			}
			currentCluster := config.Contexts[currentContext].Cluster
			for cluster := range config.Clusters {
				if cluster != currentCluster {
					delete(config.Clusters, cluster)
				}
			}
			currentAuthInfo := config.Contexts[currentContext].AuthInfo
			for authInfo := range config.AuthInfos {
				if authInfo != currentAuthInfo {
					delete(config.AuthInfos, authInfo)
				}
			}

			// Replace gcloud paths in the config
			if config.AuthInfos[currentAuthInfo] != nil && config.AuthInfos[currentAuthInfo].AuthProvider != nil &&
				config.AuthInfos[currentAuthInfo].AuthProvider.Config != nil {
				if cmdPath, present := config.AuthInfos[currentAuthInfo].AuthProvider.Config[cmdPathKey]; present {
					if strings.HasSuffix(cmdPath, gcloudBinaryName) {
						config.AuthInfos[currentAuthInfo].AuthProvider.Config[cmdPathKey] = gcloudPath
					}
				}
			}
			clusterPair := &storkv1.ClusterPair{
				TypeMeta: meta.TypeMeta{
					Kind:       reflect.TypeOf(storkv1.ClusterPair{}).Name(),
					APIVersion: storkv1.SchemeGroupVersion.String(),
				},
				ObjectMeta: meta.ObjectMeta{
					Name: "<insert_name_here>",
				},

				Spec: storkv1.ClusterPairSpec{
					Config: config,
					Options: map[string]string{
						"<insert_storage_options_here>": "",
					},
				},
			}
			if err = printEncoded(c, clusterPair, "yaml", ioStreams.Out); err != nil {
				handleError(err, ioStreams.ErrOut)
			}
		},
	}

	return generateClusterPairCommand
}
<commit_msg>Read files when generating cluster pair and populate inline<commit_after>package storkctl

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"reflect"
	"strings"

	storkv1 "github.com/libopenstorage/stork/pkg/apis/stork/v1alpha1"
	"github.com/portworx/sched-ops/k8s"
	"github.com/spf13/cobra"
	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
	"k8s.io/kubernetes/pkg/printers"
)

const (
	clusterPairSubcommand = "clusterpair"
	cmdPathKey            = "cmd-path"
	gcloudPath            = "./google-cloud-sdk/bin/gcloud"
	gcloudBinaryName      = "gcloud"
)

var clusterPairColumns = []string{"NAME", "STORAGE-STATUS", "SCHEDULER-STATUS", "CREATED"}

func newGetClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	var err error
	getClusterPairCommand := &cobra.Command{
		Use:     clusterPairSubcommand,
		Aliases: []string{"cp"},
		Short:   "Get cluster pair resources",
		Run: func(c *cobra.Command, args []string) {
			var clusterPairs *storkv1.ClusterPairList
			if len(args) > 0 {
				clusterPairs = new(storkv1.ClusterPairList)
				for _, pairName := range args {
					pair, err := k8s.Instance().GetClusterPair(pairName)
					if err != nil {
						handleError(err, ioStreams.ErrOut)
					}
					clusterPairs.Items = append(clusterPairs.Items, *pair)
				}
			} else {
				clusterPairs, err = k8s.Instance().ListClusterPairs()
				if err != nil {
					handleError(err, ioStreams.ErrOut)
				}
			}

			if len(clusterPairs.Items) == 0 {
				handleEmptyList(ioStreams.Out)
				return
			}

			outputFormat, err := cmdFactory.GetOutputFormat()
			if err != nil {
				handleError(err, ioStreams.ErrOut)
			}

			if err := printObjects(c, clusterPairs, outputFormat, clusterPairColumns, clusterPairPrinter, ioStreams.Out); err != nil {
				handleError(err, ioStreams.ErrOut)
			}
		},
	}

	return getClusterPairCommand
}

func clusterPairPrinter(clusterPairList *storkv1.ClusterPairList, writer io.Writer, options printers.PrintOptions) error {
	if clusterPairList == nil {
		return nil
	}
	for _, clusterPair := range clusterPairList.Items {
		name := printers.FormatResourceName(options.Kind, clusterPair.Name, options.WithKind)

		creationTime := toTimeString(clusterPair.CreationTimestamp)
		if _, err := fmt.Fprintf(writer, "%v\t%v\t%v\t%v\n",
			name,
			clusterPair.Status.StorageStatus,
			clusterPair.Status.SchedulerStatus,
			creationTime); err != nil {
			return err
		}
	}
	return nil
}

func getStringData(fileName string) (string, error) {
	file, err := os.Open(fileName)
	if err != nil {
		return "", fmt.Errorf("Error opening file %v: %v", fileName, err)
	}
	data, err := ioutil.ReadAll(bufio.NewReader(file))
	if err != nil {
		return "", fmt.Errorf("Error reading file %v: %v", fileName, err)
	}

	return string(data), nil
}

func getByteData(fileName string) ([]byte, error) {
	data, err := getStringData(fileName)
	if err != nil {
		return nil, err
	}
	return []byte(data), nil
}

func newGenerateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	generateClusterPairCommand := &cobra.Command{
		Use:   clusterPairSubcommand,
		Short: "Generate a spec to be used for cluster pairing from a remote cluster",
		Run: func(c *cobra.Command, args []string) {
			config, err := cmdFactory.RawConfig()
			if err != nil {
				handleError(err, ioStreams.ErrOut)
			}

			// Prune out all but the current-context and related
			// info
			currentContext := config.CurrentContext
			for context := range config.Contexts {
				if context != currentContext {
					delete(config.Contexts, context)
				}
			}
			currentCluster := config.Contexts[currentContext].Cluster
			for cluster := range config.Clusters {
				if cluster != currentCluster {
					delete(config.Clusters, cluster)
				}
			}
			currentAuthInfo := config.Contexts[currentContext].AuthInfo
			for authInfo := range config.AuthInfos {
				if authInfo != currentAuthInfo {
					delete(config.AuthInfos, authInfo)
				}
			}

			if config.AuthInfos[currentAuthInfo] != nil {
				// Replace gcloud paths in the config
				if config.AuthInfos[currentAuthInfo].AuthProvider != nil &&
					config.AuthInfos[currentAuthInfo].AuthProvider.Config != nil {
					if cmdPath, present := config.AuthInfos[currentAuthInfo].AuthProvider.Config[cmdPathKey]; present {
						if strings.HasSuffix(cmdPath, gcloudBinaryName) {
							config.AuthInfos[currentAuthInfo].AuthProvider.Config[cmdPathKey] = gcloudPath
						}
					}
				}

				// Replace file paths with inline data
				if config.AuthInfos[currentAuthInfo].ClientCertificate != "" && len(config.AuthInfos[currentAuthInfo].ClientCertificateData) == 0 {
					config.AuthInfos[currentAuthInfo].ClientCertificateData, err = getByteData(config.AuthInfos[currentAuthInfo].ClientCertificate)
					if err != nil {
						handleError(err, ioStreams.ErrOut)
					}
					config.AuthInfos[currentAuthInfo].ClientCertificate = ""
				}
				if config.AuthInfos[currentAuthInfo].ClientKey != "" && len(config.AuthInfos[currentAuthInfo].ClientKeyData) == 0 {
					config.AuthInfos[currentAuthInfo].ClientKeyData, err = getByteData(config.AuthInfos[currentAuthInfo].ClientKey)
					if err != nil {
						handleError(err, ioStreams.ErrOut)
					}
					config.AuthInfos[currentAuthInfo].ClientKey = ""
				}
				if config.AuthInfos[currentAuthInfo].TokenFile != "" && len(config.AuthInfos[currentAuthInfo].Token) == 0 {
					config.AuthInfos[currentAuthInfo].Token, err = getStringData(config.AuthInfos[currentAuthInfo].TokenFile)
					if err != nil {
						handleError(err, ioStreams.ErrOut)
					}
					config.AuthInfos[currentAuthInfo].TokenFile = ""
				}
			}
			if config.Clusters[currentCluster] != nil &&
				config.Clusters[currentCluster].CertificateAuthority != "" &&
				len(config.Clusters[currentCluster].CertificateAuthorityData) == 0 {

				config.Clusters[currentCluster].CertificateAuthorityData, err = getByteData(config.Clusters[currentCluster].CertificateAuthority)
				if err != nil {
					handleError(err, ioStreams.ErrOut)
				}
				config.Clusters[currentCluster].CertificateAuthority = ""
			}

			clusterPair := &storkv1.ClusterPair{
				TypeMeta: meta.TypeMeta{
					Kind:       reflect.TypeOf(storkv1.ClusterPair{}).Name(),
					APIVersion: storkv1.SchemeGroupVersion.String(),
				},
				ObjectMeta: meta.ObjectMeta{
					Name: "<insert_name_here>",
				},

				Spec: storkv1.ClusterPairSpec{
					Config: config,
					Options: map[string]string{
						"<insert_storage_options_here>": "",
					},
				},
			}
			if err = printEncoded(c, clusterPair, "yaml", ioStreams.Out); err != nil {
				handleError(err, ioStreams.ErrOut)
			}
		},
	}

	return generateClusterPairCommand
}
<|endoftext|>