<commit_before>package types

import (
	"io"

	"github.com/bytom/bytom/consensus"
	"github.com/bytom/bytom/encoding/blockchain"
	"github.com/bytom/bytom/protocol/bc"
)

// SupLinks is alias of SupLink slice
type SupLinks []*SupLink

// AddSupLink used to add a supLink by specified validator
func (s *SupLinks) AddSupLink(sourceHeight uint64, sourceHash bc.Hash, signature []byte, validatorOrder int) {
	for _, supLink := range *s {
		if supLink.SourceHash == sourceHash {
			supLink.Signatures[validatorOrder] = signature
			return
		}
	}

	supLink := &SupLink{SourceHeight: sourceHeight, SourceHash: sourceHash}
	supLink.Signatures[validatorOrder] = signature
	*s = append(*s, supLink)
}

func (s *SupLinks) readFrom(r *blockchain.Reader) (err error) {
	size, err := blockchain.ReadVarint31(r)
	if err != nil {
		return err
	}

	supLinks := make([]*SupLink, size)
	for i := 0; i < int(size); i++ {
		supLink := &SupLink{}
		if err := supLink.readFrom(r); err != nil {
			return err
		}

		supLinks[i] = supLink
	}
	*s = supLinks
	return nil
}

func (s SupLinks) writeTo(w io.Writer) error {
	if _, err := blockchain.WriteVarint31(w, uint64(len(s))); err != nil {
		return err
	}

	for _, supLink := range s {
		if err := supLink.writeTo(w); err != nil {
			return err
		}
	}
	return nil
}

// SupLink is an ordered pair of checkpoints (a, b), also written a → b
// the validators will sign it once considered as legal
type SupLink struct {
	SourceHeight uint64
	SourceHash   bc.Hash
	Signatures   [consensus.MaxNumOfValidators][]byte
}

// IsMajority if at least 2/3 of validators have published votes with sup link
func (s *SupLink) IsMajority(numOfValidators int) bool {
	numOfSignatures := 0
	for _, signature := range s.Signatures {
		if len(signature) >= 0 {
			numOfSignatures++
		}
	}
	return numOfSignatures > numOfValidators*2/3
}

func (s *SupLink) readFrom(r *blockchain.Reader) (err error) {
	if s.SourceHeight, err = blockchain.ReadVarint63(r); err != nil {
		return err
	}

	if _, err := s.SourceHash.ReadFrom(r); err != nil {
		return err
	}

	for i := 0; i < consensus.MaxNumOfValidators; i++ {
		if s.Signatures[i], err = blockchain.ReadVarstr31(r); err != nil {
			return err
		}
	}
	return
}

func (s *SupLink) writeTo(w io.Writer) error {
	if _, err := blockchain.WriteVarint63(w, s.SourceHeight); err != nil {
		return err
	}

	if _, err := s.SourceHash.WriteTo(w); err != nil {
		return err
	}

	for _, signature := range s.Signatures {
		if _, err := blockchain.WriteVarstr31(w, signature); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>fix is majority<commit_after>package types

import (
	"io"

	"github.com/bytom/bytom/consensus"
	"github.com/bytom/bytom/encoding/blockchain"
	"github.com/bytom/bytom/protocol/bc"
)

// SupLinks is alias of SupLink slice
type SupLinks []*SupLink

// AddSupLink used to add a supLink by specified validator
func (s *SupLinks) AddSupLink(sourceHeight uint64, sourceHash bc.Hash, signature []byte, validatorOrder int) {
	for _, supLink := range *s {
		if supLink.SourceHash == sourceHash {
			supLink.Signatures[validatorOrder] = signature
			return
		}
	}

	supLink := &SupLink{SourceHeight: sourceHeight, SourceHash: sourceHash}
	supLink.Signatures[validatorOrder] = signature
	*s = append(*s, supLink)
}

func (s *SupLinks) readFrom(r *blockchain.Reader) (err error) {
	size, err := blockchain.ReadVarint31(r)
	if err != nil {
		return err
	}

	supLinks := make([]*SupLink, size)
	for i := 0; i < int(size); i++ {
		supLink := &SupLink{}
		if err := supLink.readFrom(r); err != nil {
			return err
		}

		supLinks[i] = supLink
	}
	*s = supLinks
	return nil
}

func (s SupLinks) writeTo(w io.Writer) error {
	if _, err := blockchain.WriteVarint31(w, uint64(len(s))); err != nil {
		return err
	}

	for _, supLink := range s {
		if err := supLink.writeTo(w); err != nil {
			return err
		}
	}
	return nil
}

// SupLink is an ordered pair of checkpoints (a, b), also written a → b
// the validators will sign it once considered as legal
type SupLink struct {
	SourceHeight uint64
	SourceHash   bc.Hash
	Signatures   [consensus.MaxNumOfValidators][]byte
}

// IsMajority if at least 2/3 of validators have published votes with sup link
func (s *SupLink) IsMajority(numOfValidators int) bool {
	numOfSignatures := 0
	for _, signature := range s.Signatures {
		if len(signature) > 0 {
			numOfSignatures++
		}
	}
	return numOfSignatures > numOfValidators*2/3
}

func (s *SupLink) readFrom(r *blockchain.Reader) (err error) {
	if s.SourceHeight, err = blockchain.ReadVarint63(r); err != nil {
		return err
	}

	if _, err := s.SourceHash.ReadFrom(r); err != nil {
		return err
	}

	for i := 0; i < consensus.MaxNumOfValidators; i++ {
		if s.Signatures[i], err = blockchain.ReadVarstr31(r); err != nil {
			return err
		}
	}
	return
}

func (s *SupLink) writeTo(w io.Writer) error {
	if _, err := blockchain.WriteVarint63(w, s.SourceHeight); err != nil {
		return err
	}

	if _, err := s.SourceHash.WriteTo(w); err != nil {
		return err
	}

	for _, signature := range s.Signatures {
		if _, err := blockchain.WriteVarstr31(w, signature); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before><commit_msg>Corrent json for field<commit_after><|endoftext|>


<commit_before>package storage

import (
	"encoding/json"
	"errors"
	"github.com/RangelReale/osin"
	"github.com/garyburd/redigo/redis"
	"time"
)

const (
	CLIENT_PREFIX    = "client."
	AUTHORIZE_PREFIX = "authorization."
	ACCESS_PREFIX    = "access."
)

type RedisStorage struct {
	pool   *redis.Pool
	prefix string
}

func NewRedisStorage(server, prefix string) *RedisStorage {
	pool := newPool(server, "")
	return &RedisStorage{pool: pool, prefix: prefix}
}

func newPool(server, password string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func (store *RedisStorage) Close() {}

func (storage *RedisStorage) Clone() osin.Storage {
	return storage
}

func (storage *RedisStorage) GetClient(id string) (osin.Client, error) {
	key := CLIENT_PREFIX + id
	clientJSON, err := storage.GetKey(key)
	if err != nil {
		return nil, err
	}

	client := new(osin.DefaultClient)
	if err := json.Unmarshal([]byte(clientJSON), &client); err != nil {
		return nil, err
	}

	return client, nil
}

func (storage *RedisStorage) SetClient(id string, client osin.Client) error {
	key := CLIENT_PREFIX + id
	clientJSON, err := json.Marshal(client)
	if err != nil {
		return err
	}

	conn := storage.pool.Get()
	defer conn.Close()
	_, err = conn.Do("SET", key, clientJSON)
	return err
}

func (storage *RedisStorage) SaveAuthorize(data *osin.AuthorizeData) error {
	key := AUTHORIZE_PREFIX + data.Code
	dataJSON, err := json.Marshal(data)
	if err != nil {
		return err
	}

	conn := storage.pool.Get()
	defer conn.Close()
	_, err = conn.Do("SET", key, dataJSON)
	return err
}

func (storage *RedisStorage) LoadAuthorize(code string) (*osin.AuthorizeData, error) {
	key := AUTHORIZE_PREFIX + code
	authJSON, err := storage.GetKey(key)
	if err != nil {
		return nil, err
	}

	auth := new(osin.AuthorizeData)
	if err := json.Unmarshal([]byte(authJSON), &auth); err != nil {
		return nil, err
	}

	return auth, nil
}

func (storage *RedisStorage) RemoveAuthorize(code string) error {
	key := AUTHORIZE_PREFIX + code
	storage.DeleteKey(key)
	return nil
}

func (storage *RedisStorage) SaveAccess(data *osin.AccessData) error {
	key := ACCESS_PREFIX + data.AccessToken
	dataJSON, err := json.Marshal(data)
	if err != nil {
		return err
	}

	conn := storage.pool.Get()
	defer conn.Close()
	_, err = conn.Do("SET", key, dataJSON)
	return err
}

func (storage *RedisStorage) LoadAccess(token string) (*osin.AccessData, error) {
	key := ACCESS_PREFIX + token
	accessJSON, err := storage.GetKey(key)
	if err != nil {
		return nil, err
	}

	access := new(osin.AccessData)
	if err := json.Unmarshal([]byte(accessJSON), &access); err != nil {
		return nil, err
	}

	return access, nil
}

func (storage *RedisStorage) RemoveAccess(token string) error {
	key := ACCESS_PREFIX + token
	storage.DeleteKey(key)
	return nil
}

func (storage *RedisStorage) LoadRefresh(token string) (*osin.AccessData, error) {
	return nil, errors.New("Not implemented")
}

func (storage *RedisStorage) RemoveRefresh(token string) error {
	return errors.New("Not implemented")
}

func (storage *RedisStorage) GetKey(keyName string) (string, error) {
	db := storage.pool.Get()
	defer db.Close()
	value, err := redis.String(db.Do("GET", keyName))
	if err != nil {
		return "", err
	}

	return value, nil
}

func (storage *RedisStorage) DeleteKey(keyName string) bool {
	db := storage.pool.Get()
	defer db.Close()
	_, err := db.Do("DEL", keyName)
	if err != nil {
		return false
	}

	return true
}
<commit_msg>[PLATFORM-549] Set method for Redis OAuth2 storage<commit_after>package storage

import (
	"encoding/json"
	"errors"
	"github.com/RangelReale/osin"
	"github.com/garyburd/redigo/redis"
	"time"
)

const (
	CLIENT_PREFIX    = "client."
	AUTHORIZE_PREFIX = "authorization."
	ACCESS_PREFIX    = "access."
)

type RedisStorage struct {
	pool   *redis.Pool
	prefix string
}

func NewRedisStorage(server, prefix string) *RedisStorage {
	pool := newPool(server, "")
	return &RedisStorage{pool: pool, prefix: prefix}
}

func newPool(server, password string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func (store *RedisStorage) Close() {}

func (storage *RedisStorage) Clone() osin.Storage {
	return storage
}

func (storage *RedisStorage) GetClient(id string) (osin.Client, error) {
	key := CLIENT_PREFIX + id
	clientJSON, err := storage.GetKey(key)
	if err != nil {
		return nil, err
	}

	client := new(osin.DefaultClient)
	if err := json.Unmarshal([]byte(clientJSON), &client); err != nil {
		return nil, err
	}

	return client, nil
}

func (storage *RedisStorage) SetClient(id string, client osin.Client) error {
	key := CLIENT_PREFIX + id
	clientJSON, err := json.Marshal(client)
	if err != nil {
		return err
	}

	err = storage.SetKey(key, string(clientJSON))
	return err
}

func (storage *RedisStorage) SaveAuthorize(data *osin.AuthorizeData) error {
	key := AUTHORIZE_PREFIX + data.Code
	dataJSON, err := json.Marshal(data)
	if err != nil {
		return err
	}

	err = storage.SetKey(key, string(dataJSON))
	return err
}

func (storage *RedisStorage) LoadAuthorize(code string) (*osin.AuthorizeData, error) {
	key := AUTHORIZE_PREFIX + code
	authJSON, err := storage.GetKey(key)
	if err != nil {
		return nil, err
	}

	auth := new(osin.AuthorizeData)
	if err := json.Unmarshal([]byte(authJSON), &auth); err != nil {
		return nil, err
	}

	return auth, nil
}

func (storage *RedisStorage) RemoveAuthorize(code string) error {
	key := AUTHORIZE_PREFIX + code
	storage.DeleteKey(key)
	return nil
}

func (storage *RedisStorage) SaveAccess(data *osin.AccessData) error {
	key := ACCESS_PREFIX + data.AccessToken
	dataJSON, err := json.Marshal(data)
	if err != nil {
		return err
	}

	err = storage.SetKey(key, string(dataJSON))
	return err
}

func (storage *RedisStorage) LoadAccess(token string) (*osin.AccessData, error) {
	key := ACCESS_PREFIX + token
	accessJSON, err := storage.GetKey(key)
	if err != nil {
		return nil, err
	}

	access := new(osin.AccessData)
	if err := json.Unmarshal([]byte(accessJSON), &access); err != nil {
		return nil, err
	}

	return access, nil
}

func (storage *RedisStorage) RemoveAccess(token string) error {
	key := ACCESS_PREFIX + token
	storage.DeleteKey(key)
	return nil
}

func (storage *RedisStorage) LoadRefresh(token string) (*osin.AccessData, error) {
	return nil, errors.New("Not implemented")
}

func (storage *RedisStorage) RemoveRefresh(token string) error {
	return errors.New("Not implemented")
}

func (storage *RedisStorage) GetKey(keyName string) (string, error) {
	db := storage.pool.Get()
	defer db.Close()
	value, err := redis.String(db.Do("GET", keyName))
	if err != nil {
		return "", err
	}

	return value, nil
}

func (storage *RedisStorage) SetKey(key string, value string) error {
	db := storage.pool.Get()
	defer db.Close()
	_, err := db.Do("SET", key, value)
	if err != nil {
		return err
	}
	return nil
}

func (storage *RedisStorage) DeleteKey(keyName string) bool {
	db := storage.pool.Get()
	defer db.Close()
	_, err := db.Do("DEL", keyName)
	if err != nil {
		return false
	}

	return true
}
<|endoftext|>


<commit_before>package proto

import(
	"tritium/protoface"
)

func (m *ScriptObject) IGetName() string {
	return ""
}

func (m *ScriptObject) IGetRoot() protoface.Instruction {
	return m.GetRoot()
}

func (m *ScriptObject) IGetNthFunction(index int) protoface.Function {
	return nil
}

func (m *ScriptObject) ISetNthFunction(index int, value protoface.Function) {
	return
}

func (m *ScriptObject) IGetScopeTypeId() int32 {
	return 0
}

func (m *ScriptObject) IGetLinked() bool {
	return false
}

func (m *ScriptObject) IGetModule() string {
	return m.GetModule()
}<commit_msg>Forgot to implement this method ... not sure why it builds locally and not on Jenkins, though.<commit_after>package proto

import(
	"tritium/protoface"
)

func (m *ScriptObject) IGetName() string {
	return ""
}

func (m *ScriptObject) IGetRoot() protoface.Instruction {
	return m.GetRoot()
}

func (m *ScriptObject) IGetNthFunction(index int) protoface.Function {
	return nil
}

func (m *ScriptObject) ISetNthFunction(index int, value protoface.Function) {
	return
}

func (m *ScriptObject) IGetScopeTypeId() int32 {
	return 0
}

func (m *ScriptObject) IGetLinked() bool {
	return false
}

func (m *ScriptObject) IGetModule() string {
	return m.GetModule()
}

func (m *ScriptObject) IGetLayer() string {
	return m.GetModule()
}<|endoftext|>


<commit_before>package auth0_test

import (
	"os"
	"testing"

	"github.com/markbates/goth"
	"github.com/markbates/goth/providers/auth0"
	"github.com/stretchr/testify/assert"
	"gopkg.in/jarcoal/httpmock.v1"
)

func Test_New(t *testing.T) {
	t.Parallel()
	a := assert.New(t)
	p := provider()

	a.Equal(p.ClientKey, os.Getenv("AUTH0_KEY"))
	a.Equal(p.Secret, os.Getenv("AUTH0_SECRET"))
	a.Equal(p.Domain, os.Getenv("AUTH0_DOMAIN"))
	a.Equal(p.CallbackURL, "/foo")
}

func Test_Implements_Provider(t *testing.T) {
	t.Parallel()
	a := assert.New(t)
	a.Implements((*goth.Provider)(nil), provider())
}

func Test_BeginAuth(t *testing.T) {
	t.Parallel()
	a := assert.New(t)
	p := provider()
	session, err := p.BeginAuth("test_state")
	s := session.(*auth0.Session)
	a.NoError(err)
	expectedAuthURL := "https://" + os.Getenv("AUTH0_DOMAIN") + "/oauth/authorize"
	a.Contains(s.AuthURL, expectedAuthURL)
}

func Test_SessionFromJSON(t *testing.T) {
	t.Parallel()
	a := assert.New(t)

	p := provider()
	sessionResp := `{"AuthURL":"https://` + p.Domain + `/oauth/authorize","AccessToken":"1234567890"}`
	session, err := p.UnmarshalSession(sessionResp)
	a.NoError(err)

	s := session.(*auth0.Session)
	expectedAuthURL := "https://" + os.Getenv("AUTH0_DOMAIN") + "/oauth/authorize"
	a.Equal(s.AuthURL, expectedAuthURL)
	a.Equal(s.AccessToken, "1234567890")
}

func Test_FetchUser(t *testing.T) {
	t.Parallel()
	a := assert.New(t)

	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	sampleResp := `{
  		"email_verified": false,
  		"email": "test.account@userinfo.com",
  		"clientID": "q2hnj2iu...",
  		"updated_at": "2016-12-05T15:15:40.545Z",
  		"name": "test.account@userinfo.com",
  		"picture": "https://s.gravatar.com/avatar/dummy.png",
  		"user_id": "auth0|58454...",
  		"nickname": "test.account",
  		"identities": [
  		  {
      			"user_id": "58454...",
      			"provider": "auth0",
      			"connection": "Username-Password-Authentication",
      			"isSocial": false
    		}],
  		"created_at": "2016-12-05T11:16:59.640Z",
  		"sub": "auth0|58454..."
	}`

	httpmock.RegisterResponder("GET", "https://"+os.Getenv("AUTH0_DOMAIN")+"/userinfo",
		httpmock.NewStringResponder(200, sampleResp))

	p := provider()
	session, err := p.BeginAuth("test_state")
	s := session.(*auth0.Session)
	u, err := p.FetchUser(s)
	a.Nil(err)
	a.Equal(u.Email, "test.account@userinfo.com")
	a.Equal(u.UserID, "auth0|58454...")
	a.Equal(u.NickName, "test.account")
	a.Equal(u.Name, "test.account@userinfo.com")

}

func provider() *auth0.Provider {
	return auth0.New(os.Getenv("AUTH0_KEY"), os.Getenv("AUTH0_SECRET"), "/foo", os.Getenv("AUTH0_DOMAIN"))
}
<commit_msg>removing parallelism from mocked http tests<commit_after>package auth0_test

import (
	"os"
	"testing"

	"github.com/markbates/goth"
	"github.com/markbates/goth/providers/auth0"
	"github.com/stretchr/testify/assert"
	"gopkg.in/jarcoal/httpmock.v1"
)

func Test_New(t *testing.T) {
	t.Parallel()
	a := assert.New(t)
	p := provider()

	a.Equal(p.ClientKey, os.Getenv("AUTH0_KEY"))
	a.Equal(p.Secret, os.Getenv("AUTH0_SECRET"))
	a.Equal(p.Domain, os.Getenv("AUTH0_DOMAIN"))
	a.Equal(p.CallbackURL, "/foo")
}

func Test_Implements_Provider(t *testing.T) {
	t.Parallel()
	a := assert.New(t)
	a.Implements((*goth.Provider)(nil), provider())
}

func Test_BeginAuth(t *testing.T) {
	t.Parallel()
	a := assert.New(t)
	p := provider()
	session, err := p.BeginAuth("test_state")
	s := session.(*auth0.Session)
	a.NoError(err)
	expectedAuthURL := "https://" + os.Getenv("AUTH0_DOMAIN") + "/oauth/authorize"
	a.Contains(s.AuthURL, expectedAuthURL)
}

func Test_SessionFromJSON(t *testing.T) {
	t.Parallel()
	a := assert.New(t)

	p := provider()
	sessionResp := `{"AuthURL":"https://` + p.Domain + `/oauth/authorize","AccessToken":"1234567890"}`
	session, err := p.UnmarshalSession(sessionResp)
	a.NoError(err)

	s := session.(*auth0.Session)
	expectedAuthURL := "https://" + os.Getenv("AUTH0_DOMAIN") + "/oauth/authorize"
	a.Equal(s.AuthURL, expectedAuthURL)
	a.Equal(s.AccessToken, "1234567890")
}

func Test_FetchUser(t *testing.T) {
	//t.Parallel()
	a := assert.New(t)

	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	sampleResp := `{
  		"email_verified": false,
  		"email": "test.account@userinfo.com",
  		"clientID": "q2hnj2iu...",
  		"updated_at": "2016-12-05T15:15:40.545Z",
  		"name": "test.account@userinfo.com",
  		"picture": "https://s.gravatar.com/avatar/dummy.png",
  		"user_id": "auth0|58454...",
  		"nickname": "test.account",
  		"identities": [
  		  {
      			"user_id": "58454...",
      			"provider": "auth0",
      			"connection": "Username-Password-Authentication",
      			"isSocial": false
    		}],
  		"created_at": "2016-12-05T11:16:59.640Z",
  		"sub": "auth0|58454..."
	}`

	httpmock.RegisterResponder("GET", "https://"+os.Getenv("AUTH0_DOMAIN")+"/userinfo",
		httpmock.NewStringResponder(200, sampleResp))

	p := provider()
	session, err := p.BeginAuth("test_state")
	s := session.(*auth0.Session)
	u, err := p.FetchUser(s)
	a.Nil(err)
	a.Equal(u.Email, "test.account@userinfo.com")
	a.Equal(u.UserID, "auth0|58454...")
	a.Equal(u.NickName, "test.account")
	a.Equal(u.Name, "test.account@userinfo.com")

}

func provider() *auth0.Provider {
	return auth0.New(os.Getenv("AUTH0_KEY"), os.Getenv("AUTH0_SECRET"), "/foo", os.Getenv("AUTH0_DOMAIN"))
}
<|endoftext|>


<commit_before>package parser

// ndt_meta.go contains code for processing the ndt .meta files.

import (
	"bytes"
	"encoding/json"
	"io"
	"log"
	"net"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/m-lab/etl/metrics"
	"github.com/m-lab/etl/schema"
)

// MetaFileData is the parsed info from the .meta file.
type MetaFileData struct {
	TestName    string
	DateTime    time.Time
	SummaryData []int32 // Note: this is ignored in the legacy pipeline.
	Tls         bool
	Websockets  bool

	Fields map[string]string // All of the string fields.
}

const (
	CLIENT_TO_SERVER = 0
	SERVER_TO_CLIENT = 1
)

var fieldPairs = map[string]string{
	"server IP address":       "server_ip",
	"server hostname":         "server_hostname",
	"server kernel version":   "server_kernel_version",
	"client IP address":       "client_ip",
	"client hostname":         "client_hostname",
	"client OS name":          "client_os",
	"client_browser name":     "client_browser",
	"client_application name": "client_application",

	// Some client fields are "Additional" meta data optionally provided by the client.
	// The NDT client names these fields differently than the server.
	// Other clients may provide different key names.
	"client.kernel.version": "client_kernel_version",
	"client.version":        "client_version",

	// NDT SSL added two additional meta fields to signify whether the test was
	// a websocket and/or tls test.
	"tls":        "tls",
	"websockets": "websockets",
}

func handleIP(connSpec schema.Web100ValueMap, prefix string, ipString string) {
	connSpec.SetString(prefix+"_ip", ipString)
	ip := net.ParseIP(ipString)
	if ip == nil {
		log.Printf("Failed parsing connSpec IP: %s\n", ipString)
		metrics.WarningCount.WithLabelValues(
			"ndt", "unknown", "failed parsing connSpec IP").Inc()
	} else {
		connSpec.SetString(prefix+"_ip", ip.String())
		if ip.To4() != nil {
			connSpec.SetInt64(prefix+"_af", syscall.AF_INET)
		} else if ip.To16() != nil {
			connSpec.SetInt64(prefix+"_af", syscall.AF_INET6)
		}
	}
}

func (mfd *MetaFileData) PopulateConnSpec(connSpec schema.Web100ValueMap) {
	for k, v := range fieldPairs {
		s, ok := mfd.Fields[k]
		if ok {
			if s != "" {
				connSpec.SetString(v, s)
			}
		} else {
			log.Printf("Missing field: %s %v\n", k, v)
		}
	}
	// Only set the value for tls & websocket if the field is present.
	if s, ok := mfd.Fields["tls"]; ok {
		if s != "" {
			connSpec.SetBool("tls", mfd.Tls)
		}
	}
	if s, ok := mfd.Fields["websockets"]; ok {
		if s != "" {
			connSpec.SetBool("websockets", mfd.Websockets)
		}
	}
	s, ok := mfd.Fields["server_ip"]
	// TODO - extract function for this stanza
	if ok {
		if s != "" {
			handleIP(connSpec, "server", s.(string))
		}
	} else {
		metrics.WarningCount.WithLabelValues(
			"table", "unknown", "missing server_ip").Inc()
	}
	s, ok = connSpec["client_ip"]
	if ok {
		if s != "" {
			handleIP(connSpec, "client", s.(string))
		}
	} else {
		log.Println("client_ip missing from .meta")
		metrics.WarningCount.WithLabelValues(
			"table", "unknown", "missing client_ip").Inc()
	}
}

// createMetaFileData uses the key:value pairs to populate the interpreted fields.
// TODO(dev) - more unit tests?
// TODO(dev) - move to separate file - meta.go
func createMetaFileData(testName string, fields map[string]string) (*MetaFileData, error) {
	var data MetaFileData
	data.TestName = testName
	data.Fields = make(map[string]string, 20)
	for k, v := range fields {
		var err error
		v = strings.TrimSpace(v)
		switch k {
		case "Date/Time":
			data.DateTime, err = time.Parse(
				"20060102T15:04:05.999999999Z", v)
		case "tls":
			data.Tls, err = strconv.ParseBool(v)
			data.Fields[k] = v
		case "websockets":
			data.Websockets, err = strconv.ParseBool(v)
			data.Fields[k] = v
		case "Summary data":
			err = json.Unmarshal(
				[]byte(`{"SummaryData":[`+v+`]}`),
				&data)
		default:
			data.Fields[k] = v
		}
		if err != nil {
			return nil, err
		}
	}
	return &data, nil
}

// parseMetaFile converts the raw content into key value map.
// Meta file has .meta suffix, and contains mostly key value pairs separated by ':', some with no value, e.g.
// Date/Time: 20170512T17:55:18.538553000Z
// c2s_snaplog file: 20170512T17:55:18.538553000Z_94.197.121.150.threembb.co.uk:54430.c2s_snaplog.gz
// ...
// server IP address:
// server hostname: mlab1.lhr01.measurement-lab.org
// ...
// Summary data: 0,0,2952,0,0,0,...
// * Additional data:
// tls: true
// websockets: true
//
// Notable exception is the * Additional data: line, which also parses as a key value pair, but isn't.
// TODO pass fileInfoAndData
func parseMetaFile(rawContent []byte) (map[string]string, error) {
	result := make(map[string]string, 20)

	buf := bytes.NewBuffer(rawContent)
	var err error
	var line string
	for {
		line, err = buf.ReadString('\n')
		if err != nil {
			break
		}
		kv := strings.SplitN(line, ":", 2)
		if len(kv) != 2 {
			// Does this trigger for " * Additional data:"?
			// TODO Error message or counter?
			continue
		}
		// TODO(dev) - filter out binary data that sometimes shows up in corrupted files.
		result[kv[0]] = kv[1]
	}
	if err != io.EOF {
		// TODO Error message or counter?
		return nil, err
	}
	return result, nil
}

// ProcessMeta parses the .meta file.
// TODO(dev) - add unit tests
// TODO(prod) - For tests that include a meta file, should respect the test filenames.
// See ndt_meta_log_parser_lib.cc
func ProcessMetaFile(tableName string, suffix string, testName string, content []byte) *MetaFileData {
	// Create a map from the metafile raw content
	metamap, err := parseMetaFile(content)
	if err != nil {
		metrics.TestCount.WithLabelValues(
			tableName, "meta", "error").Inc()
		log.Println("meta processing error: " + err.Error())
		return nil
	}
	metaFile, err := createMetaFileData(testName, metamap)
	if err != nil {
		metrics.TestCount.WithLabelValues(
			tableName, "meta", "error").Inc()
		log.Println("meta processing error: " + err.Error())
		return nil
	}

	metrics.TestCount.WithLabelValues(
		tableName, "meta", "ok").Inc()
	return metaFile
}
<commit_msg>Fix rebase<commit_after>package parser

// ndt_meta.go contains code for processing the ndt .meta files.

import (
	"bytes"
	"encoding/json"
	"io"
	"log"
	"net"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/m-lab/etl/metrics"
	"github.com/m-lab/etl/schema"
)

// MetaFileData is the parsed info from the .meta file.
type MetaFileData struct {
	TestName    string
	DateTime    time.Time
	SummaryData []int32 // Note: this is ignored in the legacy pipeline.
	Tls         bool
	Websockets  bool

	Fields map[string]string // All of the string fields.
}

const (
	CLIENT_TO_SERVER = 0
	SERVER_TO_CLIENT = 1
)

var fieldPairs = map[string]string{
	"server IP address":       "server_ip",
	"server hostname":         "server_hostname",
	"server kernel version":   "server_kernel_version",
	"client IP address":       "client_ip",
	"client hostname":         "client_hostname",
	"client OS name":          "client_os",
	"client_browser name":     "client_browser",
	"client_application name": "client_application",

	// Some client fields are "Additional" meta data optionally provided by the client.
	// The NDT client names these fields differently than the server.
	// Other clients may provide different key names.
	"client.kernel.version": "client_kernel_version",
	"client.version":        "client_version",

	// NDT SSL added two additional meta fields to signify whether the test was
	// a websocket and/or tls test.
	"tls":        "tls",
	"websockets": "websockets",
}

func handleIP(connSpec schema.Web100ValueMap, prefix string, ipString string) {
	connSpec.SetString(prefix+"_ip", ipString)
	ip := net.ParseIP(ipString)
	if ip == nil {
		log.Printf("Failed parsing connSpec IP: %s\n", ipString)
		metrics.WarningCount.WithLabelValues(
			"ndt", "unknown", "failed parsing connSpec IP").Inc()
	} else {
		connSpec.SetString(prefix+"_ip", ip.String())
		if ip.To4() != nil {
			connSpec.SetInt64(prefix+"_af", syscall.AF_INET)
		} else if ip.To16() != nil {
			connSpec.SetInt64(prefix+"_af", syscall.AF_INET6)
		}
	}
}

func (mfd *MetaFileData) PopulateConnSpec(connSpec schema.Web100ValueMap) {
	for k, v := range fieldPairs {
		s, ok := mfd.Fields[k]
		if ok {
			if s != "" {
				connSpec.SetString(v, s)
			}
		} else {
			log.Printf("Missing field: %s %v\n", k, v)
		}
	}
	// Only set the value for tls & websocket if the field is present.
	if s, ok := mfd.Fields["tls"]; ok {
		if s != "" {
			connSpec.SetBool("tls", mfd.Tls)
		}
	}
	if s, ok := mfd.Fields["websockets"]; ok {
		if s != "" {
			connSpec.SetBool("websockets", mfd.Websockets)
		}
	}
	s, ok := connSpec["server_ip"]
	// TODO - extract function for this stanza
	if ok {
		if s != "" {
			handleIP(connSpec, "server", s.(string))
		}
	} else {
		metrics.WarningCount.WithLabelValues(
			"ndt", "unknown", "missing server_ip").Inc()
	}
	s, ok = connSpec["client_ip"]
	if ok {
		if s != "" {
			handleIP(connSpec, "client", s.(string))
		}
	} else {
		log.Println("client_ip missing from .meta")
		metrics.WarningCount.WithLabelValues(
			"ndt", "unknown", "missing client_ip").Inc()
	}
}

// createMetaFileData uses the key:value pairs to populate the interpreted fields.
// TODO(dev) - more unit tests?
// TODO(dev) - move to separate file - meta.go
func createMetaFileData(testName string, fields map[string]string) (*MetaFileData, error) {
	var data MetaFileData
	data.TestName = testName
	data.Fields = make(map[string]string, 20)
	for k, v := range fields {
		var err error
		v = strings.TrimSpace(v)
		switch k {
		case "Date/Time":
			data.DateTime, err = time.Parse(
				"20060102T15:04:05.999999999Z", v)
		case "tls":
			data.Tls, err = strconv.ParseBool(v)
			data.Fields[k] = v
		case "websockets":
			data.Websockets, err = strconv.ParseBool(v)
			data.Fields[k] = v
		case "Summary data":
			err = json.Unmarshal(
				[]byte(`{"SummaryData":[`+v+`]}`),
				&data)
		default:
			data.Fields[k] = v
		}
		if err != nil {
			return nil, err
		}
	}
	return &data, nil
}

// parseMetaFile converts the raw content into key value map.
// Meta file has .meta suffix, and contains mostly key value pairs separated by ':', some with no value, e.g.
// Date/Time: 20170512T17:55:18.538553000Z
// c2s_snaplog file: 20170512T17:55:18.538553000Z_94.197.121.150.threembb.co.uk:54430.c2s_snaplog.gz
// ...
// server IP address:
// server hostname: mlab1.lhr01.measurement-lab.org
// ...
// Summary data: 0,0,2952,0,0,0,...
// * Additional data:
// tls: true
// websockets: true
//
// Notable exception is the * Additional data: line, which also parses as a key value pair, but isn't.
// TODO pass fileInfoAndData
func parseMetaFile(rawContent []byte) (map[string]string, error) {
	result := make(map[string]string, 20)

	buf := bytes.NewBuffer(rawContent)
	var err error
	var line string
	for {
		line, err = buf.ReadString('\n')
		if err != nil {
			break
		}
		kv := strings.SplitN(line, ":", 2)
		if len(kv) != 2 {
			// Does this trigger for " * Additional data:"?
			// TODO Error message or counter?
			continue
		}
		// TODO(dev) - filter out binary data that sometimes shows up in corrupted files.
		result[kv[0]] = kv[1]
	}
	if err != io.EOF {
		// TODO Error message or counter?
		return nil, err
	}
	return result, nil
}

// ProcessMeta parses the .meta file.
// TODO(dev) - add unit tests
// TODO(prod) - For tests that include a meta file, should respect the test filenames.
// See ndt_meta_log_parser_lib.cc
func ProcessMetaFile(tableName string, suffix string, testName string, content []byte) *MetaFileData {
	// Create a map from the metafile raw content
	metamap, err := parseMetaFile(content)
	if err != nil {
		metrics.TestCount.WithLabelValues(
			tableName, "meta", "error").Inc()
		log.Println("meta processing error: " + err.Error())
		return nil
	}
	metaFile, err := createMetaFileData(testName, metamap)
	if err != nil {
		metrics.TestCount.WithLabelValues(
			tableName, "meta", "error").Inc()
		log.Println("meta processing error: " + err.Error())
		return nil
	}

	metrics.TestCount.WithLabelValues(
		tableName, "meta", "ok").Inc()
	return metaFile
}
<|endoftext|>


<commit_before>package auth

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/micro/go-micro/v2/metadata"

	"github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/api/resolver/path"
	"github.com/micro/go-micro/v2/auth"
	"github.com/micro/go-micro/v2/logger"
)

// CombinedAuthHandler wraps a server and authenticates requests
func CombinedAuthHandler(namespace string, r resolver.Resolver, h http.Handler) http.Handler {
	if r == nil {
		r = path.NewResolver()
	}
	if len(namespace) == 0 {
		namespace = "go.micro"
	}

	return authHandler{
		handler:   h,
		resolver:  r,
		auth:      auth.DefaultAuth,
		namespace: namespace,
	}
}

type authHandler struct {
	handler   http.Handler
	auth      auth.Auth
	resolver  resolver.Resolver
	namespace string
}

func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Determine the namespace
	namespace, err := namespaceFromRequest(req)
	if err != nil {
		logger.Error(err)
		namespace = auth.DefaultNamespace
	}

	// Set the namespace in the header
	req.Header.Set(auth.NamespaceKey, namespace)

	// Extract the token from the request
	var token string
	if header := req.Header.Get("Authorization"); len(header) > 0 {
		// Extract the auth token from the request
		if strings.HasPrefix(header, auth.BearerScheme) {
			token = header[len(auth.BearerScheme):]
		}
	} else {
		// Get the token out the cookies if not provided in headers
		if c, err := req.Cookie("micro-token"); err == nil && c != nil {
			token = strings.TrimPrefix(c.Value, auth.TokenCookieName+"=")
			req.Header.Set("Authorization", auth.BearerScheme+token)
		}
	}

	// Get the account using the token, fallback to a blank account
	// since some endpoints can be unauthenticated, so the lack of an
	// account doesn't necesserially mean a forbidden request
	acc, err := h.auth.Inspect(token)
	if err != nil {
		acc = &auth.Account{Namespace: namespace}
	}

	// Check the accounts namespace matches the namespace we're operating
	// within. If not forbid the request and log the occurance.
	if acc.Namespace != namespace {
		logger.Warnf("Cross namespace request forbidden: account %v (%v) requested access to %v in the %v namespace", acc.ID, acc.Namespace, req.URL.Path, namespace)
		w.WriteHeader(http.StatusForbidden)
	}

	// Determine the name of the service being requested
	endpoint, err := h.resolver.Resolve(req)
	if err == resolver.ErrInvalidPath || err == resolver.ErrNotFound {
		// a file not served by the resolver has been requested (e.g. favicon.ico)
		endpoint = &resolver.Endpoint{Path: req.URL.Path}
	} else if err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	} else if err == nil {
		// set the endpoint in the context so it can be used to resolve
		// the request later
		if bytes, err := json.Marshal(endpoint); err == nil {
			ctx := metadata.Set(req.Context(), "endpoint", string(bytes))
			*req = *req.WithContext(ctx)
		}
	}

	// construct the resource name, e.g. home => go.micro.web.home
	resName := h.namespace
	if len(endpoint.Name) > 0 {
		resName = resName + "." + endpoint.Name
	}

	// determine the resource path. there is an inconsistency in how resolvers
	// use method, some use it as Users.ReadUser (the rpc method), and others
	// use it as the HTTP method, e.g GET. TODO: Refactor this to make it consistent.
	resEndpoint := endpoint.Path
	if len(endpoint.Path) == 0 {
		resEndpoint = endpoint.Method
	}

	// Perform the verification check to see if the account has access to
	// the resource they're requesting
	res := &auth.Resource{Type: "service", Name: resName, Endpoint: resEndpoint, Namespace: namespace}
	if err := h.auth.Verify(acc, res); err == nil {
		// The account has the necessary permissions to access the resource
		h.handler.ServeHTTP(w, req)
		return
	}

	// The account is set, but they don't have enough permissions, hence
	// we return a forbidden error.
	if len(acc.ID) > 0 {
		w.WriteHeader(http.StatusForbidden)
		return
	}

	// If there is no auth login url set, 401
	loginURL := h.auth.Options().LoginURL
	if loginURL == "" {
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	// Redirect to the login path
	params := url.Values{"redirect_to": {req.URL.Path}}
	loginWithRedirect := fmt.Sprintf("%v?%v", loginURL, params.Encode())
	http.Redirect(w, req, loginWithRedirect, http.StatusTemporaryRedirect)
}

func namespaceFromRequest(req *http.Request) (string, error) {
	// needed to tmp debug host in prod. will be removed.
	logger.Infof("Host is '%v'; URL Host is '%v'; URL Hostname is '%v'", req.Host, req.URL.Host, req.URL.Hostname())

	// determine the host, e.g. dev.micro.mu:8080
	host := req.URL.Hostname()
	if len(host) == 0 {
		// fallback to req.Host
		host, _, _ = net.SplitHostPort(req.Host)
	}

	// check for an ip address
	if net.ParseIP(host) != nil {
		return auth.DefaultNamespace, nil
	}

	// check for dev enviroment
	if host == "localhost" || host == "127.0.0.1" {
		return auth.DefaultNamespace, nil
	}

	// if host is not a subdomain, deturn default namespace
	comps := strings.Split(host, ".")
	if len(comps) != 3 {
		return auth.DefaultNamespace, nil
	}

	// check for the micro.mu domain
	domain := fmt.Sprintf("%v.%v", comps[1], comps[2])
	if domain == "micro.mu" {
		return auth.DefaultNamespace, nil
	}

	// return the subdomain as the host
	return comps[0], nil
}
<commit_msg>Set value in context, not metadata<commit_after>package auth

import (
	"context"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/api/resolver/path"
	"github.com/micro/go-micro/v2/auth"
	"github.com/micro/go-micro/v2/logger"
)

// CombinedAuthHandler wraps a server and authenticates requests
func CombinedAuthHandler(namespace string, r resolver.Resolver, h http.Handler) http.Handler {
	if r == nil {
		r = path.NewResolver()
	}
	if len(namespace) == 0 {
		namespace = "go.micro"
	}

	return authHandler{
		handler:   h,
		resolver:  r,
		auth:      auth.DefaultAuth,
		namespace: namespace,
	}
}

type authHandler struct {
	handler   http.Handler
	auth      auth.Auth
	resolver  resolver.Resolver
	namespace string
}

func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Determine the namespace
	namespace, err := namespaceFromRequest(req)
	if err != nil {
		logger.Error(err)
		namespace = auth.DefaultNamespace
	}

	// Set the namespace in the header
	req.Header.Set(auth.NamespaceKey, namespace)

	// Extract the token from the request
	var token string
	if header := req.Header.Get("Authorization"); len(header) > 0 {
		// Extract the auth token from the request
		if strings.HasPrefix(header, auth.BearerScheme) {
			token = header[len(auth.BearerScheme):]
		}
	} else {
		// Get the token out the cookies if not provided in headers
		if c, err := req.Cookie("micro-token"); err == nil && c != nil {
			token = strings.TrimPrefix(c.Value, auth.TokenCookieName+"=")
			req.Header.Set("Authorization", auth.BearerScheme+token)
		}
	}

	// Get the account using the token, fallback to a blank account
	// since some endpoints can be unauthenticated, so the lack of an
	// account doesn't necesserially mean a forbidden request
	acc, err := h.auth.Inspect(token)
	if err != nil {
		acc = &auth.Account{Namespace: namespace}
	}

	// Check the accounts namespace matches the namespace we're operating
	// within. If not forbid the request and log the occurance.
	if acc.Namespace != namespace {
		logger.Warnf("Cross namespace request forbidden: account %v (%v) requested access to %v in the %v namespace", acc.ID, acc.Namespace, req.URL.Path, namespace)
		w.WriteHeader(http.StatusForbidden)
	}

	// Determine the name of the service being requested
	endpoint, err := h.resolver.Resolve(req)
	if err == resolver.ErrInvalidPath || err == resolver.ErrNotFound {
		// a file not served by the resolver has been requested (e.g. favicon.ico)
		endpoint = &resolver.Endpoint{Path: req.URL.Path}
	} else if err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	} else if err == nil {
		// set the endpoint in the context so it can be used to resolve
		// the request later
		ctx := context.WithValue(req.Context(), resolver.Endpoint{}, endpoint)
		*req = *req.WithContext(ctx)
	}

	// construct the resource name, e.g. home => go.micro.web.home
	resName := h.namespace
	if len(endpoint.Name) > 0 {
		resName = resName + "." + endpoint.Name
	}

	// determine the resource path. there is an inconsistency in how resolvers
	// use method, some use it as Users.ReadUser (the rpc method), and others
	// use it as the HTTP method, e.g GET. TODO: Refactor this to make it consistent.
	resEndpoint := endpoint.Path
	if len(endpoint.Path) == 0 {
		resEndpoint = endpoint.Method
	}

	// Perform the verification check to see if the account has access to
	// the resource they're requesting
	res := &auth.Resource{Type: "service", Name: resName, Endpoint: resEndpoint, Namespace: namespace}
	if err := h.auth.Verify(acc, res); err == nil {
		// The account has the necessary permissions to access the resource
		h.handler.ServeHTTP(w, req)
		return
	}

	// The account is set, but they don't have enough permissions, hence
	// we return a forbidden error.
	if len(acc.ID) > 0 {
		w.WriteHeader(http.StatusForbidden)
		return
	}

	// If there is no auth login url set, 401
	loginURL := h.auth.Options().LoginURL
	if loginURL == "" {
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	// Redirect to the login path
	params := url.Values{"redirect_to": {req.URL.Path}}
	loginWithRedirect := fmt.Sprintf("%v?%v", loginURL, params.Encode())
	http.Redirect(w, req, loginWithRedirect, http.StatusTemporaryRedirect)
}

func namespaceFromRequest(req *http.Request) (string, error) {
	// needed to tmp debug host in prod. will be removed.
	logger.Infof("Host is '%v'; URL Host is '%v'; URL Hostname is '%v'", req.Host, req.URL.Host, req.URL.Hostname())

	// determine the host, e.g. dev.micro.mu:8080
	host := req.URL.Hostname()
	if len(host) == 0 {
		// fallback to req.Host
		host, _, _ = net.SplitHostPort(req.Host)
	}

	// check for an ip address
	if net.ParseIP(host) != nil {
		return auth.DefaultNamespace, nil
	}

	// check for dev enviroment
	if host == "localhost" || host == "127.0.0.1" {
		return auth.DefaultNamespace, nil
	}

	// if host is not a subdomain, deturn default namespace
	comps := strings.Split(host, ".")
	if len(comps) != 3 {
		return auth.DefaultNamespace, nil
	}

	// check for the micro.mu domain
	domain := fmt.Sprintf("%v.%v", comps[1], comps[2])
	if domain == "micro.mu" {
		return auth.DefaultNamespace, nil
	}

	// return the subdomain as the host
	return comps[0], nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 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 v1

import (
	"fmt"
	"strconv"
	"strings"

	"k8s.io/apimachinery/pkg/api/resource"
	"k8s.io/apimachinery/pkg/conversion"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/intstr"
)

func AddConversionFuncs(scheme *runtime.Scheme) error {
	return scheme.AddConversionFuncs(
		Convert_v1_TypeMeta_To_v1_TypeMeta,

		Convert_unversioned_ListMeta_To_unversioned_ListMeta,

		Convert_intstr_IntOrString_To_intstr_IntOrString,

		Convert_unversioned_Time_To_unversioned_Time,

		Convert_Pointer_v1_Duration_To_v1_Duration,
		Convert_v1_Duration_To_Pointer_v1_Duration,

		Convert_Slice_string_To_unversioned_Time,

		Convert_resource_Quantity_To_resource_Quantity,

		Convert_string_To_labels_Selector,
		Convert_labels_Selector_To_string,

		Convert_string_To_fields_Selector,
		Convert_fields_Selector_To_string,

		Convert_Pointer_bool_To_bool,
		Convert_bool_To_Pointer_bool,

		Convert_Pointer_string_To_string,
		Convert_string_To_Pointer_string,

		Convert_Pointer_int64_To_int,
		Convert_int_To_Pointer_int64,

		Convert_Pointer_int32_To_int32,
		Convert_int32_To_Pointer_int32,

		Convert_Pointer_float64_To_float64,
		Convert_float64_To_Pointer_float64,

		Convert_map_to_unversioned_LabelSelector,
		Convert_unversioned_LabelSelector_to_map,

		Convert_Slice_string_To_Slice_int32,
	)
}

func Convert_Pointer_float64_To_float64(in **float64, out *float64, s conversion.Scope) error {
	if *in == nil {
		*out = 0
		return nil
	}
	*out = float64(**in)
	return nil
}

func Convert_float64_To_Pointer_float64(in *float64, out **float64, s conversion.Scope) error {
	temp := float64(*in)
	*out = &temp
	return nil
}

func Convert_Pointer_int32_To_int32(in **int32, out *int32, s conversion.Scope) error {
	if *in == nil {
		*out = 0
		return nil
	}
	*out = int32(**in)
	return nil
}

func Convert_int32_To_Pointer_int32(in *int32, out **int32, s conversion.Scope) error {
	temp := int32(*in)
	*out = &temp
	return nil
}

func Convert_Pointer_int64_To_int(in **int64, out *int, s conversion.Scope) error {
	if *in == nil {
		*out = 0
		return nil
	}
	*out = int(**in)
	return nil
}

func Convert_int_To_Pointer_int64(in *int, out **int64, s conversion.Scope) error {
	temp := int64(*in)
	*out = &temp
	return nil
}

func Convert_Pointer_string_To_string(in **string, out *string, s conversion.Scope) error {
	if *in == nil {
		*out = ""
		return nil
	}
	*out = **in
	return nil
}

func Convert_string_To_Pointer_string(in *string, out **string, s conversion.Scope) error {
	if in == nil {
		stringVar := ""
		*out = &stringVar
		return nil
	}
	*out = in
	return nil
}

func Convert_Pointer_bool_To_bool(in **bool, out *bool, s conversion.Scope) error {
	if *in == nil {
		*out = false
		return nil
	}
	*out = **in
	return nil
}

func Convert_bool_To_Pointer_bool(in *bool, out **bool, s conversion.Scope) error {
	if in == nil {
		boolVar := false
		*out = &boolVar
		return nil
	}
	*out = in
	return nil
}

// +k8s:conversion-fn=drop
func Convert_v1_TypeMeta_To_v1_TypeMeta(in, out *TypeMeta, s conversion.Scope) error {
	// These values are explicitly not copied
	//out.APIVersion = in.APIVersion
	//out.Kind = in.Kind
	return nil
}

// +k8s:conversion-fn=copy-only
func Convert_unversioned_ListMeta_To_unversioned_ListMeta(in, out *ListMeta, s conversion.Scope) error {
	*out = *in
	return nil
}

// +k8s:conversion-fn=copy-only
func Convert_intstr_IntOrString_To_intstr_IntOrString(in, out *intstr.IntOrString, s conversion.Scope) error {
	*out = *in
	return nil
}

// +k8s:conversion-fn=copy-only
func Convert_unversioned_Time_To_unversioned_Time(in *Time, out *Time, s conversion.Scope) error {
	// Cannot deep copy these, because time.Time has unexported fields.
	*out = *in
	return nil
}

func Convert_Pointer_v1_Duration_To_v1_Duration(in **Duration, out *Duration, s conversion.Scope) error {
	if *in == nil {
		*out = Duration{} // zero duration
		return nil
	}
	*out = **in // copy
	return nil
}

func Convert_v1_Duration_To_Pointer_v1_Duration(in *Duration, out **Duration, s conversion.Scope) error {
	temp := *in //copy
	*out = &temp
	return nil
}

// Convert_Slice_string_To_unversioned_Time allows converting a URL query parameter value
func Convert_Slice_string_To_unversioned_Time(input *[]string, out *Time, s conversion.Scope) error {
	str := ""
	if len(*input) > 0 {
		str = (*input)[0]
	}
	return out.UnmarshalQueryParameter(str)
}

func Convert_string_To_labels_Selector(in *string, out *labels.Selector, s conversion.Scope) error {
	selector, err := labels.Parse(*in)
	if err != nil {
		return err
	}
	*out = selector
	return nil
}

func Convert_string_To_fields_Selector(in *string, out *fields.Selector, s conversion.Scope) error {
	selector, err := fields.ParseSelector(*in)
	if err != nil {
		return err
	}
	*out = selector
	return nil
}

func Convert_labels_Selector_To_string(in *labels.Selector, out *string, s conversion.Scope) error {
	if *in == nil {
		return nil
	}
	*out = (*in).String()
	return nil
}

func Convert_fields_Selector_To_string(in *fields.Selector, out *string, s conversion.Scope) error {
	if *in == nil {
		return nil
	}
	*out = (*in).String()
	return nil
}

// +k8s:conversion-fn=copy-only
func Convert_resource_Quantity_To_resource_Quantity(in *resource.Quantity, out *resource.Quantity, s conversion.Scope) error {
	*out = *in
	return nil
}

func Convert_map_to_unversioned_LabelSelector(in *map[string]string, out *LabelSelector, s conversion.Scope) error {
	if in == nil {
		return nil
	}
	out = new(LabelSelector)
	for labelKey, labelValue := range *in {
		AddLabelToSelector(out, labelKey, labelValue)
	}
	return nil
}

func Convert_unversioned_LabelSelector_to_map(in *LabelSelector, out *map[string]string, s conversion.Scope) error {
	var err error
	*out, err = LabelSelectorAsMap(in)
	return err
}

// Convert_Slice_string_To_Slice_int32 converts multiple query parameters or
// a single query parameter with a comma delimited value to multiple int32.
// This is used for port forwarding which needs the ports as int32.
func Convert_Slice_string_To_Slice_int32(in *[]string, out *[]int32, s conversion.Scope) error {
	for _, s := range *in {
		for _, v := range strings.Split(s, ",") {
			x, err := strconv.ParseUint(v, 10, 16)
			if err != nil {
				return fmt.Errorf("cannot convert to []int32: %v", err)
			}
			*out = append(*out, int32(x))
		}
	}
	return nil
}
<commit_msg>Fix loss of selector during RC/RS conversion.<commit_after>/*
Copyright 2014 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 v1

import (
	"fmt"
	"strconv"
	"strings"

	"k8s.io/apimachinery/pkg/api/resource"
	"k8s.io/apimachinery/pkg/conversion"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/intstr"
)

func AddConversionFuncs(scheme *runtime.Scheme) error {
	return scheme.AddConversionFuncs(
		Convert_v1_TypeMeta_To_v1_TypeMeta,

		Convert_unversioned_ListMeta_To_unversioned_ListMeta,

		Convert_intstr_IntOrString_To_intstr_IntOrString,

		Convert_unversioned_Time_To_unversioned_Time,

		Convert_Pointer_v1_Duration_To_v1_Duration,
		Convert_v1_Duration_To_Pointer_v1_Duration,

		Convert_Slice_string_To_unversioned_Time,

		Convert_resource_Quantity_To_resource_Quantity,

		Convert_string_To_labels_Selector,
		Convert_labels_Selector_To_string,

		Convert_string_To_fields_Selector,
		Convert_fields_Selector_To_string,

		Convert_Pointer_bool_To_bool,
		Convert_bool_To_Pointer_bool,

		Convert_Pointer_string_To_string,
		Convert_string_To_Pointer_string,

		Convert_Pointer_int64_To_int,
		Convert_int_To_Pointer_int64,

		Convert_Pointer_int32_To_int32,
		Convert_int32_To_Pointer_int32,

		Convert_Pointer_float64_To_float64,
		Convert_float64_To_Pointer_float64,

		Convert_map_to_unversioned_LabelSelector,
		Convert_unversioned_LabelSelector_to_map,

		Convert_Slice_string_To_Slice_int32,
	)
}

func Convert_Pointer_float64_To_float64(in **float64, out *float64, s conversion.Scope) error {
	if *in == nil {
		*out = 0
		return nil
	}
	*out = float64(**in)
	return nil
}

func Convert_float64_To_Pointer_float64(in *float64, out **float64, s conversion.Scope) error {
	temp := float64(*in)
	*out = &temp
	return nil
}

func Convert_Pointer_int32_To_int32(in **int32, out *int32, s conversion.Scope) error {
	if *in == nil {
		*out = 0
		return nil
	}
	*out = int32(**in)
	return nil
}

func Convert_int32_To_Pointer_int32(in *int32, out **int32, s conversion.Scope) error {
	temp := int32(*in)
	*out = &temp
	return nil
}

func Convert_Pointer_int64_To_int(in **int64, out *int, s conversion.Scope) error {
	if *in == nil {
		*out = 0
		return nil
	}
	*out = int(**in)
	return nil
}

func Convert_int_To_Pointer_int64(in *int, out **int64, s conversion.Scope) error {
	temp := int64(*in)
	*out = &temp
	return nil
}

func Convert_Pointer_string_To_string(in **string, out *string, s conversion.Scope) error {
	if *in == nil {
		*out = ""
		return nil
	}
	*out = **in
	return nil
}

func Convert_string_To_Pointer_string(in *string, out **string, s conversion.Scope) error {
	if in == nil {
		stringVar := ""
		*out = &stringVar
		return nil
	}
	*out = in
	return nil
}

func Convert_Pointer_bool_To_bool(in **bool, out *bool, s conversion.Scope) error {
	if *in == nil {
		*out = false
		return nil
	}
	*out = **in
	return nil
}

func Convert_bool_To_Pointer_bool(in *bool, out **bool, s conversion.Scope) error {
	if in == nil {
		boolVar := false
		*out = &boolVar
		return nil
	}
	*out = in
	return nil
}

// +k8s:conversion-fn=drop
func Convert_v1_TypeMeta_To_v1_TypeMeta(in, out *TypeMeta, s conversion.Scope) error {
	// These values are explicitly not copied
	//out.APIVersion = in.APIVersion
	//out.Kind = in.Kind
	return nil
}

// +k8s:conversion-fn=copy-only
func Convert_unversioned_ListMeta_To_unversioned_ListMeta(in, out *ListMeta, s conversion.Scope) error {
	*out = *in
	return nil
}

// +k8s:conversion-fn=copy-only
func Convert_intstr_IntOrString_To_intstr_IntOrString(in, out *intstr.IntOrString, s conversion.Scope) error {
	*out = *in
	return nil
}

// +k8s:conversion-fn=copy-only
func Convert_unversioned_Time_To_unversioned_Time(in *Time, out *Time, s conversion.Scope) error {
	// Cannot deep copy these, because time.Time has unexported fields.
	*out = *in
	return nil
}

func Convert_Pointer_v1_Duration_To_v1_Duration(in **Duration, out *Duration, s conversion.Scope) error {
	if *in == nil {
		*out = Duration{} // zero duration
		return nil
	}
	*out = **in // copy
	return nil
}

func Convert_v1_Duration_To_Pointer_v1_Duration(in *Duration, out **Duration, s conversion.Scope) error {
	temp := *in //copy
	*out = &temp
	return nil
}

// Convert_Slice_string_To_unversioned_Time allows converting a URL query parameter value
func Convert_Slice_string_To_unversioned_Time(input *[]string, out *Time, s conversion.Scope) error {
	str := ""
	if len(*input) > 0 {
		str = (*input)[0]
	}
	return out.UnmarshalQueryParameter(str)
}

func Convert_string_To_labels_Selector(in *string, out *labels.Selector, s conversion.Scope) error {
	selector, err := labels.Parse(*in)
	if err != nil {
		return err
	}
	*out = selector
	return nil
}

func Convert_string_To_fields_Selector(in *string, out *fields.Selector, s conversion.Scope) error {
	selector, err := fields.ParseSelector(*in)
	if err != nil {
		return err
	}
	*out = selector
	return nil
}

func Convert_labels_Selector_To_string(in *labels.Selector, out *string, s conversion.Scope) error {
	if *in == nil {
		return nil
	}
	*out = (*in).String()
	return nil
}

func Convert_fields_Selector_To_string(in *fields.Selector, out *string, s conversion.Scope) error {
	if *in == nil {
		return nil
	}
	*out = (*in).String()
	return nil
}

// +k8s:conversion-fn=copy-only
func Convert_resource_Quantity_To_resource_Quantity(in *resource.Quantity, out *resource.Quantity, s conversion.Scope) error {
	*out = *in
	return nil
}

func Convert_map_to_unversioned_LabelSelector(in *map[string]string, out *LabelSelector, s conversion.Scope) error {
	if in == nil {
		return nil
	}
	for labelKey, labelValue := range *in {
		AddLabelToSelector(out, labelKey, labelValue)
	}
	return nil
}

func Convert_unversioned_LabelSelector_to_map(in *LabelSelector, out *map[string]string, s conversion.Scope) error {
	var err error
	*out, err = LabelSelectorAsMap(in)
	return err
}

// Convert_Slice_string_To_Slice_int32 converts multiple query parameters or
// a single query parameter with a comma delimited value to multiple int32.
// This is used for port forwarding which needs the ports as int32.
func Convert_Slice_string_To_Slice_int32(in *[]string, out *[]int32, s conversion.Scope) error {
	for _, s := range *in {
		for _, v := range strings.Split(s, ",") {
			x, err := strconv.ParseUint(v, 10, 16)
			if err != nil {
				return fmt.Errorf("cannot convert to []int32: %v", err)
			}
			*out = append(*out, int32(x))
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package connector

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"

	"github.com/pkg/errors"

	"github.com/datawire/dlib/dexec"
	"github.com/datawire/dlib/dgroup"
	"github.com/datawire/dlib/dlog"
	"github.com/datawire/telepresence2/rpc/v2/daemon"
)

// worker names
const (
	K8sBridgeWorker = "K8S"
	K8sSSHWorker    = "SSH"
)

// ProxyRedirPort is the port to which we redirect proxied IPs. It
// should probably eventually be configurable and/or dynamically
// chosen.
const ProxyRedirPort = "1234"

// teleproxy holds the configuration for a Teleproxy
type bridge struct {
	sshPort   int32
	namespace string
	daemon    daemon.DaemonClient
	cancel    context.CancelFunc
}

func newBridge(namespace string, daemon daemon.DaemonClient, sshPort int32) *bridge {
	return &bridge{
		namespace: namespace,
		daemon:    daemon,
		sshPort:   sshPort,
	}
}

func (br *bridge) start(c context.Context) error {
	if err := checkKubectl(c); err != nil {
		return err
	}
	c, br.cancel = context.WithCancel(c)

	g := dgroup.ParentGroup(c)
	g.Go(K8sSSHWorker, br.sshWorker)
	g.Go(K8sBridgeWorker, br.bridgeWorker)
	return nil
}

func (br *bridge) bridgeWorker(c context.Context) error {
	// setup kubernetes bridge
	dlog.Infof(c, "kubernetes namespace=%s", br.namespace)
	paths := []string{
		br.namespace + ".svc.cluster.local.",
		"svc.cluster.local.",
		"cluster.local.",
		"",
	}
	dlog.Infof(c, "Setting DNS search path: %s", paths[0])
	_, err := br.daemon.SetDnsSearchPath(c, &daemon.Paths{Paths: paths})
	if err != nil {
		if c.Err() != nil {
			err = nil
		} else {
			err = fmt.Errorf("error setting up search path: %v", err)
		}
	}
	return err
}

func (br *bridge) sshWorker(c context.Context) error {
	// XXX: probably need some kind of keepalive check for ssh, first
	// curl after wakeup seems to trigger detection of death
	ssh := dexec.CommandContext(c, "ssh",

		"-F", "none", // don't load the user's config file

		// connection settings
		"-C", // compression
		"-oConnectTimeout=5",
		"-oStrictHostKeyChecking=no",     // don't bother checking the host key...
		"-oUserKnownHostsFile=/dev/null", // and since we're not checking it, don't bother remembering it either

		// port-forward settings
		"-N", // no remote command; just connect and forward ports
		"-oExitOnForwardFailure=yes",
		"-D", "localhost:1080",

		// where to connect to
		"-p", strconv.Itoa(int(br.sshPort)),
		"telepresence@localhost",
	)
	err := ssh.Run()
	if err != nil && c.Err() != nil {
		err = nil
	}
	return err
}

const kubectlErr = "kubectl version 1.10 or greater is required"

func checkKubectl(c context.Context) error {
	output, err := dexec.CommandContext(c, "kubectl", "version", "--client", "-o", "json").Output()
	if err != nil {
		return errors.Wrap(err, kubectlErr)
	}

	var info struct {
		ClientVersion struct {
			Major string
			Minor string
		}
	}

	if err = json.Unmarshal(output, &info); err != nil {
		return errors.Wrap(err, kubectlErr)
	}

	major, err := strconv.Atoi(info.ClientVersion.Major)
	if err != nil {
		return errors.Wrap(err, kubectlErr)
	}
	minor, err := strconv.Atoi(info.ClientVersion.Minor)
	if err != nil {
		return errors.Wrap(err, kubectlErr)
	}

	if major != 1 || minor < 10 {
		return errors.Errorf("%s (found %d.%d)", kubectlErr, major, minor)
	}
	return nil
}

// check checks the status of teleproxy bridge by doing the equivalent of
//  curl http://traffic-manager.svc:8022.
// Note there is no namespace specified, as we are checking for bridge status in the
// current namespace.
func (br *bridge) check(c context.Context) bool {
	address := fmt.Sprintf("localhost:%d", br.sshPort)
	conn, err := net.DialTimeout("tcp", address, 15*time.Second)
	if err != nil {
		dlog.Errorf(c, "fail to establish tcp connection to %s: %v", address, err)
		return false
	}
	defer conn.Close()

	msg, _, err := bufio.NewReader(conn).ReadLine()
	if err != nil {
		dlog.Errorf(c, "tcp read: %v", err)
		return false
	}
	if !strings.Contains(string(msg), "SSH") {
		dlog.Errorf(c, "expected SSH prompt, got: %v", string(msg))
		return false
	}
	return true
}
<commit_msg>Better kubectl client parsing<commit_after>package connector

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"

	"github.com/blang/semver"
	"github.com/pkg/errors"

	"github.com/datawire/dlib/dexec"
	"github.com/datawire/dlib/dgroup"
	"github.com/datawire/dlib/dlog"
	"github.com/datawire/telepresence2/rpc/v2/daemon"
)

// worker names
const (
	K8sBridgeWorker = "K8S"
	K8sSSHWorker    = "SSH"
)

// ProxyRedirPort is the port to which we redirect proxied IPs. It
// should probably eventually be configurable and/or dynamically
// chosen.
const ProxyRedirPort = "1234"

// teleproxy holds the configuration for a Teleproxy
type bridge struct {
	sshPort   int32
	namespace string
	daemon    daemon.DaemonClient
	cancel    context.CancelFunc
}

func newBridge(namespace string, daemon daemon.DaemonClient, sshPort int32) *bridge {
	return &bridge{
		namespace: namespace,
		daemon:    daemon,
		sshPort:   sshPort,
	}
}

func (br *bridge) start(c context.Context) error {
	if err := checkKubectl(c); err != nil {
		return err
	}
	c, br.cancel = context.WithCancel(c)

	g := dgroup.ParentGroup(c)
	g.Go(K8sSSHWorker, br.sshWorker)
	g.Go(K8sBridgeWorker, br.bridgeWorker)
	return nil
}

func (br *bridge) bridgeWorker(c context.Context) error {
	// setup kubernetes bridge
	dlog.Infof(c, "kubernetes namespace=%s", br.namespace)
	paths := []string{
		br.namespace + ".svc.cluster.local.",
		"svc.cluster.local.",
		"cluster.local.",
		"",
	}
	dlog.Infof(c, "Setting DNS search path: %s", paths[0])
	_, err := br.daemon.SetDnsSearchPath(c, &daemon.Paths{Paths: paths})
	if err != nil {
		if c.Err() != nil {
			err = nil
		} else {
			err = fmt.Errorf("error setting up search path: %v", err)
		}
	}
	return err
}

func (br *bridge) sshWorker(c context.Context) error {
	// XXX: probably need some kind of keepalive check for ssh, first
	// curl after wakeup seems to trigger detection of death
	ssh := dexec.CommandContext(c, "ssh",

		"-F", "none", // don't load the user's config file

		// connection settings
		"-C", // compression
		"-oConnectTimeout=5",
		"-oStrictHostKeyChecking=no",     // don't bother checking the host key...
		"-oUserKnownHostsFile=/dev/null", // and since we're not checking it, don't bother remembering it either

		// port-forward settings
		"-N", // no remote command; just connect and forward ports
		"-oExitOnForwardFailure=yes",
		"-D", "localhost:1080",

		// where to connect to
		"-p", strconv.Itoa(int(br.sshPort)),
		"telepresence@localhost",
	)
	err := ssh.Run()
	if err != nil && c.Err() != nil {
		err = nil
	}
	return err
}

const kubectlErr = "kubectl version 1.10 or greater is required"

func checkKubectl(c context.Context) error {
	output, err := dexec.CommandContext(c, "kubectl", "version", "--client", "-o", "json").Output()
	if err != nil {
		return errors.Wrap(err, kubectlErr)
	}

	var info struct {
		ClientVersion struct {
			GitVersion string
		}
	}

	if err = json.Unmarshal(output, &info); err != nil {
		return errors.Wrap(err, kubectlErr)
	}

	version, err := semver.ParseTolerant(info.ClientVersion.GitVersion)
	if err != nil {
		return errors.Wrap(err, kubectlErr)
	}

	if version.Major != 1 || version.Minor < 10 {
		return errors.Errorf("%s (found %s)", kubectlErr, info.ClientVersion.GitVersion)
	}
	return nil
}

// check checks the status of teleproxy bridge by doing the equivalent of
//  curl http://traffic-manager.svc:8022.
// Note there is no namespace specified, as we are checking for bridge status in the
// current namespace.
func (br *bridge) check(c context.Context) bool {
	address := fmt.Sprintf("localhost:%d", br.sshPort)
	conn, err := net.DialTimeout("tcp", address, 15*time.Second)
	if err != nil {
		dlog.Errorf(c, "fail to establish tcp connection to %s: %v", address, err)
		return false
	}
	defer conn.Close()

	msg, _, err := bufio.NewReader(conn).ReadLine()
	if err != nil {
		dlog.Errorf(c, "tcp read: %v", err)
		return false
	}
	if !strings.Contains(string(msg), "SSH") {
		dlog.Errorf(c, "expected SSH prompt, got: %v", string(msg))
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package templates

// Readme is a default README laid down by s2i create
const Readme = `
# Creating a basic S2I builder image

## Getting started

### Files and Directories
| File                   | Required? | Description                                                  |
|------------------------|-----------|--------------------------------------------------------------|
| Dockerfile             | Yes       | Defines the base builder image                               |
| s2i/bin/assemble       | Yes       | Script that builds the application                           |
| s2i/bin/usage          | No        | Script that prints the usage of the builder                  |
| s2i/bin/run            | Yes       | Script that runs the application                             |
| s2i/bin/save-artifacts | No        | Script for incremental builds that saves the built artifacts |
| test/run               | No        | Test script for the builder image                            |
| test/test-app          | Yes       | Test application source code                                 |

#### Dockerfile
Create a *Dockerfile* that installs all of the necessary tools and libraries that are needed to build and run our application.  This file will also handle copying the s2i scripts into the created image.

#### S2I scripts

##### assemble
Create an *assemble* script that will build our application, e.g.:
- build python modules
- bundle install ruby gems
- setup application specific configuration

The script can also specify a way to restore any saved artifacts from the previous image.

##### run
Create a *run* script that will start the application.

##### save-artifacts (optional)
Create a *save-artifacts* script which allows a new build to reuse content from a previous version of the application image.

##### usage (optional)
Create a *usage* script that will print out instructions on how to use the image.

##### Make the scripts executable
Make sure that all of the scripts are executable by running *chmod +x s2i/bin/**

#### Create the builder image
The following command will create a builder image named {{.ImageName}} based on the Dockerfile that was created previously.
` +
	"```\n" +
	"docker build -t {{.ImageName}} .\n" +
	"```\n" +
	`The builder image can also be created by using the *make* command since a *Makefile* is included.

Once the image has finished building, the command *s2i usage {{.ImageName}}* will print out the help info that was defined in the *usage* script.

#### Testing the builder image
The builder image can be tested using the following commands:
` +
	"```\n" +
	"docker build -t {{.ImageName}}-candidate .\n" +
	"IMAGE_NAME={{.ImageName}}-candidate test/run\n" +
	"```\n" +
	`The builder image can also be tested by using the *make test* command since a *Makefile* is included.

#### Creating the application image
The application image combines the builder image with your applications source code, which is served using whatever application is installed via the *Dockerfile*, compiled using the *assemble* script, and run using the *run* script.
The following command will create the application image:
` +
	"```\n" +
	"s2i build test/test-app {{.ImageName}} {{.ImageName}}-app\n" +
	"---> Building and installing application from source...\n" +
	"```\n" +
	`Using the logic defined in the *assemble* script, s2i will now create an application image using the builder image as a base and including the source code from the test/test-app directory.

#### Running the application image
Running the application image is as simple as invoking the docker run command:
` +
	"```\n" +
	"docker run -d -p 8080:8080 {{.ImageName}}-app\n" +
	"```\n" +
	`The application, which consists of a simple static web page, should now be accessible at  [http://localhost:8080](http://localhost:8080).

#### Using the saved artifacts script
Rebuilding the application using the saved artifacts can be accomplished using the following command:
` +
	"```\n" +
	"s2i build --incremental=true test/test-app nginx-centos7 nginx-app\n" +
	"---> Restoring build artifacts...\n" +
	"---> Building and installing application from source...\n" +
	"```\n" +
	`This will run the *save-artifacts* script which includes the custom code to backup the currently running application source, rebuild the application image, and then re-deploy the previously saved source using the *assemble* script.
`
<commit_msg>Fix instruction in s2i create README template<commit_after>package templates

// Readme is a default README laid down by s2i create
const Readme = `
# Creating a basic S2I builder image

## Getting started

### Files and Directories
| File                   | Required? | Description                                                  |
|------------------------|-----------|--------------------------------------------------------------|
| Dockerfile             | Yes       | Defines the base builder image                               |
| s2i/bin/assemble       | Yes       | Script that builds the application                           |
| s2i/bin/usage          | No        | Script that prints the usage of the builder                  |
| s2i/bin/run            | Yes       | Script that runs the application                             |
| s2i/bin/save-artifacts | No        | Script for incremental builds that saves the built artifacts |
| test/run               | No        | Test script for the builder image                            |
| test/test-app          | Yes       | Test application source code                                 |

#### Dockerfile
Create a *Dockerfile* that installs all of the necessary tools and libraries that are needed to build and run our application.  This file will also handle copying the s2i scripts into the created image.

#### S2I scripts

##### assemble
Create an *assemble* script that will build our application, e.g.:
- build python modules
- bundle install ruby gems
- setup application specific configuration

The script can also specify a way to restore any saved artifacts from the previous image.

##### run
Create a *run* script that will start the application.

##### save-artifacts (optional)
Create a *save-artifacts* script which allows a new build to reuse content from a previous version of the application image.

##### usage (optional)
Create a *usage* script that will print out instructions on how to use the image.

##### Make the scripts executable
Make sure that all of the scripts are executable by running *chmod +x s2i/bin/**

#### Create the builder image
The following command will create a builder image named {{.ImageName}} based on the Dockerfile that was created previously.
` +
	"```\n" +
	"docker build -t {{.ImageName}} .\n" +
	"```\n" +
	`The builder image can also be created by using the *make* command since a *Makefile* is included.

Once the image has finished building, the command *s2i usage {{.ImageName}}* will print out the help info that was defined in the *usage* script.

#### Testing the builder image
The builder image can be tested using the following commands:
` +
	"```\n" +
	"docker build -t {{.ImageName}}-candidate .\n" +
	"IMAGE_NAME={{.ImageName}}-candidate test/run\n" +
	"```\n" +
	`The builder image can also be tested by using the *make test* command since a *Makefile* is included.

#### Creating the application image
The application image combines the builder image with your applications source code, which is served using whatever application is installed via the *Dockerfile*, compiled using the *assemble* script, and run using the *run* script.
The following command will create the application image:
` +
	"```\n" +
	"s2i build test/test-app {{.ImageName}} {{.ImageName}}-app\n" +
	"---> Building and installing application from source...\n" +
	"```\n" +
	`Using the logic defined in the *assemble* script, s2i will now create an application image using the builder image as a base and including the source code from the test/test-app directory.

#### Running the application image
Running the application image is as simple as invoking the docker run command:
` +
	"```\n" +
	"docker run -d -p 8080:8080 {{.ImageName}}-app\n" +
	"```\n" +
	`The application, which consists of a simple static web page, should now be accessible at  [http://localhost:8080](http://localhost:8080).

#### Using the saved artifacts script
Rebuilding the application using the saved artifacts can be accomplished using the following command:
` +
	"```\n" +
	"s2i build --incremental=true test/test-app {{.ImageName}} {{.ImageName}}-app\n" +
	"---> Restoring build artifacts...\n" +
	"---> Building and installing application from source...\n" +
	"```\n" +
	`This will run the *save-artifacts* script which includes the custom code to backup the currently running application source, rebuild the application image, and then re-deploy the previously saved source using the *assemble* script.
`
<|endoftext|>


<commit_before>package interceptor

import (
	"encoding/json"
	"log"
	"net"
	"strings"
	"sync"

	"github.com/datawire/ambassador/pkg/supervisor"

	"github.com/datawire/ambassador/internal/pkg/nat"
	rt "github.com/datawire/ambassador/internal/pkg/route"
)

type Interceptor struct {
	translator *nat.Translator
	tables     map[string]rt.Table
	tablesLock sync.RWMutex

	domains     map[string]rt.Route
	domainsLock sync.RWMutex

	search     []string
	searchLock sync.RWMutex

	work chan func(*supervisor.Process) error
}

func NewInterceptor(name string) *Interceptor {
	ret := &Interceptor{
		tables:     make(map[string]rt.Table),
		translator: nat.NewTranslator(name),
		domains:    make(map[string]rt.Route),
		search:     []string{""},
		work:       make(chan func(*supervisor.Process) error),
	}
	ret.tablesLock.Lock() // leave it locked until .Start() unlocks it
	return ret
}

func (i *Interceptor) Work(p *supervisor.Process) error {
	i.translator.Enable(p)
	i.tablesLock.Unlock()

	p.Ready()

	for {
		select {
		case <-p.Shutdown():
			i.tablesLock.Lock()
			i.translator.Disable(p)
			// leave it locked
			return nil
		case f := <-i.work:
			err := f(p)
			if err != nil {
				return err
			}
		}
	}
}

// Resolve looks up the given query in the (FIXME: somewhere), trying
// all the suffixes in the search path, and returns a Route on success
// or nil on failure. This implementation does not count the number of
// dots in the query.
func (i *Interceptor) Resolve(query string) *rt.Route {
	if !strings.HasSuffix(query, ".") {
		query += "."
	}

	const prefix = "teleproxy"
	const suffix = ".cachebust.telepresence.io." // must end with .
	const replacement = "teleproxy."             // must end with .
	if strings.HasPrefix(query, prefix) && strings.HasSuffix(query, suffix) {
		query = replacement
	}

	i.searchLock.RLock()
	defer i.searchLock.RUnlock()
	i.domainsLock.RLock()
	defer i.domainsLock.RUnlock()

	for _, suffix := range i.search {
		name := query + suffix
		value, ok := i.domains[strings.ToLower(name)]
		if ok {
			return &value
		}
	}
	return nil
}

func (i *Interceptor) Destination(conn *net.TCPConn) (string, error) {
	_, host, err := i.translator.GetOriginalDst(conn)
	return host, err
}

func (i *Interceptor) Render(table string) string {
	var obj interface{}

	if table == "" {
		var tables []rt.Table
		i.tablesLock.RLock()
		for _, t := range i.tables {
			tables = append(tables, t)
		}
		i.tablesLock.RUnlock()
		obj = tables
	} else {
		var ok bool
		i.tablesLock.RLock()
		obj, ok = i.tables[table]
		i.tablesLock.RUnlock()
		if !ok {
			return ""
		}
	}

	bytes, err := json.MarshalIndent(obj, "", "  ")
	if err != nil {
		return err.Error()
	} else {
		return string(bytes)
	}
}

func (i *Interceptor) Delete(table string) bool {
	result := make(chan bool)
	i.work <- func(p *supervisor.Process) error {
		i.tablesLock.Lock()
		defer i.tablesLock.Unlock()
		i.domainsLock.Lock()
		defer i.domainsLock.Unlock()

		var names []string
		if table == "" {
			for name := range i.tables {
				names = append(names, name)
			}
		} else if _, ok := i.tables[table]; ok {
			names = []string{table}
		} else {
			result <- false
			return nil
		}

		for _, name := range names {
			if name != "bootstrap" {
				err := i.update(p, rt.Table{Name: name})
				if err != nil {
					return err
				}
			}
		}

		result <- true
		return nil
	}

	return <-result
}

func (i *Interceptor) Update(table rt.Table) {
	result := make(chan struct{})
	i.work <- func(p *supervisor.Process) error {
		defer close(result)
		return i.update(p, table)
	}
	<-result
}

func (i *Interceptor) update(p *supervisor.Process, table rt.Table) error {
	// Make a copy of the current table
	i.tablesLock.Lock()
	oldTable, ok := i.tables[table.Name]
	oldRoutes := make(map[string]rt.Route)
	if ok {
		for _, route := range oldTable.Routes {
			oldRoutes[route.Name] = route
		}
	}
	i.tablesLock.Unlock()

	// Operate on the copy of the current table and the new table
	for _, newRoute := range table.Routes {
		oldRoute, oldRouteOk := oldRoutes[newRoute.Name]
		// A nil Route (when oldRouteOk != true) will compare
		// inequal to any valid new Route.
		if newRoute != oldRoute {
			// We're updating a route. Make sure DNS waits until the new answer
			// is ready, i.e. don't serve the old answer.
			i.domainsLock.Lock()

			// delete the old version
			if oldRouteOk {
				switch newRoute.Proto {
				case "tcp":
					i.translator.ClearTCP(p, oldRoute.Ip, oldRoute.Port)
				case "udp":
					i.translator.ClearUDP(p, oldRoute.Ip, oldRoute.Port)
				default:
					log.Printf("INT: unrecognized protocol: %v", newRoute)
				}
			}
			// and add the new version
			if newRoute.Target != "" {
				switch newRoute.Proto {
				case "tcp":
					i.translator.ForwardTCP(p, newRoute.Ip, newRoute.Port, newRoute.Target)
				case "udp":
					i.translator.ForwardUDP(p, newRoute.Ip, newRoute.Port, newRoute.Target)
				default:
					log.Printf("INT: unrecognized protocol: %v", newRoute)
				}
			}

			if newRoute.Name != "" {
				log.Printf("INT: STORE %v->%v", newRoute.Domain(), newRoute)
				i.domains[newRoute.Domain()] = newRoute
			}

			i.domainsLock.Unlock()
		}

		// remove the route from our map of old routes so we
		// don't end up deleting it below
		delete(oldRoutes, newRoute.Name)
	}

	// Clear out stale routes and DNS names
	i.domainsLock.Lock()
	for _, route := range oldRoutes {
		log.Printf("INT: CLEAR %v->%v", route.Domain(), route)
		delete(i.domains, route.Domain())

		switch route.Proto {
		case "tcp":
			i.translator.ClearTCP(p, route.Ip, route.Port)
		case "udp":
			i.translator.ClearUDP(p, route.Ip, route.Port)
		default:
			log.Printf("INT: unrecognized protocol: %v", route)
		}
	}
	i.domainsLock.Unlock()

	// Update the externally-visible table
	i.tablesLock.Lock()
	if table.Routes == nil || len(table.Routes) == 0 {
		delete(i.tables, table.Name)
	} else {
		i.tables[table.Name] = table
	}
	i.tablesLock.Unlock()

	return nil
}

// SetSearchPath updates the DNS search path used by the resolver
func (i *Interceptor) SetSearchPath(paths []string) {
	i.searchLock.Lock()
	defer i.searchLock.Unlock()

	i.search = paths
}

// GetSearchPath retrieves the current search path
func (i *Interceptor) GetSearchPath() []string {
	i.searchLock.RLock()
	defer i.searchLock.RUnlock()

	return i.search
}
<commit_msg>Add debug statements<commit_after>package interceptor

import (
	"encoding/json"
	"log"
	"net"
	"strings"
	"sync"

	"github.com/datawire/ambassador/pkg/supervisor"

	"github.com/datawire/ambassador/internal/pkg/nat"
	rt "github.com/datawire/ambassador/internal/pkg/route"
)

type Interceptor struct {
	translator *nat.Translator
	tables     map[string]rt.Table
	tablesLock sync.RWMutex

	domains     map[string]rt.Route
	domainsLock sync.RWMutex

	search     []string
	searchLock sync.RWMutex

	work chan func(*supervisor.Process) error
}

func NewInterceptor(name string) *Interceptor {
	ret := &Interceptor{
		tables:     make(map[string]rt.Table),
		translator: nat.NewTranslator(name),
		domains:    make(map[string]rt.Route),
		search:     []string{""},
		work:       make(chan func(*supervisor.Process) error),
	}
	ret.tablesLock.Lock() // leave it locked until .Start() unlocks it
	return ret
}

func (i *Interceptor) Work(p *supervisor.Process) error {
	i.translator.Enable(p)
	i.tablesLock.Unlock()

	p.Ready()

	for {
		select {
		case <-p.Shutdown():
			i.tablesLock.Lock()
			i.translator.Disable(p)
			// leave it locked
			return nil
		case f := <-i.work:
			err := f(p)
			if err != nil {
				return err
			}
		}
	}
}

// Resolve looks up the given query in the (FIXME: somewhere), trying
// all the suffixes in the search path, and returns a Route on success
// or nil on failure. This implementation does not count the number of
// dots in the query.
func (i *Interceptor) Resolve(query string) *rt.Route {
	if !strings.HasSuffix(query, ".") {
		query += "."
	}

	const prefix = "teleproxy"
	const suffix = ".cachebust.telepresence.io." // must end with .
	const replacement = "teleproxy."             // must end with .
	if strings.HasPrefix(query, prefix) && strings.HasSuffix(query, suffix) {
		query = replacement
	}

	i.searchLock.RLock()
	defer i.searchLock.RUnlock()
	i.domainsLock.RLock()
	defer i.domainsLock.RUnlock()

	for _, suffix := range i.search {
		name := query + suffix
		value, ok := i.domains[strings.ToLower(name)]
		if ok {
			return &value
		}
	}
	return nil
}

func (i *Interceptor) Destination(conn *net.TCPConn) (string, error) {
	_, host, err := i.translator.GetOriginalDst(conn)
	return host, err
}

func (i *Interceptor) Render(table string) string {
	var obj interface{}

	if table == "" {
		var tables []rt.Table
		i.tablesLock.RLock()
		for _, t := range i.tables {
			tables = append(tables, t)
		}
		i.tablesLock.RUnlock()
		obj = tables
	} else {
		var ok bool
		i.tablesLock.RLock()
		obj, ok = i.tables[table]
		i.tablesLock.RUnlock()
		if !ok {
			return ""
		}
	}

	bytes, err := json.MarshalIndent(obj, "", "  ")
	if err != nil {
		return err.Error()
	} else {
		return string(bytes)
	}
}

func (i *Interceptor) Delete(table string) bool {
	result := make(chan bool)
	i.work <- func(p *supervisor.Process) error {
		i.tablesLock.Lock()
		defer i.tablesLock.Unlock()
		i.domainsLock.Lock()
		defer i.domainsLock.Unlock()

		var names []string
		if table == "" {
			for name := range i.tables {
				names = append(names, name)
			}
		} else if _, ok := i.tables[table]; ok {
			names = []string{table}
		} else {
			result <- false
			return nil
		}

		for _, name := range names {
			if name != "bootstrap" {
				err := i.update(p, rt.Table{Name: name})
				if err != nil {
					return err
				}
			}
		}

		result <- true
		return nil
	}

	return <-result
}

func (i *Interceptor) Update(table rt.Table) {
	result := make(chan struct{})
	i.work <- func(p *supervisor.Process) error {
		defer close(result)
		return i.update(p, table)
	}
	<-result
}

func (i *Interceptor) update(p *supervisor.Process, table rt.Table) error {
	// Make a copy of the current table
	i.tablesLock.Lock()
	oldTable, ok := i.tables[table.Name]
	oldRoutes := make(map[string]rt.Route)
	if ok {
		for _, route := range oldTable.Routes {
			oldRoutes[route.Name] = route
		}
	}
	i.tablesLock.Unlock()

	// Operate on the copy of the current table and the new table
	for _, newRoute := range table.Routes {
		oldRoute, oldRouteOk := oldRoutes[newRoute.Name]
		// A nil Route (when oldRouteOk != true) will compare
		// inequal to any valid new Route.
		if newRoute != oldRoute {
			log.Printf("INT: new route %v:%v domain %v does not match old route", newRoute.Ip, newRoute.Port, newRoute.Domain())
			log.Printf("INT: old route exists for %v:%v and domain %v", oldRoute.Ip, oldRoute.Port, oldRoute.Domain())
			// We're updating a route. Make sure DNS waits until the new answer
			// is ready, i.e. don't serve the old answer.
			i.domainsLock.Lock()

			// delete the old version
			if oldRouteOk {
				switch newRoute.Proto {
				case "tcp":
					i.translator.ClearTCP(p, oldRoute.Ip, oldRoute.Port)
				case "udp":
					i.translator.ClearUDP(p, oldRoute.Ip, oldRoute.Port)
				default:
					log.Printf("INT: unrecognized protocol: %v", newRoute)
				}
			}
			// and add the new version
			if newRoute.Target != "" {
				switch newRoute.Proto {
				case "tcp":
					i.translator.ForwardTCP(p, newRoute.Ip, newRoute.Port, newRoute.Target)
				case "udp":
					i.translator.ForwardUDP(p, newRoute.Ip, newRoute.Port, newRoute.Target)
				default:
					log.Printf("INT: unrecognized protocol: %v", newRoute)
				}
			}

			if newRoute.Name != "" {
				log.Printf("INT: STORE %v->%v", newRoute.Domain(), newRoute)
				i.domains[newRoute.Domain()] = newRoute
			}

			i.domainsLock.Unlock()
		}

		// remove the route from our map of old routes so we
		// don't end up deleting it below
		delete(oldRoutes, newRoute.Name)
	}

	// Clear out stale routes and DNS names
	i.domainsLock.Lock()
	for _, route := range oldRoutes {
		log.Printf("INT: CLEAR %v->%v", route.Domain(), route)
		delete(i.domains, route.Domain())

		switch route.Proto {
		case "tcp":
			i.translator.ClearTCP(p, route.Ip, route.Port)
		case "udp":
			i.translator.ClearUDP(p, route.Ip, route.Port)
		default:
			log.Printf("INT: unrecognized protocol: %v", route)
		}
	}
	i.domainsLock.Unlock()

	// Update the externally-visible table
	i.tablesLock.Lock()
	if table.Routes == nil || len(table.Routes) == 0 {
		delete(i.tables, table.Name)
	} else {
		i.tables[table.Name] = table
	}
	i.tablesLock.Unlock()

	return nil
}

// SetSearchPath updates the DNS search path used by the resolver
func (i *Interceptor) SetSearchPath(paths []string) {
	i.searchLock.Lock()
	defer i.searchLock.Unlock()

	i.search = paths
}

// GetSearchPath retrieves the current search path
func (i *Interceptor) GetSearchPath() []string {
	i.searchLock.RLock()
	defer i.searchLock.RUnlock()

	return i.search
}
<|endoftext|>


<commit_before>/*
Copyright 2014 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 resource

import (
	"fmt"
	"reflect"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/yaml"
)

// Mapper is a convenience struct for holding references to the three interfaces
// needed to create Info for arbitrary objects.
type Mapper struct {
	runtime.ObjectTyper
	meta.RESTMapper
	ClientMapper
}

// InfoForData creates an Info object for the given data. An error is returned
// if any of the decoding or client lookup steps fail. Name and namespace will be
// set into Info if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
	json, err := yaml.ToJSON(data)
	if err != nil {
		return nil, fmt.Errorf("unable to parse %q: %v", source, err)
	}
	data = json
	version, kind, err := m.DataVersionAndKind(data)
	if err != nil {
		return nil, fmt.Errorf("unable to get type info from %q: %v", source, err)
	}
	if kind == "" {
		return nil, fmt.Errorf("kind not set in %q", source)
	}
	mapping, err := m.RESTMapping(kind, version)
	if err != nil {
		return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
	}
	obj, err := mapping.Codec.Decode(data)
	if err != nil {
		return nil, fmt.Errorf("unable to load %q: %v", source, err)
	}
	client, err := m.ClientForMapping(mapping)
	if err != nil {
		return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
	}
	name, _ := mapping.MetadataAccessor.Name(obj)
	namespace, _ := mapping.MetadataAccessor.Namespace(obj)
	resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj)
	return &Info{
		Mapping:   mapping,
		Client:    client,
		Namespace: namespace,
		Name:      name,

		Object:          obj,
		ResourceVersion: resourceVersion,
	}, nil
}

// InfoForData creates an Info object for the given Object. An error is returned
// if the object cannot be introspected. Name and namespace will be set into Info
// if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForObject(obj runtime.Object) (*Info, error) {
	version, kind, err := m.ObjectVersionAndKind(obj)
	if err != nil {
		return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err)
	}
	mapping, err := m.RESTMapping(kind, version)
	if err != nil {
		return nil, fmt.Errorf("unable to recognize %q: %v", kind, err)
	}
	client, err := m.ClientForMapping(mapping)
	if err != nil {
		return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
	}
	name, _ := mapping.MetadataAccessor.Name(obj)
	namespace, _ := mapping.MetadataAccessor.Namespace(obj)
	resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj)
	return &Info{
		Mapping:   mapping,
		Client:    client,
		Namespace: namespace,
		Name:      name,

		Object:          obj,
		ResourceVersion: resourceVersion,
	}, nil
}
<commit_msg>kubectl should use UnstructuredJSONScheme to decode version and kind, as it throws errors if either are missing]<commit_after>/*
Copyright 2014 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 resource

import (
	"fmt"
	"reflect"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/yaml"
)

// Mapper is a convenience struct for holding references to the three interfaces
// needed to create Info for arbitrary objects.
type Mapper struct {
	runtime.ObjectTyper
	meta.RESTMapper
	ClientMapper
}

// InfoForData creates an Info object for the given data. An error is returned
// if any of the decoding or client lookup steps fail. Name and namespace will be
// set into Info if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
	json, err := yaml.ToJSON(data)
	if err != nil {
		return nil, fmt.Errorf("unable to parse %q: %v", source, err)
	}
	data = json
	version, kind, err := runtime.UnstructuredJSONScheme.DataVersionAndKind(data)
	if err != nil {
		return nil, fmt.Errorf("unable to get type info from %q: %v", source, err)
	}
	if kind == "" {
		return nil, fmt.Errorf("kind not set in %q", source)
	}
	mapping, err := m.RESTMapping(kind, version)
	if err != nil {
		return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
	}
	obj, err := mapping.Codec.Decode(data)
	if err != nil {
		return nil, fmt.Errorf("unable to load %q: %v", source, err)
	}
	client, err := m.ClientForMapping(mapping)
	if err != nil {
		return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
	}
	name, _ := mapping.MetadataAccessor.Name(obj)
	namespace, _ := mapping.MetadataAccessor.Namespace(obj)
	resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj)
	return &Info{
		Mapping:   mapping,
		Client:    client,
		Namespace: namespace,
		Name:      name,

		Object:          obj,
		ResourceVersion: resourceVersion,
	}, nil
}

// InfoForData creates an Info object for the given Object. An error is returned
// if the object cannot be introspected. Name and namespace will be set into Info
// if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForObject(obj runtime.Object) (*Info, error) {
	version, kind, err := m.ObjectVersionAndKind(obj)
	if err != nil {
		return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err)
	}
	mapping, err := m.RESTMapping(kind, version)
	if err != nil {
		return nil, fmt.Errorf("unable to recognize %q: %v", kind, err)
	}
	client, err := m.ClientForMapping(mapping)
	if err != nil {
		return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
	}
	name, _ := mapping.MetadataAccessor.Name(obj)
	namespace, _ := mapping.MetadataAccessor.Namespace(obj)
	resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj)
	return &Info{
		Mapping:   mapping,
		Client:    client,
		Namespace: namespace,
		Name:      name,

		Object:          obj,
		ResourceVersion: resourceVersion,
	}, nil
}
<|endoftext|>