<commit_before>package multipaxos

import "net"
import "net/rpc"
import "syscall"
import "crypto/rand"
import "math/big"
import "fmt"
import "time"

//constants
const(
	MAX_RETRY = 10
	DEBUG = -1000
	NPINGS = 5
	PINGINTERVAL = 500*time.Millisecond
	PINGWAIT = NPINGS*PINGINTERVAL
	//op types
	LCHANGE = "LCHANGE"
	NORMAL = "NORMAL"
	//status code
	OK = "OK"
	NOT_LEADER = "NOT_LEADER"
	REJECT = "REJECT"
	//Leader status
	UNKNOWN_LEADER = "UNKNOWN LEADER"
	WRONG_SERVER = "WRONG SERVER"
	INVALID_INSTANCE= "INVALID INSTANCE"
	)
//new array type needed for sorting an array of int64
type intarr []int
func (a intarr) Len() int { return len(a) }
func (a intarr) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a intarr) Less(i, j int) bool { return a[i] < a[j] }

type Status string
type OpType string

type MultiPaxosLeader struct{
	epoch int
	id int
	numPingsMissed int
	valid bool
}
func (mpl *MultiPaxosLeader) isValid() bool{
	return !(mpl.epoch<=0 || mpl.numPingsMissed > NPINGS || !mpl.valid)
}
type MultiPaxosOP struct{
	Epoch int
	Type OpType
	Op interface{}
}
type MultiPaxosLeaderChange struct{
	NewEpoch int
	ID int
}
type PingArgs struct{
	ServerID int
	LowestInstance int
	MaxDone int
}
type PingReply struct{
	Status Status
	Epoch int
	InstancesData map[int]MultiPaxosOP
	Leader string
	Min int
}
type RemoteStartArgs struct{
	InstanceNumber int
	Op interface{}
}
type RemoteStartReply struct{
	Status Status
	Epoch int
	Leader string
}
//***********************************************************************************************************************************//
//Helper Functions
//***********************************************************************************************************************************//

//generates random int
func nrand() int64 {
  max := big.NewInt(int64(1) << 62)
  bigx, _ := rand.Int(rand.Reader, max)
  x:=bigx.Int64()
  return x
}
//
// call() sends an RPC to the rpcname handler on server srv
// with arguments args, waits for the reply, and leaves the
// reply in reply. the reply argument should be a pointer
// to a reply structure.
//
// the return value is true if the server responded, and false
// if call() was not able to contact the server. in particular,
// the reply's contents are only valid if call() returned true.
//
// you should assume that call() will time out and return an
// error after a while if it doesn't get a reply from the server.
//
// please use call() to send all RPCs, in client.go and server.go.
// please don't change this function.
//
func call(srv string, name string, args interface{}, reply interface{}, unix bool) bool {
  var err error
  var c *rpc.Client
  if unix {
    c, err = rpc.Dial("unix", srv)
  } else {
    c, err = rpc.Dial("tcp", srv)
  }
  if err != nil {
    err1 := err.(*net.OpError)
    if err1.Err != syscall.ENOENT && err1.Err != syscall.ECONNREFUSED {
      fmt.Printf("paxos Dial() failed: %v\n", err1)
    }
    return false
  }
  defer c.Close()

  err = c.Call(name, args, reply)
  if err == nil {
    return true
  }

  fmt.Println(err)
  return false
}
//debug print statement functions with priorities
func DPrint(pri int, format string) (n int, err error) {
  if DEBUG > pri {
    fmt.Printf(format)
  }
  return
}
func Log (pri int, prefix string, id string, format string) (n int, err error) {
  return DPrint(pri, "{" + prefix+" "+id+ "} " + format+"\n")
}<commit_msg>enabled logging<commit_after>package multipaxos

import "net"
import "net/rpc"
import "syscall"
import "crypto/rand"
import "math/big"
import "fmt"
import "time"

//constants
const(
	MAX_RETRY = 10
	DEBUG = 3
	NPINGS = 5
	PINGINTERVAL = 500*time.Millisecond
	PINGWAIT = NPINGS*PINGINTERVAL
	//op types
	LCHANGE = "LCHANGE"
	NORMAL = "NORMAL"
	//status code
	OK = "OK"
	NOT_LEADER = "NOT_LEADER"
	REJECT = "REJECT"
	//Leader status
	UNKNOWN_LEADER = "UNKNOWN LEADER"
	WRONG_SERVER = "WRONG SERVER"
	INVALID_INSTANCE= "INVALID INSTANCE"
	)
//new array type needed for sorting an array of int64
type intarr []int
func (a intarr) Len() int { return len(a) }
func (a intarr) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a intarr) Less(i, j int) bool { return a[i] < a[j] }

type Status string
type OpType string

type MultiPaxosLeader struct{
	epoch int
	id int
	numPingsMissed int
	valid bool
}
func (mpl *MultiPaxosLeader) isValid() bool{
	return !(mpl.epoch<=0 || mpl.numPingsMissed > NPINGS || !mpl.valid)
}
type MultiPaxosOP struct{
	Epoch int
	Type OpType
	Op interface{}
}
type MultiPaxosLeaderChange struct{
	NewEpoch int
	ID int
}
type PingArgs struct{
	ServerID int
	LowestInstance int
	MaxDone int
}
type PingReply struct{
	Status Status
	Epoch int
	InstancesData map[int]MultiPaxosOP
	Leader string
	Min int
}
type RemoteStartArgs struct{
	InstanceNumber int
	Op interface{}
}
type RemoteStartReply struct{
	Status Status
	Epoch int
	Leader string
}
//***********************************************************************************************************************************//
//Helper Functions
//***********************************************************************************************************************************//

//generates random int
func nrand() int64 {
  max := big.NewInt(int64(1) << 62)
  bigx, _ := rand.Int(rand.Reader, max)
  x:=bigx.Int64()
  return x
}
//
// call() sends an RPC to the rpcname handler on server srv
// with arguments args, waits for the reply, and leaves the
// reply in reply. the reply argument should be a pointer
// to a reply structure.
//
// the return value is true if the server responded, and false
// if call() was not able to contact the server. in particular,
// the reply's contents are only valid if call() returned true.
//
// you should assume that call() will time out and return an
// error after a while if it doesn't get a reply from the server.
//
// please use call() to send all RPCs, in client.go and server.go.
// please don't change this function.
//
func call(srv string, name string, args interface{}, reply interface{}, unix bool) bool {
  var err error
  var c *rpc.Client
  if unix {
    c, err = rpc.Dial("unix", srv)
  } else {
    c, err = rpc.Dial("tcp", srv)
  }
  if err != nil {
    err1 := err.(*net.OpError)
    if err1.Err != syscall.ENOENT && err1.Err != syscall.ECONNREFUSED {
      fmt.Printf("paxos Dial() failed: %v\n", err1)
    }
    return false
  }
  defer c.Close()

  err = c.Call(name, args, reply)
  if err == nil {
    return true
  }

  fmt.Println(err)
  return false
}
//debug print statement functions with priorities
func DPrint(pri int, format string) (n int, err error) {
  if DEBUG > pri {
    fmt.Printf(format)
  }
  return
}
func Log (pri int, prefix string, id string, format string) (n int, err error) {
  return DPrint(pri, "{" + prefix+" "+id+ "} " + format+"\n")
}<|endoftext|>


<commit_before>package storage

import "testing"

/**
 * ZooKeeper Storage Manager Test
 *
 * @author: Anant Bhardwaj
 * @date: 05/11/2014
 */

func TestBasicLeaderModified(t *testing.T) {
  servers := "localhost:2181"
  sm := MakeStorageManager()
  sm.Open(servers)
  defer sm.Close()
  sm.Create("/test", "")
  sm.Create("/test/_var_tmp_824-1000_px-12568-basic-1", "")
  sm.Create("/test/_var_tmp_824-1000_px-12568-basic-1/store", "")
  sm.Create("/test/_var_tmp_824-1000_px-12568-basic-1/done", "")
  sm.Create("/test/_var_tmp_824-1000_px-12568-basic-1/store/0", "6.824")

  _ = sm.Write("/test/_var_tmp_824-1000_px-12568-basic-1/store/0", "6.824")
  data, _ := sm.Read("/test/_var_tmp_824-1000_px-12568-basic-1/store/0")
  if data != "6.824" {
    t.Fatalf("got=%v wanted=%v", data, "6.824")
  }

  sm.Close()
  sm.Open(servers)
  data, _ = sm.Read("/test/_var_tmp_824-1000_px-12568-basic-1/store/0")
  if data != "6.824" {
    t.Fatalf("got=%v wanted=%v", data, "6.824")
  }
  sm.Close()
}

<commit_msg>more tests<commit_after>package storage

import "testing"

/**
 * ZooKeeper Storage Manager Test
 *
 * @author: Anant Bhardwaj
 * @date: 05/11/2014
 */

func TestBasicLeaderModified(t *testing.T) {
  servers := "localhost:2181"
  sm := MakeStorageManager()
  sm.Open(servers)
  defer sm.Close()
  sm.Create("/edu", "")
  sm.Create("/edu/mit", "")
  sm.Create("/edu/mit/class", "")

  // test create, write, and read

  _ = sm.Create("/edu/mit/class/6.824", "Distributed Systems")
  _ = sm.Write("/edu/mit/class/6.831", "UI Design")

  data, _ := sm.Read("/edu/mit/class/6.824")
  if data != "Distributed Systems" {
    t.Fatalf("got=%v wanted=%v", data, "Distributed Systems")
  }

  data, _ = sm.Read("/edu/mit/class/6.831")
  if data != "UI Design" {
    t.Fatalf("got=%v wanted=%v", data, "UI Design")
  }

  sm.Close()

  // close the zookeper to check the persistence

  sm.Open(servers)
  data, _ = sm.Read("/edu/mit/class/6.824")
  if data != "Distributed Systems" {
    t.Fatalf("got=%v wanted=%v", data, "Distributed Systems")
  }

  data, _ = sm.Read("/edu/mit/class/6.831")
  if data != "UI Design" {
    t.Fatalf("got=%v wanted=%v", data, "UI Design")
  }

  sm.Close()
}

<|endoftext|>


<commit_before>package distro

import (
	"github.com/drasko/edgex-export"
	MQTT "github.com/eclipse/paho.mqtt.golang"
	"go.uber.org/zap"
	"strconv"
)

type mqttSender struct {
	client MQTT.Client
	topic  string
}

const clientID = "edgex"
const topic = "EdgeX"

func NewMqttSender(addr export.Addressable) Sender {
	opts := MQTT.NewClientOptions()
	// CHN: Should be added protocol from Addressable instead of include it the address param.
	// CHN: We will maintain this behaviour for compatibility with Java
	broker := addr.Address + ":" + strconv.Itoa(addr.Port)
	opts.AddBroker(broker)
	opts.SetClientID(clientID)
	opts.SetUsername(addr.User)
	opts.SetPassword(addr.Password)

	var sender mqttSender

	sender := mqttClient{
		client: MQTT.NewClient(opts),
		topic:  addr.Topic,
	}

	if token := sender.mqttClient.Connect(); token.Wait() && token.Error() != nil {
		panic(token.Error())
	}
	logger.Info("Sample Publisher Started")

	return sender
}

func (sender mqttSender) Send(data []byte) {
	token := sender.mqttClient.Publish(sender.topic, 0, false, data)
	// FIXME: could be removed? set of tokens?
	token.Wait()
	logger.Info("Sent data: ", zap.String("data", data))
}
<commit_msg>Fixed compilation<commit_after>package distro

import (
	"github.com/drasko/edgex-export"
	MQTT "github.com/eclipse/paho.mqtt.golang"
	"go.uber.org/zap"
	"strconv"
)

type mqttSender struct {
	client MQTT.Client
	topic  string
}

const clientID = "edgex"
const topic = "EdgeX"

func NewMqttSender(addr export.Addressable) Sender {
	opts := MQTT.NewClientOptions()
	// CHN: Should be added protocol from Addressable instead of include it the address param.
	// CHN: We will maintain this behaviour for compatibility with Java
	broker := addr.Address + ":" + strconv.Itoa(addr.Port)
	opts.AddBroker(broker)
	opts.SetClientID(clientID)
	opts.SetUsername(addr.User)
	opts.SetPassword(addr.Password)

	sender := mqttSender{
		client: MQTT.NewClient(opts),
		topic:  addr.Topic,
	}

	if token := sender.client.Connect(); token.Wait() && token.Error() != nil {
		panic(token.Error())
	}
	logger.Info("Sample Publisher Started")

	return sender
}

func (sender mqttSender) Send(data []byte) {
	token := sender.client.Publish(sender.topic, 0, false, data)
	// FIXME: could be removed? set of tokens?
	token.Wait()
	logger.Info("Sent data: ", zap.String("data", data))
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 Go Fightclub Authors
// This source code is released under the terms of the
// MIT license. Please see the file LICENSE for license details.

package main

import (
	"afp"
	"afp/filters/null"
	"afp/filters/fexec"
	"afp/filters/libav"
    "afp/filters/alsa"
)

var filters map[string]func() afp.Filter = map[string]func() afp.Filter {
	"execsink"		: fexec.NewExecSink,
	"execlink"		: fexec.NewExecLink,
	"execsource"	: fexec.NewExecSource,*/
	"nullsource"	: null.NewNullSource,
	"nulllink"		: null.NewNullLink,
	"nullsink"		: null.NewNullSink,
	"stdoutsink"	: stdout.NewStdoutSink,
	"libavsource"	: libavfilter.NewLibAVSource,
    "alsasource"    : alsa.NewAlsaSource,
    "alsasink"      : alsa.NewAlsaSink,
}
<commit_msg>remove accidental */ in filterlist<commit_after>// Copyright (c) 2010 Go Fightclub Authors
// This source code is released under the terms of the
// MIT license. Please see the file LICENSE for license details.

package main

import (
	"afp"
	"afp/filters/null"
	"afp/filters/fexec"
	"afp/filters/libav"
    "afp/filters/alsa"
)

var filters map[string]func() afp.Filter = map[string]func() afp.Filter {
	"execsink"		: fexec.NewExecSink,
	"execlink"		: fexec.NewExecLink,
	"execsource"	: fexec.NewExecSource,
	"nullsource"	: null.NewNullSource,
	"nulllink"		: null.NewNullLink,
	"nullsink"		: null.NewNullSink,
	"stdoutsink"	: stdout.NewStdoutSink,
	"libavsource"	: libavfilter.NewLibAVSource,
    "alsasource"    : alsa.NewAlsaSource,
    "alsasink"      : alsa.NewAlsaSink,
}
<|endoftext|>


<commit_before>package ignition

// This schema structure is based on github.com/coreos/ignition/config/v2_2/types/schema.go
// Due to issue with unmarshalling embedded anonymous nested structures,
// this file removes such structures.
// Changed types: Directory, File, Link.
type CaReference struct {
	Source       string       `json:"source,omitempty"`
	Verification Verification `json:"verification,omitempty"`
}
type Config struct {
	Ignition Ignition `json:"ignition"`
	Networkd Networkd `json:"networkd,omitempty"`
	Passwd   Passwd   `json:"passwd,omitempty"`
	Storage  Storage  `json:"storage,omitempty"`
	Systemd  Systemd  `json:"systemd,omitempty"`
}
type ConfigReference struct {
	Source       string       `json:"source,omitempty"`
	Verification Verification `json:"verification,omitempty"`
}
type Create struct {
	Force   bool           `json:"force,omitempty"`
	Options []CreateOption `json:"options,omitempty"`
}
type CreateOption string
type Device string
type Directory struct {
	Filesystem string     `json:"filesystem,omitempty"`
	Group      *NodeGroup `json:"group,omitempty"`
	Mode       *int       `json:"mode,omitempty"`
	Overwrite  *bool      `json:"overwrite,omitempty"`
	Path       string     `json:"path,omitempty"`
	User       *NodeUser  `json:"user,omitempty"`
}
type Disk struct {
	Device     string      `json:"device,omitempty"`
	Partitions []Partition `json:"partitions,omitempty"`
	WipeTable  bool        `json:"wipeTable,omitempty"`
}
type File struct {
	Append     bool         `json:"append,omitempty"`
	Contents   FileContents `json:"contents,omitempty"`
	Filesystem string       `json:"filesystem,omitempty"`
	Mode       int          `json:"mode,omitempty"`
	Group      *NodeGroup   `json:"group,omitempty"`
	Overwrite  *bool        `json:"overwrite,omitempty"`
	Path       string       `json:"path,omitempty"`
	User       *NodeUser    `json:"user,omitempty"`
}
type FileContents struct {
	Compression  string       `json:"compression,omitempty"`
	Source       string       `json:"source,omitempty"`
	Verification Verification `json:"verification,omitempty"`
}
type Filesystem struct {
	Mount *Mount  `json:"mount,omitempty"`
	Name  string  `json:"name,omitempty"`
	Path  *string `json:"path,omitempty"`
}
type Group string
type Ignition struct {
	Config   IgnitionConfig `json:"config,omitempty"`
	Security Security       `json:"security,omitempty"`
	Timeouts Timeouts       `json:"timeouts,omitempty"`
	Version  string         `json:"version,omitempty"`
}
type IgnitionConfig struct {
	Append  []ConfigReference `json:"append,omitempty"`
	Replace *ConfigReference  `json:"replace,omitempty"`
}
type Link struct {
	Filesystem string     `json:"filesystem,omitempty"`
	Group      *NodeGroup `json:"group,omitempty"`
	Hard       bool       `json:"hard,omitempty"`
	Overwrite  *bool      `json:"overwrite,omitempty"`
	Path       string     `json:"path,omitempty"`
	Target     string     `json:"target,omitempty"`
	User       *NodeUser  `json:"user,omitempty"`
}
type Mount struct {
	Create         *Create       `json:"create,omitempty"`
	Device         string        `json:"device,omitempty"`
	Format         string        `json:"format,omitempty"`
	Label          *string       `json:"label,omitempty"`
	Options        []MountOption `json:"options,omitempty"`
	UUID           *string       `json:"uuid,omitempty"`
	WipeFilesystem bool          `json:"wipeFilesystem,omitempty"`
}
type MountOption string
type Networkd struct {
	Units []Networkdunit `json:"units,omitempty"`
}
type NetworkdDropin struct {
	Contents string `json:"contents,omitempty"`
	Name     string `json:"name,omitempty"`
}
type Networkdunit struct {
	Contents string           `json:"contents,omitempty"`
	Dropins  []NetworkdDropin `json:"dropins,omitempty"`
	Name     string           `json:"name,omitempty"`
}
type Node struct {
	Filesystem string     `json:"filesystem,omitempty"`
	Group      *NodeGroup `json:"group,omitempty"`
	Overwrite  *bool      `json:"overwrite,omitempty"`
	Path       string     `json:"path,omitempty"`
	User       *NodeUser  `json:"user,omitempty"`
}
type NodeGroup struct {
	ID   *int   `json:"id,omitempty"`
	Name string `json:"name,omitempty"`
}
type NodeUser struct {
	ID   *int   `json:"id,omitempty"`
	Name string `json:"name,omitempty"`
}
type Partition struct {
	GUID     string `json:"guid,omitempty"`
	Label    string `json:"label,omitempty"`
	Number   int    `json:"number,omitempty"`
	Size     int    `json:"size,omitempty"`
	Start    int    `json:"start,omitempty"`
	TypeGUID string `json:"typeGuid,omitempty"`
}
type Passwd struct {
	Groups []PasswdGroup `json:"groups,omitempty"`
	Users  []PasswdUser  `json:"users,omitempty"`
}
type PasswdGroup struct {
	Gid          *int   `json:"gid,omitempty"`
	Name         string `json:"name,omitempty"`
	PasswordHash string `json:"passwordHash,omitempty"`
	System       bool   `json:"system,omitempty"`
}
type PasswdUser struct {
	Create            *Usercreate        `json:"create,omitempty"`
	Gecos             string             `json:"gecos,omitempty"`
	Groups            []Group            `json:"groups,omitempty"`
	HomeDir           string             `json:"homeDir,omitempty"`
	Name              string             `json:"name,omitempty"`
	NoCreateHome      bool               `json:"noCreateHome,omitempty"`
	NoLogInit         bool               `json:"noLogInit,omitempty"`
	NoUserGroup       bool               `json:"noUserGroup,omitempty"`
	PasswordHash      *string            `json:"passwordHash,omitempty"`
	PrimaryGroup      string             `json:"primaryGroup,omitempty"`
	SSHAuthorizedKeys []SSHAuthorizedKey `json:"sshAuthorizedKeys,omitempty"`
	Shell             string             `json:"shell,omitempty"`
	System            bool               `json:"system,omitempty"`
	UID               *int               `json:"uid,omitempty"`
}
type Raid struct {
	Devices []Device     `json:"devices,omitempty"`
	Level   string       `json:"level,omitempty"`
	Name    string       `json:"name,omitempty"`
	Options []RaidOption `json:"options,omitempty"`
	Spares  int          `json:"spares,omitempty"`
}
type RaidOption string
type SSHAuthorizedKey string
type Security struct {
	TLS TLS `json:"tls,omitempty"`
}
type Storage struct {
	Directories []Directory  `json:"directories,omitempty"`
	Disks       []Disk       `json:"disks,omitempty"`
	Files       []File       `json:"files,omitempty"`
	Filesystems []Filesystem `json:"filesystems,omitempty"`
	Links       []Link       `json:"links,omitempty"`
	Raid        []Raid       `json:"raid,omitempty"`
}
type Systemd struct {
	Units []Unit `json:"units,omitempty"`
}
type SystemdDropin struct {
	Contents string `json:"contents,omitempty"`
	Name     string `json:"name,omitempty"`
}
type TLS struct {
	CertificateAuthorities []CaReference `json:"certificateAuthorities,omitempty"`
}
type Timeouts struct {
	HTTPResponseHeaders *int `json:"httpResponseHeaders,omitempty"`
	HTTPTotal           *int `json:"httpTotal,omitempty"`
}
type Unit struct {
	Contents string          `json:"contents,omitempty"`
	Dropins  []SystemdDropin `json:"dropins,omitempty"`
	Enable   bool            `json:"enable,omitempty"`
	Enabled  *bool           `json:"enabled,omitempty"`
	Mask     bool            `json:"mask,omitempty"`
	Name     string          `json:"name,omitempty"`
}
type Usercreate struct {
	Gecos        string            `json:"gecos,omitempty"`
	Groups       []UsercreateGroup `json:"groups,omitempty"`
	HomeDir      string            `json:"homeDir,omitempty"`
	NoCreateHome bool              `json:"noCreateHome,omitempty"`
	NoLogInit    bool              `json:"noLogInit,omitempty"`
	NoUserGroup  bool              `json:"noUserGroup,omitempty"`
	PrimaryGroup string            `json:"primaryGroup,omitempty"`
	Shell        string            `json:"shell,omitempty"`
	System       bool              `json:"system,omitempty"`
	UID          *int              `json:"uid,omitempty"`
}
type UsercreateGroup string
type Verification struct {
	Hash *string `json:"hash,omitempty"`
}
<commit_msg>Add yaml tags for ignition schema (#433)<commit_after>package ignition

// This schema structure is based on github.com/coreos/ignition/config/v2_2/types/schema.go
// Due to issue with unmarshalling embedded anonymous nested structures,
// this file removes such structures.
// Changed types: Directory, File, Link.
type CaReference struct {
	Source       string       `json:"source,omitempty" yaml:"source,omitempty"`
	Verification Verification `json:"verification,omitempty" yaml:"verification,omitempty"`
}
type Config struct {
	Ignition Ignition `json:"ignition" yaml:"ignition,omitempty"`
	Networkd Networkd `json:"networkd,omitempty" yaml:"networkd,omitempty"`
	Passwd   Passwd   `json:"passwd,omitempty" yaml:"passwd,omitempty"`
	Storage  Storage  `json:"storage,omitempty" yaml:"storage,omitempty"`
	Systemd  Systemd  `json:"systemd,omitempty" yaml:"systemd,omitempty"`
}
type ConfigReference struct {
	Source       string       `json:"source,omitempty" yaml:"source,omitempty"`
	Verification Verification `json:"verification,omitempty" yaml:"verification,omitempty"`
}
type Create struct {
	Force   bool           `json:"force,omitempty" yaml:"force,omitempty"`
	Options []CreateOption `json:"options,omitempty" yaml:"options,omitempty"`
}
type CreateOption string
type Device string
type Directory struct {
	Filesystem string     `json:"filesystem,omitempty" yaml:"filesystem,omitempty"`
	Group      *NodeGroup `json:"group,omitempty" yaml:"group,omitempty"`
	Mode       *int       `json:"mode,omitempty" yaml:"mode,omitempty"`
	Overwrite  *bool      `json:"overwrite,omitempty" yaml:"overwrite,omitempty"`
	Path       string     `json:"path,omitempty" yaml:"path,omitempty"`
	User       *NodeUser  `json:"user,omitempty" yaml:"user,omitempty"`
}
type Disk struct {
	Device     string      `json:"device,omitempty" yaml:"device,omitempty"`
	Partitions []Partition `json:"partitions,omitempty" yaml:"partitions,omitempty"`
	WipeTable  bool        `json:"wipeTable,omitempty" yaml:"wipeTable,omitempty"`
}
type File struct {
	Append     bool         `json:"append,omitempty" yaml:"append,omitempty"`
	Contents   FileContents `json:"contents,omitempty" yaml:"contents,omitempty"`
	Filesystem string       `json:"filesystem,omitempty" yaml:"filesystem,omitempty"`
	Mode       int          `json:"mode,omitempty" yaml:"mode,omitempty"`
	Group      *NodeGroup   `json:"group,omitempty" yaml:"group,omitempty"`
	Overwrite  *bool        `json:"overwrite,omitempty" yaml:"overwrite,omitempty"`
	Path       string       `json:"path,omitempty" yaml:"path,omitempty"`
	User       *NodeUser    `json:"user,omitempty" yaml:"user,omitempty"`
}
type FileContents struct {
	Compression  string       `json:"compression,omitempty" yaml:"compression,omitempty"`
	Source       string       `json:"source,omitempty" yaml:"source,omitempty"`
	Verification Verification `json:"verification,omitempty" yaml:"verification,omitempty"`
}
type Filesystem struct {
	Mount *Mount  `json:"mount,omitempty" yaml:"mount,omitempty"`
	Name  string  `json:"name,omitempty" yaml:"name,omitempty"`
	Path  *string `json:"path,omitempty" yaml:"path,omitempty"`
}
type Group string
type Ignition struct {
	Config   IgnitionConfig `json:"config,omitempty" yaml:"config,omitempty"`
	Security Security       `json:"security,omitempty" yaml:"security,omitempty"`
	Timeouts Timeouts       `json:"timeouts,omitempty" yaml:"timeouts,omitempty"`
	Version  string         `json:"version,omitempty" yaml:"version,omitempty"`
}
type IgnitionConfig struct {
	Append  []ConfigReference `json:"append,omitempty" yaml:"append,omitempty"`
	Replace *ConfigReference  `json:"replace,omitempty" yaml:"replace,omitempty"`
}
type Link struct {
	Filesystem string     `json:"filesystem,omitempty" yaml:"filesystem,omitempty"`
	Group      *NodeGroup `json:"group,omitempty" yaml:"group,omitempty"`
	Hard       bool       `json:"hard,omitempty" yaml:"hard,omitempty"`
	Overwrite  *bool      `json:"overwrite,omitempty" yaml:"overwrite,omitempty"`
	Path       string     `json:"path,omitempty" yaml:"path,omitempty"`
	Target     string     `json:"target,omitempty" yaml:"target,omitempty"`
	User       *NodeUser  `json:"user,omitempty" yaml:"user,omitempty"`
}
type Mount struct {
	Create         *Create       `json:"create,omitempty" yaml:"create,omitempty"`
	Device         string        `json:"device,omitempty" yaml:"device,omitempty"`
	Format         string        `json:"format,omitempty" yaml:"format,omitempty"`
	Label          *string       `json:"label,omitempty" yaml:"label,omitempty"`
	Options        []MountOption `json:"options,omitempty" yaml:"options,omitempty"`
	UUID           *string       `json:"uuid,omitempty" yaml:"uuid,omitempty"`
	WipeFilesystem bool          `json:"wipeFilesystem,omitempty" yaml:"wipeFilesystem,omitempty"`
}
type MountOption string
type Networkd struct {
	Units []Networkdunit `json:"units,omitempty" yaml:"units,omitempty"`
}
type NetworkdDropin struct {
	Contents string `json:"contents,omitempty" yaml:"contents,omitempty"`
	Name     string `json:"name,omitempty" yaml:"name,omitempty"`
}
type Networkdunit struct {
	Contents string           `json:"contents,omitempty" yaml:"contents,omitempty"`
	Dropins  []NetworkdDropin `json:"dropins,omitempty" yaml:"dropins,omitempty"`
	Name     string           `json:"name,omitempty" yaml:"name,omitempty"`
}
type Node struct {
	Filesystem string     `json:"filesystem,omitempty" yaml:"filesystem,omitempty"`
	Group      *NodeGroup `json:"group,omitempty" yaml:"group,omitempty"`
	Overwrite  *bool      `json:"overwrite,omitempty" yaml:"overwrite,omitempty"`
	Path       string     `json:"path,omitempty" yaml:"path,omitempty"`
	User       *NodeUser  `json:"user,omitempty" yaml:"user,omitempty"`
}
type NodeGroup struct {
	ID   *int   `json:"id,omitempty" yaml:"id,omitempty"`
	Name string `json:"name,omitempty" yaml:"name,omitempty"`
}
type NodeUser struct {
	ID   *int   `json:"id,omitempty" yaml:"id,omitempty"`
	Name string `json:"name,omitempty" yaml:"name,omitempty"`
}
type Partition struct {
	GUID     string `json:"guid,omitempty" yaml:"guid,omitempty"`
	Label    string `json:"label,omitempty" yaml:"label,omitempty"`
	Number   int    `json:"number,omitempty" yaml:"number,omitempty"`
	Size     int    `json:"size,omitempty" yaml:"size,omitempty"`
	Start    int    `json:"start,omitempty" yaml:"start,omitempty"`
	TypeGUID string `json:"typeGuid,omitempty" yaml:"typeGUID,omitempty"`
}
type Passwd struct {
	Groups []PasswdGroup `json:"groups,omitempty" yaml:"groups,omitempty"`
	Users  []PasswdUser  `json:"users,omitempty" yaml:"users,omitempty"`
}
type PasswdGroup struct {
	Gid          *int   `json:"gid,omitempty" yaml:"gid,omitempty"`
	Name         string `json:"name,omitempty" yaml:"name,omitempty"`
	PasswordHash string `json:"passwordHash,omitempty" yaml:"passwordHash,omitempty"`
	System       bool   `json:"system,omitempty" yaml:"system,omitempty"`
}
type PasswdUser struct {
	Create            *Usercreate        `json:"create,omitempty" yaml:"create,omitempty"`
	Gecos             string             `json:"gecos,omitempty" yaml:"gecos,omitempty"`
	Groups            []Group            `json:"groups,omitempty" yaml:"groups,omitempty"`
	HomeDir           string             `json:"homeDir,omitempty" yaml:"homeDir,omitempty"`
	Name              string             `json:"name,omitempty" yaml:"name,omitempty"`
	NoCreateHome      bool               `json:"noCreateHome,omitempty" yaml:"noCreateHome,omitempty"`
	NoLogInit         bool               `json:"noLogInit,omitempty" yaml:"noLogInit,omitempty"`
	NoUserGroup       bool               `json:"noUserGroup,omitempty" yaml:"noUserGroup,omitempty"`
	PasswordHash      *string            `json:"passwordHash,omitempty" yaml:"passwordHash,omitempty"`
	PrimaryGroup      string             `json:"primaryGroup,omitempty" yaml:"primaryGroup,omitempty"`
	SSHAuthorizedKeys []SSHAuthorizedKey `json:"sshAuthorizedKeys,omitempty" yaml:"sshAuthorizedKeys,omitempty"`
	Shell             string             `json:"shell,omitempty" yaml:"shell,omitempty"`
	System            bool               `json:"system,omitempty" yaml:"system,omitempty"`
	UID               *int               `json:"uid,omitempty" yaml:"uid,omitempty"`
}
type Raid struct {
	Devices []Device     `json:"devices,omitempty" yaml:"devices,omitempty"`
	Level   string       `json:"level,omitempty" yaml:"level,omitempty"`
	Name    string       `json:"name,omitempty" yaml:"name,omitempty"`
	Options []RaidOption `json:"options,omitempty" yaml:"options,omitempty"`
	Spares  int          `json:"spares,omitempty" yaml:"spares,omitempty"`
}
type RaidOption string
type SSHAuthorizedKey string
type Security struct {
	TLS TLS `json:"tls,omitempty" yaml:"tls,omitempty"`
}
type Storage struct {
	Directories []Directory  `json:"directories,omitempty" yaml:"directories,omitempty"`
	Disks       []Disk       `json:"disks,omitempty" yaml:"disks,omitempty"`
	Files       []File       `json:"files,omitempty" yaml:"files,omitempty"`
	Filesystems []Filesystem `json:"filesystems,omitempty" yaml:"filesystems,omitempty"`
	Links       []Link       `json:"links,omitempty" yaml:"links,omitempty"`
	Raid        []Raid       `json:"raid,omitempty" yaml:"raid,omitempty"`
}
type Systemd struct {
	Units []Unit `json:"units,omitempty" yaml:"units,omitempty"`
}
type SystemdDropin struct {
	Contents string `json:"contents,omitempty" yaml:"contents,omitempty"`
	Name     string `json:"name,omitempty" yaml:"name,omitempty"`
}
type TLS struct {
	CertificateAuthorities []CaReference `json:"certificateAuthorities,omitempty" yaml:"certificateAuthorities,omitempty"`
}
type Timeouts struct {
	HTTPResponseHeaders *int `json:"httpResponseHeaders,omitempty" yaml:"httpResponseHeaders,omitempty"`
	HTTPTotal           *int `json:"httpTotal,omitempty" yaml:"httpTotal,omitempty"`
}
type Unit struct {
	Contents string          `json:"contents,omitempty" yaml:"contents,omitempty"`
	Dropins  []SystemdDropin `json:"dropins,omitempty" yaml:"dropins,omitempty"`
	Enable   bool            `json:"enable,omitempty" yaml:"enable,omitempty"`
	Enabled  *bool           `json:"enabled,omitempty" yaml:"enabled,omitempty"`
	Mask     bool            `json:"mask,omitempty" yaml:"mask,omitempty"`
	Name     string          `json:"name,omitempty" yaml:"name,omitempty"`
}
type Usercreate struct {
	Gecos        string            `json:"gecos,omitempty" yaml:"gecos,omitempty"`
	Groups       []UsercreateGroup `json:"groups,omitempty" yaml:"groups,omitempty"`
	HomeDir      string            `json:"homeDir,omitempty" yaml:"homeDir,omitempty"`
	NoCreateHome bool              `json:"noCreateHome,omitempty" yaml:"noCreateHome,omitempty"`
	NoLogInit    bool              `json:"noLogInit,omitempty" yaml:"noLogInit,omitempty"`
	NoUserGroup  bool              `json:"noUserGroup,omitempty" yaml:"noUserGroup,omitempty"`
	PrimaryGroup string            `json:"primaryGroup,omitempty" yaml:"primaryGroup,omitempty"`
	Shell        string            `json:"shell,omitempty" yaml:"shell,omitempty"`
	System       bool              `json:"system,omitempty" yaml:"system,omitempty"`
	UID          *int              `json:"uid,omitempty" yaml:"uid,omitempty"`
}
type UsercreateGroup string
type Verification struct {
	Hash *string `json:"hash,omitempty" yaml:"hash,omitempty"`
}
<|endoftext|>


<commit_before>package errorsutil

import (
	"errors"
	"fmt"
	"strings"
)

// Append adds additional text to an existing error.
func Append(err error, str string) error {
	return errors.New(fmt.Sprint(err) + str)
}

func Join(inclNils bool, errs ...error) error {
	strs := []string{}
	for _, err := range errs {
		if err == nil {
			if inclNils {
				strs = append(strs, "nil")
			}
		} else {
			strs = append(strs, err.Error())
		}
	}
	if len(strs) > 0 {
		return errors.New(strings.Join(strs, ";"))
	}
	return nil
}

// PanicOnErr is a syntactic sugar function to panic on error.
func PanicOnErr(err error) {
	if err != nil {
		panic(err)
	}
}

type ErrorInfo struct {
	Error       error
	ErrorString string // must match Error
	Code        string
	Display     string
	Input       string
	Correct     string
}

type ErrorInfos []*ErrorInfo

func (eis ErrorInfos) Inflate() {
	for i, ei := range eis {
		if ei != nil && ei.Error != nil {
			ei.ErrorString = ei.Error.Error()
		}
		eis[i] = ei
	}
}

func (eis ErrorInfos) GoodInputs() []string {
	inputs := []string{}
	for _, ei := range eis {
		if ei.Error == nil {
			inputs = append(inputs, ei.Input)
		}
	}
	return inputs
}

func (eis ErrorInfos) GoodCorrects() []string {
	inputs := []string{}
	for _, ei := range eis {
		if ei.Error == nil {
			inputs = append(inputs, ei.Correct)
		}
	}
	return inputs
}

func (eis ErrorInfos) ErrorsString() []string {
	estrings := []string{}
	for _, ei := range eis {
		if ei.Error != nil {
			estrings = append(estrings, ei.Error.Error())
		}
	}
	return estrings
}

func (eis ErrorInfos) Filter(isError bool) ErrorInfos {
	filtered := ErrorInfos{}
	for _, ei := range eis {
		if isError {
			if ei.Error != nil {
				filtered = append(filtered, ei)
			} else {
				filtered = append(filtered, nil)
			}
		} else if !isError {
			if ei.Error == nil {
				filtered = append(filtered, ei)
			} else {
				filtered = append(filtered, nil)
			}
		}
	}
	return filtered
}
<commit_msg>feat: errorsutil.ErrorsToStrings()<commit_after>package errorsutil

import (
	"errors"
	"fmt"
	"strings"
)

// Append adds additional text to an existing error.
func Append(err error, str string) error {
	return errors.New(fmt.Sprint(err) + str)
}

func Join(inclNils bool, errs ...error) error {
	strs := []string{}
	for _, err := range errs {
		if err == nil {
			if inclNils {
				strs = append(strs, "nil")
			}
		} else {
			strs = append(strs, err.Error())
		}
	}
	if len(strs) > 0 {
		return errors.New(strings.Join(strs, ";"))
	}
	return nil
}

// PanicOnErr is a syntactic sugar function to panic on error.
func PanicOnErr(err error) {
	if err != nil {
		panic(err)
	}
}

func ErrorsToStrings(errs []error) (int, []string) {
	strs := []string{}
	count := 0
	for _, err := range errs {
		if err != nil {
			strs = append(strs, err.Error())
			count += 1
		} else {
			strs = append(strs, "")
		}
	}
	return count, strs
}

type ErrorInfo struct {
	Error       error
	ErrorString string // must match Error
	Code        string
	Display     string
	Input       string
	Correct     string
}

type ErrorInfos []*ErrorInfo

func (eis ErrorInfos) Inflate() {
	for i, ei := range eis {
		if ei != nil && ei.Error != nil {
			ei.ErrorString = ei.Error.Error()
		}
		eis[i] = ei
	}
}

func (eis ErrorInfos) GoodInputs() []string {
	inputs := []string{}
	for _, ei := range eis {
		if ei.Error == nil {
			inputs = append(inputs, ei.Input)
		}
	}
	return inputs
}

func (eis ErrorInfos) GoodCorrects() []string {
	inputs := []string{}
	for _, ei := range eis {
		if ei.Error == nil {
			inputs = append(inputs, ei.Correct)
		}
	}
	return inputs
}

func (eis ErrorInfos) ErrorsString() []string {
	estrings := []string{}
	for _, ei := range eis {
		if ei.Error != nil {
			estrings = append(estrings, ei.Error.Error())
		}
	}
	return estrings
}

func (eis ErrorInfos) Filter(isError bool) ErrorInfos {
	filtered := ErrorInfos{}
	for _, ei := range eis {
		if isError {
			if ei.Error != nil {
				filtered = append(filtered, ei)
			} else {
				filtered = append(filtered, nil)
			}
		} else if !isError {
			if ei.Error == nil {
				filtered = append(filtered, ei)
			} else {
				filtered = append(filtered, nil)
			}
		}
	}
	return filtered
}
<|endoftext|>


<commit_before>/*
   Copyright The containerd 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 archive

import (
	"archive/tar"
	"context"
	"encoding/json"
	"io"
	"path"
	"sort"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/platforms"
	digest "github.com/opencontainers/go-digest"
	ocispecs "github.com/opencontainers/image-spec/specs-go"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

type exportOptions struct {
	manifests          []ocispec.Descriptor
	platform           platforms.MatchComparer
	allPlatforms       bool
	skipDockerManifest bool
}

// ExportOpt defines options for configuring exported descriptors
type ExportOpt func(context.Context, *exportOptions) error

// WithPlatform defines the platform to require manifest lists have
// not exporting all platforms.
// Additionally, platform is used to resolve image configs for
// Docker v1.1, v1.2 format compatibility.
func WithPlatform(p platforms.MatchComparer) ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		o.platform = p
		return nil
	}
}

// WithAllPlatforms exports all manifests from a manifest list.
// Missing content will fail the export.
func WithAllPlatforms() ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		o.allPlatforms = true
		return nil
	}
}

// WithSkipDockerManifest skips creation of the Docker compatible
// manifest.json file.
func WithSkipDockerManifest() ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		o.skipDockerManifest = true
		return nil
	}
}

// WithImage adds the provided images to the exported archive.
func WithImage(is images.Store, name string) ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		img, err := is.Get(ctx, name)
		if err != nil {
			return err
		}

		img.Target.Annotations = addNameAnnotation(name, img.Target.Annotations)
		o.manifests = append(o.manifests, img.Target)

		return nil
	}
}

// WithManifest adds a manifest to the exported archive.
// When names are given they will be set on the manifest in the
// exported archive, creating an index record for each name.
// When no names are provided, it is up to caller to put name annotation to
// on the manifest descriptor if needed.
func WithManifest(manifest ocispec.Descriptor, names ...string) ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		if len(names) == 0 {
			o.manifests = append(o.manifests, manifest)
		}
		for _, name := range names {
			mc := manifest
			mc.Annotations = addNameAnnotation(name, manifest.Annotations)
			o.manifests = append(o.manifests, mc)
		}

		return nil
	}
}

func addNameAnnotation(name string, base map[string]string) map[string]string {
	annotations := map[string]string{}
	for k, v := range base {
		annotations[k] = v
	}

	annotations[images.AnnotationImageName] = name
	annotations[ocispec.AnnotationRefName] = ociReferenceName(name)

	return annotations
}

// Export implements Exporter.
func Export(ctx context.Context, store content.Provider, writer io.Writer, opts ...ExportOpt) error {
	var eo exportOptions
	for _, opt := range opts {
		if err := opt(ctx, &eo); err != nil {
			return err
		}
	}

	records := []tarRecord{
		ociLayoutFile(""),
		ociIndexRecord(eo.manifests),
	}

	algorithms := map[string]struct{}{}
	dManifests := map[digest.Digest]*exportManifest{}
	resolvedIndex := map[digest.Digest]digest.Digest{}
	for _, desc := range eo.manifests {
		switch desc.MediaType {
		case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
			mt, ok := dManifests[desc.Digest]
			if !ok {
				// TODO(containerd): Skip if already added
				r, err := getRecords(ctx, store, desc, algorithms)
				if err != nil {
					return err
				}
				records = append(records, r...)

				mt = &exportManifest{
					manifest: desc,
				}
				dManifests[desc.Digest] = mt
			}

			name := desc.Annotations[images.AnnotationImageName]
			if name != "" && !eo.skipDockerManifest {
				mt.names = append(mt.names, name)
			}
		case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
			d, ok := resolvedIndex[desc.Digest]
			if !ok {
				records = append(records, blobRecord(store, desc))

				p, err := content.ReadBlob(ctx, store, desc)
				if err != nil {
					return err
				}

				var index ocispec.Index
				if err := json.Unmarshal(p, &index); err != nil {
					return err
				}

				var manifests []ocispec.Descriptor
				for _, m := range index.Manifests {
					if eo.platform != nil {
						if m.Platform == nil || eo.platform.Match(*m.Platform) {
							manifests = append(manifests, m)
						} else if !eo.allPlatforms {
							continue
						}
					}

					r, err := getRecords(ctx, store, m, algorithms)
					if err != nil {
						return err
					}

					records = append(records, r...)
				}

				if !eo.skipDockerManifest {
					if len(manifests) >= 1 {
						if len(manifests) > 1 {
							sort.SliceStable(manifests, func(i, j int) bool {
								if manifests[i].Platform == nil {
									return false
								}
								if manifests[j].Platform == nil {
									return true
								}
								return eo.platform.Less(*manifests[i].Platform, *manifests[j].Platform)
							})
						}
						d = manifests[0].Digest
						dManifests[d] = &exportManifest{
							manifest: manifests[0],
						}
					} else if eo.platform != nil {
						return errors.Wrap(errdefs.ErrNotFound, "no manifest found for platform")
					}
				}
				resolvedIndex[desc.Digest] = d
			}
			if d != "" {
				if name := desc.Annotations[images.AnnotationImageName]; name != "" {
					mt := dManifests[d]
					mt.names = append(mt.names, name)
				}

			}
		default:
			return errors.Wrap(errdefs.ErrInvalidArgument, "only manifests may be exported")
		}
	}

	if len(dManifests) > 0 {
		tr, err := manifestsRecord(ctx, store, dManifests)
		if err != nil {
			return errors.Wrap(err, "unable to create manifests file")
		}

		records = append(records, tr)
	}

	if len(algorithms) > 0 {
		records = append(records, directoryRecord("blobs/", 0755))
		for alg := range algorithms {
			records = append(records, directoryRecord("blobs/"+alg+"/", 0755))
		}
	}

	tw := tar.NewWriter(writer)
	defer tw.Close()
	return writeTar(ctx, tw, records)
}

func getRecords(ctx context.Context, store content.Provider, desc ocispec.Descriptor, algorithms map[string]struct{}) ([]tarRecord, error) {
	var records []tarRecord
	exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
		records = append(records, blobRecord(store, desc))
		algorithms[desc.Digest.Algorithm().String()] = struct{}{}
		return nil, nil
	}

	childrenHandler := images.ChildrenHandler(store)

	handlers := images.Handlers(
		childrenHandler,
		images.HandlerFunc(exportHandler),
	)

	// Walk sequentially since the number of fetchs is likely one and doing in
	// parallel requires locking the export handler
	if err := images.Walk(ctx, handlers, desc); err != nil {
		return nil, err
	}

	return records, nil
}

type tarRecord struct {
	Header *tar.Header
	CopyTo func(context.Context, io.Writer) (int64, error)
}

func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord {
	path := path.Join("blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded())
	return tarRecord{
		Header: &tar.Header{
			Name:     path,
			Mode:     0444,
			Size:     desc.Size,
			Typeflag: tar.TypeReg,
		},
		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
			r, err := cs.ReaderAt(ctx, desc)
			if err != nil {
				return 0, errors.Wrap(err, "failed to get reader")
			}
			defer r.Close()

			// Verify digest
			dgstr := desc.Digest.Algorithm().Digester()

			n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r))
			if err != nil {
				return 0, errors.Wrap(err, "failed to copy to tar")
			}
			if dgstr.Digest() != desc.Digest {
				return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest())
			}
			return n, nil
		},
	}
}

func directoryRecord(name string, mode int64) tarRecord {
	return tarRecord{
		Header: &tar.Header{
			Name:     name,
			Mode:     mode,
			Typeflag: tar.TypeDir,
		},
	}
}

func ociLayoutFile(version string) tarRecord {
	if version == "" {
		version = ocispec.ImageLayoutVersion
	}
	layout := ocispec.ImageLayout{
		Version: version,
	}

	b, err := json.Marshal(layout)
	if err != nil {
		panic(err)
	}

	return tarRecord{
		Header: &tar.Header{
			Name:     ocispec.ImageLayoutFile,
			Mode:     0444,
			Size:     int64(len(b)),
			Typeflag: tar.TypeReg,
		},
		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
			n, err := w.Write(b)
			return int64(n), err
		},
	}

}

func ociIndexRecord(manifests []ocispec.Descriptor) tarRecord {
	index := ocispec.Index{
		Versioned: ocispecs.Versioned{
			SchemaVersion: 2,
		},
		Manifests: manifests,
	}

	b, err := json.Marshal(index)
	if err != nil {
		panic(err)
	}

	return tarRecord{
		Header: &tar.Header{
			Name:     "index.json",
			Mode:     0644,
			Size:     int64(len(b)),
			Typeflag: tar.TypeReg,
		},
		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
			n, err := w.Write(b)
			return int64(n), err
		},
	}
}

type exportManifest struct {
	manifest ocispec.Descriptor
	names    []string
}

func manifestsRecord(ctx context.Context, store content.Provider, manifests map[digest.Digest]*exportManifest) (tarRecord, error) {
	mfsts := make([]struct {
		Config   string
		RepoTags []string
		Layers   []string
	}, len(manifests))

	var i int
	for _, m := range manifests {
		p, err := content.ReadBlob(ctx, store, m.manifest)
		if err != nil {
			return tarRecord{}, err
		}

		var manifest ocispec.Manifest
		if err := json.Unmarshal(p, &manifest); err != nil {
			return tarRecord{}, err
		}
		if err := manifest.Config.Digest.Validate(); err != nil {
			return tarRecord{}, errors.Wrapf(err, "invalid manifest %q", m.manifest.Digest)
		}

		dgst := manifest.Config.Digest
		mfsts[i].Config = path.Join("blobs", dgst.Algorithm().String(), dgst.Encoded())
		for _, l := range manifest.Layers {
			path := path.Join("blobs", l.Digest.Algorithm().String(), l.Digest.Encoded())
			mfsts[i].Layers = append(mfsts[i].Layers, path)
		}

		for _, name := range m.names {
			nname, err := familiarizeReference(name)
			if err != nil {
				return tarRecord{}, err
			}

			mfsts[i].RepoTags = append(mfsts[i].RepoTags, nname)
		}

		i++
	}

	b, err := json.Marshal(mfsts)
	if err != nil {
		return tarRecord{}, err
	}

	return tarRecord{
		Header: &tar.Header{
			Name:     "manifest.json",
			Mode:     0644,
			Size:     int64(len(b)),
			Typeflag: tar.TypeReg,
		},
		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
			n, err := w.Write(b)
			return int64(n), err
		},
	}, nil
}

func writeTar(ctx context.Context, tw *tar.Writer, records []tarRecord) error {
	sort.Slice(records, func(i, j int) bool {
		return records[i].Header.Name < records[j].Header.Name
	})

	var last string
	for _, record := range records {
		if record.Header.Name == last {
			continue
		}
		last = record.Header.Name
		if err := tw.WriteHeader(record.Header); err != nil {
			return err
		}
		if record.CopyTo != nil {
			n, err := record.CopyTo(ctx, tw)
			if err != nil {
				return err
			}
			if n != record.Header.Size {
				return errors.Errorf("unexpected copy size for %s", record.Header.Name)
			}
		} else if record.Header.Size > 0 {
			return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name)
		}
	}
	return nil
}
<commit_msg>Perfect documentations<commit_after>/*
   Copyright The containerd 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 archive

import (
	"archive/tar"
	"context"
	"encoding/json"
	"io"
	"path"
	"sort"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/platforms"
	digest "github.com/opencontainers/go-digest"
	ocispecs "github.com/opencontainers/image-spec/specs-go"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

type exportOptions struct {
	manifests          []ocispec.Descriptor
	platform           platforms.MatchComparer
	allPlatforms       bool
	skipDockerManifest bool
}

// ExportOpt defines options for configuring exported descriptors
type ExportOpt func(context.Context, *exportOptions) error

// WithPlatform defines the platform to require manifest lists have
// not exporting all platforms.
// Additionally, platform is used to resolve image configs for
// Docker v1.1, v1.2 format compatibility.
func WithPlatform(p platforms.MatchComparer) ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		o.platform = p
		return nil
	}
}

// WithAllPlatforms exports all manifests from a manifest list.
// Missing content will fail the export.
func WithAllPlatforms() ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		o.allPlatforms = true
		return nil
	}
}

// WithSkipDockerManifest skips creation of the Docker compatible
// manifest.json file.
func WithSkipDockerManifest() ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		o.skipDockerManifest = true
		return nil
	}
}

// WithImage adds the provided images to the exported archive.
func WithImage(is images.Store, name string) ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		img, err := is.Get(ctx, name)
		if err != nil {
			return err
		}

		img.Target.Annotations = addNameAnnotation(name, img.Target.Annotations)
		o.manifests = append(o.manifests, img.Target)

		return nil
	}
}

// WithManifest adds a manifest to the exported archive.
// When names are given they will be set on the manifest in the
// exported archive, creating an index record for each name.
// When no names are provided, it is up to caller to put name annotation to
// on the manifest descriptor if needed.
func WithManifest(manifest ocispec.Descriptor, names ...string) ExportOpt {
	return func(ctx context.Context, o *exportOptions) error {
		if len(names) == 0 {
			o.manifests = append(o.manifests, manifest)
		}
		for _, name := range names {
			mc := manifest
			mc.Annotations = addNameAnnotation(name, manifest.Annotations)
			o.manifests = append(o.manifests, mc)
		}

		return nil
	}
}

func addNameAnnotation(name string, base map[string]string) map[string]string {
	annotations := map[string]string{}
	for k, v := range base {
		annotations[k] = v
	}

	annotations[images.AnnotationImageName] = name
	annotations[ocispec.AnnotationRefName] = ociReferenceName(name)

	return annotations
}

// Export implements Exporter.
func Export(ctx context.Context, store content.Provider, writer io.Writer, opts ...ExportOpt) error {
	var eo exportOptions
	for _, opt := range opts {
		if err := opt(ctx, &eo); err != nil {
			return err
		}
	}

	records := []tarRecord{
		ociLayoutFile(""),
		ociIndexRecord(eo.manifests),
	}

	algorithms := map[string]struct{}{}
	dManifests := map[digest.Digest]*exportManifest{}
	resolvedIndex := map[digest.Digest]digest.Digest{}
	for _, desc := range eo.manifests {
		switch desc.MediaType {
		case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
			mt, ok := dManifests[desc.Digest]
			if !ok {
				// TODO(containerd): Skip if already added
				r, err := getRecords(ctx, store, desc, algorithms)
				if err != nil {
					return err
				}
				records = append(records, r...)

				mt = &exportManifest{
					manifest: desc,
				}
				dManifests[desc.Digest] = mt
			}

			name := desc.Annotations[images.AnnotationImageName]
			if name != "" && !eo.skipDockerManifest {
				mt.names = append(mt.names, name)
			}
		case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
			d, ok := resolvedIndex[desc.Digest]
			if !ok {
				records = append(records, blobRecord(store, desc))

				p, err := content.ReadBlob(ctx, store, desc)
				if err != nil {
					return err
				}

				var index ocispec.Index
				if err := json.Unmarshal(p, &index); err != nil {
					return err
				}

				var manifests []ocispec.Descriptor
				for _, m := range index.Manifests {
					if eo.platform != nil {
						if m.Platform == nil || eo.platform.Match(*m.Platform) {
							manifests = append(manifests, m)
						} else if !eo.allPlatforms {
							continue
						}
					}

					r, err := getRecords(ctx, store, m, algorithms)
					if err != nil {
						return err
					}

					records = append(records, r...)
				}

				if !eo.skipDockerManifest {
					if len(manifests) >= 1 {
						if len(manifests) > 1 {
							sort.SliceStable(manifests, func(i, j int) bool {
								if manifests[i].Platform == nil {
									return false
								}
								if manifests[j].Platform == nil {
									return true
								}
								return eo.platform.Less(*manifests[i].Platform, *manifests[j].Platform)
							})
						}
						d = manifests[0].Digest
						dManifests[d] = &exportManifest{
							manifest: manifests[0],
						}
					} else if eo.platform != nil {
						return errors.Wrap(errdefs.ErrNotFound, "no manifest found for platform")
					}
				}
				resolvedIndex[desc.Digest] = d
			}
			if d != "" {
				if name := desc.Annotations[images.AnnotationImageName]; name != "" {
					mt := dManifests[d]
					mt.names = append(mt.names, name)
				}

			}
		default:
			return errors.Wrap(errdefs.ErrInvalidArgument, "only manifests may be exported")
		}
	}

	if len(dManifests) > 0 {
		tr, err := manifestsRecord(ctx, store, dManifests)
		if err != nil {
			return errors.Wrap(err, "unable to create manifests file")
		}

		records = append(records, tr)
	}

	if len(algorithms) > 0 {
		records = append(records, directoryRecord("blobs/", 0755))
		for alg := range algorithms {
			records = append(records, directoryRecord("blobs/"+alg+"/", 0755))
		}
	}

	tw := tar.NewWriter(writer)
	defer tw.Close()
	return writeTar(ctx, tw, records)
}

func getRecords(ctx context.Context, store content.Provider, desc ocispec.Descriptor, algorithms map[string]struct{}) ([]tarRecord, error) {
	var records []tarRecord
	exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
		records = append(records, blobRecord(store, desc))
		algorithms[desc.Digest.Algorithm().String()] = struct{}{}
		return nil, nil
	}

	childrenHandler := images.ChildrenHandler(store)

	handlers := images.Handlers(
		childrenHandler,
		images.HandlerFunc(exportHandler),
	)

	// Walk sequentially since the number of fetches is likely one and doing in
	// parallel requires locking the export handler
	if err := images.Walk(ctx, handlers, desc); err != nil {
		return nil, err
	}

	return records, nil
}

type tarRecord struct {
	Header *tar.Header
	CopyTo func(context.Context, io.Writer) (int64, error)
}

func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord {
	path := path.Join("blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded())
	return tarRecord{
		Header: &tar.Header{
			Name:     path,
			Mode:     0444,
			Size:     desc.Size,
			Typeflag: tar.TypeReg,
		},
		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
			r, err := cs.ReaderAt(ctx, desc)
			if err != nil {
				return 0, errors.Wrap(err, "failed to get reader")
			}
			defer r.Close()

			// Verify digest
			dgstr := desc.Digest.Algorithm().Digester()

			n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r))
			if err != nil {
				return 0, errors.Wrap(err, "failed to copy to tar")
			}
			if dgstr.Digest() != desc.Digest {
				return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest())
			}
			return n, nil
		},
	}
}

func directoryRecord(name string, mode int64) tarRecord {
	return tarRecord{
		Header: &tar.Header{
			Name:     name,
			Mode:     mode,
			Typeflag: tar.TypeDir,
		},
	}
}

func ociLayoutFile(version string) tarRecord {
	if version == "" {
		version = ocispec.ImageLayoutVersion
	}
	layout := ocispec.ImageLayout{
		Version: version,
	}

	b, err := json.Marshal(layout)
	if err != nil {
		panic(err)
	}

	return tarRecord{
		Header: &tar.Header{
			Name:     ocispec.ImageLayoutFile,
			Mode:     0444,
			Size:     int64(len(b)),
			Typeflag: tar.TypeReg,
		},
		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
			n, err := w.Write(b)
			return int64(n), err
		},
	}

}

func ociIndexRecord(manifests []ocispec.Descriptor) tarRecord {
	index := ocispec.Index{
		Versioned: ocispecs.Versioned{
			SchemaVersion: 2,
		},
		Manifests: manifests,
	}

	b, err := json.Marshal(index)
	if err != nil {
		panic(err)
	}

	return tarRecord{
		Header: &tar.Header{
			Name:     "index.json",
			Mode:     0644,
			Size:     int64(len(b)),
			Typeflag: tar.TypeReg,
		},
		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
			n, err := w.Write(b)
			return int64(n), err
		},
	}
}

type exportManifest struct {
	manifest ocispec.Descriptor
	names    []string
}

func manifestsRecord(ctx context.Context, store content.Provider, manifests map[digest.Digest]*exportManifest) (tarRecord, error) {
	mfsts := make([]struct {
		Config   string
		RepoTags []string
		Layers   []string
	}, len(manifests))

	var i int
	for _, m := range manifests {
		p, err := content.ReadBlob(ctx, store, m.manifest)
		if err != nil {
			return tarRecord{}, err
		}

		var manifest ocispec.Manifest
		if err := json.Unmarshal(p, &manifest); err != nil {
			return tarRecord{}, err
		}
		if err := manifest.Config.Digest.Validate(); err != nil {
			return tarRecord{}, errors.Wrapf(err, "invalid manifest %q", m.manifest.Digest)
		}

		dgst := manifest.Config.Digest
		mfsts[i].Config = path.Join("blobs", dgst.Algorithm().String(), dgst.Encoded())
		for _, l := range manifest.Layers {
			path := path.Join("blobs", l.Digest.Algorithm().String(), l.Digest.Encoded())
			mfsts[i].Layers = append(mfsts[i].Layers, path)
		}

		for _, name := range m.names {
			nname, err := familiarizeReference(name)
			if err != nil {
				return tarRecord{}, err
			}

			mfsts[i].RepoTags = append(mfsts[i].RepoTags, nname)
		}

		i++
	}

	b, err := json.Marshal(mfsts)
	if err != nil {
		return tarRecord{}, err
	}

	return tarRecord{
		Header: &tar.Header{
			Name:     "manifest.json",
			Mode:     0644,
			Size:     int64(len(b)),
			Typeflag: tar.TypeReg,
		},
		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
			n, err := w.Write(b)
			return int64(n), err
		},
	}, nil
}

func writeTar(ctx context.Context, tw *tar.Writer, records []tarRecord) error {
	sort.Slice(records, func(i, j int) bool {
		return records[i].Header.Name < records[j].Header.Name
	})

	var last string
	for _, record := range records {
		if record.Header.Name == last {
			continue
		}
		last = record.Header.Name
		if err := tw.WriteHeader(record.Header); err != nil {
			return err
		}
		if record.CopyTo != nil {
			n, err := record.CopyTo(ctx, tw)
			if err != nil {
				return err
			}
			if n != record.Header.Size {
				return errors.Errorf("unexpected copy size for %s", record.Header.Name)
			}
		} else if record.Header.Size > 0 {
			return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name)
		}
	}
	return nil
}
<|endoftext|>


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

package mat64

import (
	"math"
	"math/rand"
	"testing"

	"gopkg.in/check.v1"
)

func (s *S) TestPool(c *check.C) {
	for i := 1; i < 10; i++ {
		for j := 1; j < 10; j++ {
			var w, m *Dense
			for k := 0; k < 5; k++ {
				w = getWorkspace(i, j, true)
				m = NewDense(i, j, nil)
				c.Check(w.mat, check.DeepEquals, m.mat)
				c.Check(w.capRows, check.DeepEquals, m.capRows)
				c.Check(w.capCols, check.DeepEquals, m.capCols)
				c.Check(cap(w.mat.Data) < 2*len(w.mat.Data), check.Equals, true, check.Commentf("r: %d c: %d -> len: %d cap: %d", i, j, len(w.mat.Data), cap(w.mat.Data)))
			}
			w.Set(0, 0, math.NaN())
			for k := 0; k < 5; k++ {
				putWorkspace(w)
			}
			for k := 0; k < 5; k++ {
				w = getWorkspace(i, j, true)
				m = NewDense(i, j, nil)
				c.Check(w.mat, check.DeepEquals, m.mat)
				c.Check(w.capRows, check.DeepEquals, m.capRows)
				c.Check(w.capCols, check.DeepEquals, m.capCols)
				c.Check(cap(w.mat.Data) < 2*len(w.mat.Data), check.Equals, true, check.Commentf("r: %d c: %d -> len: %d cap: %d", i, j, len(w.mat.Data), cap(w.mat.Data)))
			}
		}
	}
}

var benchmat *Dense

func poolBenchmark(n, r, c int, clear bool) {
	for i := 0; i < n; i++ {
		benchmat = getWorkspace(r, c, clear)
		putWorkspace(benchmat)
	}
}

func newBenchmark(n, r, c int) {
	for i := 0; i < n; i++ {
		benchmat = NewDense(r, c, nil)
	}
}

func BenchmarkPool10by10Uncleared(b *testing.B)   { poolBenchmark(b.N, 10, 10, false) }
func BenchmarkPool10by10Cleared(b *testing.B)     { poolBenchmark(b.N, 10, 10, true) }
func BenchmarkNew10by10(b *testing.B)             { newBenchmark(b.N, 10, 10) }
func BenchmarkPool100by100Uncleared(b *testing.B) { poolBenchmark(b.N, 100, 100, false) }
func BenchmarkPool100by100Cleared(b *testing.B)   { poolBenchmark(b.N, 100, 100, true) }
func BenchmarkNew100by100(b *testing.B)           { newBenchmark(b.N, 100, 100) }

func BenchmarkMulWorkspaceDense100Half(b *testing.B)        { denseMulWorkspaceBench(b, 100, 0.5) }
func BenchmarkMulWorkspaceDense100Tenth(b *testing.B)       { denseMulWorkspaceBench(b, 100, 0.1) }
func BenchmarkMulWorkspaceDense1000Half(b *testing.B)       { denseMulWorkspaceBench(b, 1000, 0.5) }
func BenchmarkMulWorkspaceDense1000Tenth(b *testing.B)      { denseMulWorkspaceBench(b, 1000, 0.1) }
func BenchmarkMulWorkspaceDense1000Hundredth(b *testing.B)  { denseMulWorkspaceBench(b, 1000, 0.01) }
func BenchmarkMulWorkspaceDense1000Thousandth(b *testing.B) { denseMulWorkspaceBench(b, 1000, 0.001) }
func denseMulWorkspaceBench(b *testing.B, size int, rho float64) {
	b.StopTimer()
	a, _ := randDense(size, rho, rand.NormFloat64)
	d, _ := randDense(size, rho, rand.NormFloat64)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		a.Mul(a, d)
	}
}
<commit_msg>mat64: refactor pool tests<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mat64

import (
	"math"
	"math/rand"
	"reflect"
	"testing"

	"gopkg.in/check.v1"
)

func (s *S) TestPool(c *check.C) {
	for i := 1; i < 10; i++ {
		for j := 1; j < 10; j++ {
			m := NewDense(i, j, nil)
			for k := 0; k < 5; k++ {
				work := make([]*Dense, rand.Intn(10)+1)
				for l := range work {
					w := getWorkspace(i, j, true)
					if !reflect.DeepEqual(w.mat, m.mat) {
						c.Error("unexpected non-zeroed matrix returned by getWorkspace")
					}
					if w.capRows != m.capRows {
						c.Error("unexpected capacity matrix returned by getWorkspace")
					}
					if w.capCols != m.capCols {
						c.Error("unexpected capacity matrix returned by getWorkspace")
					}
					if cap(w.mat.Data) >= 2*len(w.mat.Data) {
						c.Errorf("r: %d c: %d -> len: %d cap: %d", i, j, len(w.mat.Data), cap(w.mat.Data))
					}
					w.Set(0, 0, math.NaN())
					work[l] = w
				}
				for _, w := range work {
					putWorkspace(w)
				}
			}
		}
	}
}

var benchmat *Dense

func poolBenchmark(n, r, c int, clear bool) {
	for i := 0; i < n; i++ {
		benchmat = getWorkspace(r, c, clear)
		putWorkspace(benchmat)
	}
}

func newBenchmark(n, r, c int) {
	for i := 0; i < n; i++ {
		benchmat = NewDense(r, c, nil)
	}
}

func BenchmarkPool10by10Uncleared(b *testing.B)   { poolBenchmark(b.N, 10, 10, false) }
func BenchmarkPool10by10Cleared(b *testing.B)     { poolBenchmark(b.N, 10, 10, true) }
func BenchmarkNew10by10(b *testing.B)             { newBenchmark(b.N, 10, 10) }
func BenchmarkPool100by100Uncleared(b *testing.B) { poolBenchmark(b.N, 100, 100, false) }
func BenchmarkPool100by100Cleared(b *testing.B)   { poolBenchmark(b.N, 100, 100, true) }
func BenchmarkNew100by100(b *testing.B)           { newBenchmark(b.N, 100, 100) }

func BenchmarkMulWorkspaceDense100Half(b *testing.B)        { denseMulWorkspaceBench(b, 100, 0.5) }
func BenchmarkMulWorkspaceDense100Tenth(b *testing.B)       { denseMulWorkspaceBench(b, 100, 0.1) }
func BenchmarkMulWorkspaceDense1000Half(b *testing.B)       { denseMulWorkspaceBench(b, 1000, 0.5) }
func BenchmarkMulWorkspaceDense1000Tenth(b *testing.B)      { denseMulWorkspaceBench(b, 1000, 0.1) }
func BenchmarkMulWorkspaceDense1000Hundredth(b *testing.B)  { denseMulWorkspaceBench(b, 1000, 0.01) }
func BenchmarkMulWorkspaceDense1000Thousandth(b *testing.B) { denseMulWorkspaceBench(b, 1000, 0.001) }
func denseMulWorkspaceBench(b *testing.B, size int, rho float64) {
	b.StopTimer()
	a, _ := randDense(size, rho, rand.NormFloat64)
	d, _ := randDense(size, rho, rand.NormFloat64)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		a.Mul(a, d)
	}
}
<|endoftext|>


<commit_before>// nmon2influxdb
// import nmon report in InfluxDB
// author: adejoux@djouxtech.net

package main

import (
	"bufio"
	"fmt"
	"github.com/adejoux/influxdbclient"
	"github.com/codegangsta/cli"
	"os"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

var hostRegexp = regexp.MustCompile(`^AAA,host,(\S+)`)
var timeRegexp = regexp.MustCompile(`^ZZZZ,([^,]+),(.*)$`)
var intervalRegexp = regexp.MustCompile(`^AAA,interval,(\d+)`)
var headerRegexp = regexp.MustCompile(`^AAA|^BBB|^UARG|^TOP|,T\d`)
var infoRegexp = regexp.MustCompile(`AAA,(.*)`)
var cpuallRegexp = regexp.MustCompile(`^CPU\d+|^SCPU\d+|^PCPU\d+`)
var diskallRegexp = regexp.MustCompile(`^DISK`)
var skipRegexp = regexp.MustCompile(`T0000|^TOP`)
var statsRegexp = regexp.MustCompile(`[^Z]+,(T\d+)`)
var nfsRegexp = regexp.MustCompile(`^NFS`)
var nameRegexp = regexp.MustCompile(`(\d+)$`)

func NmonImport(c *cli.Context) {

	if len(c.Args()) < 1 {
		fmt.Printf("file name needs to be provided\n")
		os.Exit(1)
	}
	// parsing parameters
	params := ParseParameters(c)

	nmon := InitNmon(params)

	influxdb := influxdbclient.NewInfluxDB(params.Server, params.Port, params.Db, params.User, params.Password)
	nmon.Debug = params.Debug
	influxdb.SetDebug(params.Debug)

	influxdb.Connect()

	if exist, _ := influxdb.ExistDB(params.Db); exist != true {
		_, err := influxdb.CreateDB(params.Db)
		check(err)
	}

	file, err := os.Open(params.Name)
	check(err)

	defer file.Close()
	reader := bufio.NewReader(file)
	scanner := bufio.NewScanner(reader)
	scanner.Split(bufio.ScanLines)

	var lines []string

	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	sort.Strings(lines)

	for _, line := range lines {

		if cpuallRegexp.MatchString(line) && !params.CpuAll {
			continue
		}

		if diskallRegexp.MatchString(line) && params.NoDisks {
			continue
		}

		if skipRegexp.MatchString(line) {
			continue
		}

		if statsRegexp.MatchString(line) {
			matched := statsRegexp.FindStringSubmatch(line)
			elems := strings.Split(line, ",")
			timeStr, err := nmon.GetTimeStamp(matched[1])
			check(err)
			name := elems[0]
			timestamp, err := ConvertTimeStamp(timeStr, nmon.Params.TZ)

			for i, value := range elems[2:] {
				tags := map[string]string{"host": nmon.Hostname, "name": nmon.DataSeries[name].Columns[i]}

				// try to convert string to integer
				converted, err := strconv.ParseFloat(value, 64)
				if err != nil {
					//if not working, skip to next value. We don't want text values in InfluxDB.
					continue
				}

				//send integer if it worked
				field := map[string]interface{}{"value": converted}

				measurement := ""
				if nfsRegexp.MatchString(name) {
					measurement = name
				} else {
					measurement = nameRegexp.ReplaceAllString(name, "")
				}

				influxdb.AddPoint(measurement, timestamp, field, tags)

				if influxdb.PointsCount() == 10000 {
					err = influxdb.WritePoints()
					check(err)
					influxdb.ClearPoints()
					fmt.Printf("#")
				}
			}
		}
	}
	// flushing remaining data
	influxdb.WritePoints()
	fmt.Printf("#\n")

	fmt.Printf("File %s imported !\n", params.Name)
}
<commit_msg>fix import bug when new entries are detected<commit_after>// nmon2influxdb
// import nmon report in InfluxDB
// author: adejoux@djouxtech.net

package main

import (
	"bufio"
	"fmt"
	"github.com/adejoux/influxdbclient"
	"github.com/codegangsta/cli"
	"os"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

var hostRegexp = regexp.MustCompile(`^AAA,host,(\S+)`)
var timeRegexp = regexp.MustCompile(`^ZZZZ,([^,]+),(.*)$`)
var intervalRegexp = regexp.MustCompile(`^AAA,interval,(\d+)`)
var headerRegexp = regexp.MustCompile(`^AAA|^BBB|^UARG|^TOP|,T\d`)
var infoRegexp = regexp.MustCompile(`AAA,(.*)`)
var cpuallRegexp = regexp.MustCompile(`^CPU\d+|^SCPU\d+|^PCPU\d+`)
var diskallRegexp = regexp.MustCompile(`^DISK`)
var skipRegexp = regexp.MustCompile(`T0000|^TOP`)
var statsRegexp = regexp.MustCompile(`[^Z]+,(T\d+)`)
var nfsRegexp = regexp.MustCompile(`^NFS`)
var nameRegexp = regexp.MustCompile(`(\d+)$`)

func NmonImport(c *cli.Context) {

	if len(c.Args()) < 1 {
		fmt.Printf("file name needs to be provided\n")
		os.Exit(1)
	}
	// parsing parameters
	params := ParseParameters(c)

	nmon := InitNmon(params)

	influxdb := influxdbclient.NewInfluxDB(params.Server, params.Port, params.Db, params.User, params.Password)
	nmon.Debug = params.Debug
	influxdb.SetDebug(params.Debug)

	influxdb.Connect()

	if exist, _ := influxdb.ExistDB(params.Db); exist != true {
		_, err := influxdb.CreateDB(params.Db)
		check(err)
	}

	file, err := os.Open(params.Name)
	check(err)

	defer file.Close()
	reader := bufio.NewReader(file)
	scanner := bufio.NewScanner(reader)
	scanner.Split(bufio.ScanLines)

	var lines []string

	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	sort.Strings(lines)

	for _, line := range lines {

		if cpuallRegexp.MatchString(line) && !params.CpuAll {
			continue
		}

		if diskallRegexp.MatchString(line) && params.NoDisks {
			continue
		}

		if skipRegexp.MatchString(line) {
			continue
		}

		if statsRegexp.MatchString(line) {
			matched := statsRegexp.FindStringSubmatch(line)
			elems := strings.Split(line, ",")
			timeStr, err := nmon.GetTimeStamp(matched[1])
			check(err)
			name := elems[0]
			timestamp, err := ConvertTimeStamp(timeStr, nmon.Params.TZ)

			for i, value := range elems[2:] {
				if len(nmon.DataSeries[name].Columns) < i+1 {
					if nmon.Debug {
						fmt.Printf("Entry added position %d in serie %s since nmon start: skipped\n", i+1, name)
					}
					continue
				}
				tags := map[string]string{"host": nmon.Hostname, "name": nmon.DataSeries[name].Columns[i]}

				// try to convert string to integer
				converted, err := strconv.ParseFloat(value, 64)
				if err != nil {
					//if not working, skip to next value. We don't want text values in InfluxDB.
					continue
				}

				//send integer if it worked
				field := map[string]interface{}{"value": converted}

				measurement := ""
				if nfsRegexp.MatchString(name) {
					measurement = name
				} else {
					measurement = nameRegexp.ReplaceAllString(name, "")
				}

				influxdb.AddPoint(measurement, timestamp, field, tags)

				if influxdb.PointsCount() == 10000 {
					err = influxdb.WritePoints()
					check(err)
					influxdb.ClearPoints()
					fmt.Printf("#")
				}
			}
		}
	}
	// flushing remaining data
	influxdb.WritePoints()
	fmt.Printf("#\n")

	fmt.Printf("File %s imported !\n", params.Name)
}
<|endoftext|>


<commit_before>package builder

import (
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/tsaikd/KDGoLib/cliutil/cmdutil"
	"github.com/tsaikd/KDGoLib/version"
)

func init() {
	version.VERSION = "0.0.3"

	cmdutil.AddCommand(cli.Command{
		Name:   "version",
		Usage:  "Show version detail",
		Action: actionWrapper(versionAction),
	})
}

func versionAction(c *cli.Context) (err error) {
	verjson, err := version.Json()
	if err != nil {
		return
	}
	fmt.Println(verjson)
	return
}
<commit_msg>0.0.4<commit_after>package builder

import (
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/tsaikd/KDGoLib/cliutil/cmdutil"
	"github.com/tsaikd/KDGoLib/version"
)

func init() {
	version.VERSION = "0.0.4"

	cmdutil.AddCommand(cli.Command{
		Name:   "version",
		Usage:  "Show version detail",
		Action: actionWrapper(versionAction),
	})
}

func versionAction(c *cli.Context) (err error) {
	verjson, err := version.Json()
	if err != nil {
		return
	}
	fmt.Println(verjson)
	return
}
<|endoftext|>


<commit_before>// +build static,!system_libgit2

package git

/*
#cgo windows CFLAGS: -I${SRCDIR}/static-build/install/include/
#cgo windows LDFLAGS: -L${SRCDIR}/static-build/install/lib/ -lgit2 -lwinhttp
#cgo !windows pkg-config: --static ${SRCDIR}/static-build/install/lib/pkgconfig/libgit2.pc
#cgo CFLAGS: -DLIBGIT2_STATIC
#include <git2.h>

#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 1 || LIBGIT2_VER_MINOR > 1
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.1.0 and v1.1.0"
#endif
*/
import "C"
<commit_msg>fix buldled static build on Windows/MinGW (#761)<commit_after>// +build static,!system_libgit2

package git

/*
#cgo windows CFLAGS: -I${SRCDIR}/static-build/install/include/
#cgo windows LDFLAGS: -L${SRCDIR}/static-build/install/lib/ -lgit2 -lwinhttp -lws2_32 -lole32 -lrpcrt4 -lcrypt32
#cgo !windows pkg-config: --static ${SRCDIR}/static-build/install/lib/pkgconfig/libgit2.pc
#cgo CFLAGS: -DLIBGIT2_STATIC
#include <git2.h>

#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 1 || LIBGIT2_VER_MINOR > 1
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.1.0 and v1.1.0"
#endif
*/
import "C"
<|endoftext|>


<commit_before>package context

import (
	"io"
	"strings"
	"testing"

	"github.com/spf13/afero"
	"github.com/stretchr/testify/assert"
)

type testFile struct {
	Path    string
	Content io.Reader
}

func TestAcquireMainLanguageForFile(t *testing.T) {
	testCases := []struct {
		name           string
		withFile       testFile
		expectLanguage string
	}{
		{
			name: "Should work with golang files",
			withFile: testFile{
				Path:    "/main.go",
				Content: strings.NewReader("package main\nfunc main() {}"),
			},
			expectLanguage: "golang",
		},
		{
			name: "Should work with java files",
			withFile: testFile{
				Path:    "/main.java",
				Content: strings.NewReader("public static void main() {}"),
			},
			expectLanguage: "java",
		},
	}

	for _, tc := range testCases {
		tc := tc

		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			fs := &afero.Afero{Fs: afero.NewMemMapFs()}

			fs.WriteReader(tc.withFile.Path, tc.withFile.Content)

			language, err := acquireMainLanguageForFile(fs, tc.withFile.Path)
			assert.NoError(t, err)

			assert.Equal(t, tc.expectLanguage, language)
		})
	}
}
<commit_msg>✅ Add failing main language for dir tests<commit_after>package context

import (
	"io"
	"strings"
	"testing"

	"github.com/spf13/afero"
	"github.com/stretchr/testify/assert"
)

type testFile struct {
	Path    string
	Content io.Reader
}

func TestAcquireMainLanguageForFile(t *testing.T) {
	testCases := []struct {
		name           string
		withFile       testFile
		expectLanguage string
	}{
		{
			name: "Should work with golang files",
			withFile: testFile{
				Path:    "/main.go",
				Content: strings.NewReader("package main\nfunc main() {}"),
			},
			expectLanguage: "golang",
		},
		{
			name: "Should work with java files",
			withFile: testFile{
				Path:    "/main.java",
				Content: strings.NewReader("public static void main() {}"),
			},
			expectLanguage: "java",
		},
	}

	for _, tc := range testCases {
		tc := tc

		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			fs := &afero.Afero{Fs: afero.NewMemMapFs()}

			fs.WriteReader(tc.withFile.Path, tc.withFile.Content)

			language, err := acquireMainLanguageForFile(fs, tc.withFile.Path)
			assert.NoError(t, err)

			assert.Equal(t, tc.expectLanguage, language)
		})
	}
}

func TestAcquireMainLanguageForDir(t *testing.T) {
	testCases := []struct {
		name           string
		withFiles      []testFile
		expectLanguage string
	}{
		{
			name: "Should return golang with only golang files",
			withFiles: []testFile{
				{
					Path:    "/main.go",
					Content: strings.NewReader("package main"),
				},
				{
					Path:    "/tests.go",
					Content: strings.NewReader("package main"),
				},
				{
					Path:    "/types.go",
					Content: strings.NewReader("package main"),
				},
			},
			expectLanguage: "golang",
		},
		{
			name: "Should return golang with mostly golang files",
			withFiles: []testFile{
				{
					Path:    "/main.go",
					Content: strings.NewReader("package main"),
				},
				{
					Path:    "/tests.go",
					Content: strings.NewReader("package main"),
				},
				{
					Path:    "/Makefile",
					Content: strings.NewReader(".PHONY: all"),
				},
			},
			expectLanguage: "golang",
		},
		{
			name: "Should return golang with 3/5 files being golang",
			withFiles: []testFile{
				{
					Path:    "/monitor.java",
					Content: strings.NewReader("public static void main() {}"),
				},
				{
					Path:    "/main.go",
					Content: strings.NewReader("package main"),
				},
				{
					Path:    "/tests.go",
					Content: strings.NewReader("package main"),
				},
				{
					Path:    "/types.go",
					Content: strings.NewReader("package main"),
				},
				{
					Path:    "/lib.java",
					Content: strings.NewReader("public static void main() {}"),
				},
			},
			expectLanguage: "golang",
		},
	}

	for _, tc := range testCases {
		tc := tc

		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			fs := &afero.Afero{Fs: afero.NewMemMapFs()}

			for _, item := range tc.withFiles {
				err := fs.WriteReader(item.Path, item.Content)
				assert.NoError(t, err)
			}

			language, err := acquireMainLanguageForDir(fs, "/")
			assert.NoError(t, err)

			assert.Equal(t, tc.expectLanguage, language)
		})
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative 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 resources

import (
	"context"
	"errors"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/apimachinery/pkg/util/sets"

	network "knative.dev/networking/pkg"
	"knative.dev/networking/pkg/apis/networking"
	netv1alpha1 "knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/pkg/kmeta"
	"knative.dev/serving/pkg/apis/serving"
	v1 "knative.dev/serving/pkg/apis/serving/v1"
	"knative.dev/serving/pkg/reconciler/route/domains"
)

var errLoadBalancerNotFound = errors.New("failed to fetch loadbalancer domain/IP from ingress status")

// GetNames returns a set of service names.
func GetNames(services []*corev1.Service) sets.String {
	names := make(sets.String, len(services))

	for i := range services {
		names.Insert(services[i].Name)
	}

	return names
}

// SelectorFromRoute creates a label selector given a specific route.
func SelectorFromRoute(route *v1.Route) labels.Selector {
	return labels.SelectorFromSet(labels.Set{serving.RouteLabelKey: route.Name})
}

// MakeK8sPlaceholderService creates a placeholder Service to prevent naming collisions. It's owned by the
// provided v1.Route.
func MakeK8sPlaceholderService(ctx context.Context, route *v1.Route, targetName string) (*corev1.Service, error) {
	hostname, err := domains.HostnameFromTemplate(ctx, route.Name, targetName)
	if err != nil {
		return nil, err
	}
	fullName, err := domains.DomainNameFromTemplate(ctx, route.ObjectMeta, hostname)
	if err != nil {
		return nil, err
	}

	service, err := makeK8sService(ctx, route, targetName)
	if err != nil {
		return nil, err
	}
	service.Spec = corev1.ServiceSpec{
		Type:            corev1.ServiceTypeExternalName,
		ExternalName:    fullName,
		SessionAffinity: corev1.ServiceAffinityNone,
		Ports: []corev1.ServicePort{{
			Name:       networking.ServicePortNameH2C,
			Port:       int32(80),
			TargetPort: intstr.FromInt(80),
		}},
	}

	return service, nil
}

// MakeK8sService creates a Service that redirect to the loadbalancer specified
// in Ingress status. It's owned by the provided v1.Route.
func MakeK8sService(ctx context.Context, route *v1.Route, targetName string, ingress *netv1alpha1.Ingress, isPrivate bool, clusterIP string) (*corev1.Service, error) {
	svcSpec, err := makeServiceSpec(ingress, isPrivate, clusterIP)
	if err != nil {
		return nil, err
	}

	service, err := makeK8sService(ctx, route, targetName)
	if err != nil {
		return nil, err
	}
	service.Spec = *svcSpec
	return service, nil
}

func makeK8sService(ctx context.Context, route *v1.Route, targetName string) (*corev1.Service, error) {
	hostname, err := domains.HostnameFromTemplate(ctx, route.Name, targetName)
	if err != nil {
		return nil, err
	}

	svcLabels := map[string]string{
		serving.RouteLabelKey: route.Name,
	}

	return &corev1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:      hostname,
			Namespace: route.Namespace,
			OwnerReferences: []metav1.OwnerReference{
				// This service is owned by the Route.
				*kmeta.NewControllerRef(route),
			},
			Labels: kmeta.UnionMaps(kmeta.FilterMap(route.GetLabels(), func(key string) bool {
				// Do not propagate the visibility label from Route as users may want to set the label
				// in the specific k8s svc for subroute. see https://github.com/knative/serving/pull/4560.
				return key == network.VisibilityLabelKey
			}), svcLabels),
			Annotations: route.GetAnnotations(),
		},
	}, nil
}

func makeServiceSpec(ingress *netv1alpha1.Ingress, isPrivate bool, clusterIP string) (*corev1.ServiceSpec, error) {
	ingressStatus := ingress.Status

	lbStatus := ingressStatus.PublicLoadBalancer
	if isPrivate || ingressStatus.PrivateLoadBalancer != nil {
		// Always use private load balancer if it exists,
		// because k8s service is only useful for inter-cluster communication.
		// External communication will be handle via ingress gateway, which won't be affected by what is configured here.
		lbStatus = ingressStatus.PrivateLoadBalancer
	}

	if lbStatus == nil || len(lbStatus.Ingress) == 0 {
		return nil, errLoadBalancerNotFound
	}
	if len(lbStatus.Ingress) > 1 {
		// Return error as we only support one LoadBalancer currently.
		return nil, errors.New(
			"more than one ingress are specified in status(LoadBalancer) of Ingress " + ingress.GetName())
	}
	balancer := lbStatus.Ingress[0]

	// Here we decide LoadBalancer information in the order of
	// DomainInternal > Domain > LoadBalancedIP to prioritize cluster-local,
	// and domain (since it would change less than IP).
	switch {
	case balancer.DomainInternal != "":
		return &corev1.ServiceSpec{
			Type:            corev1.ServiceTypeExternalName,
			ExternalName:    balancer.DomainInternal,
			SessionAffinity: corev1.ServiceAffinityNone,
			Ports: []corev1.ServicePort{{
				Name:       networking.ServicePortNameH2C,
				Port:       int32(80),
				TargetPort: intstr.FromInt(80),
			}},
		}, nil
	case balancer.Domain != "":
		return &corev1.ServiceSpec{
			Type:         corev1.ServiceTypeExternalName,
			ExternalName: balancer.Domain,
			Ports: []corev1.ServicePort{{
				Name:       networking.ServicePortNameH2C,
				Port:       int32(80),
				TargetPort: intstr.FromInt(80),
			}},
		}, nil
	case balancer.MeshOnly:
		// The Ingress is loadbalanced through a Service mesh.
		// We won't have a specific LB endpoint to route traffic to,
		// but we still need to create a ClusterIP service to make
		// sure the domain name is available for access within the
		// mesh.
		return &corev1.ServiceSpec{
			Type:      corev1.ServiceTypeClusterIP,
			ClusterIP: clusterIP,
			Ports: []corev1.ServicePort{{
				Name: networking.ServicePortNameHTTP1,
				Port: networking.ServiceHTTPPort,
			}},
		}, nil
	case balancer.IP != "":
		// TODO(lichuqiang): deal with LoadBalancer IP.
		// We'll also need ports info to make it take effect.
	}
	return nil, errLoadBalancerNotFound
}
<commit_msg>Fix the helpers in the service to be more readable. (#10833)<commit_after>/*
Copyright 2018 The Knative 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 resources

import (
	"context"
	"errors"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/apimachinery/pkg/util/sets"

	network "knative.dev/networking/pkg"
	"knative.dev/networking/pkg/apis/networking"
	netv1alpha1 "knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/pkg/kmeta"
	"knative.dev/serving/pkg/apis/serving"
	v1 "knative.dev/serving/pkg/apis/serving/v1"
	"knative.dev/serving/pkg/reconciler/route/domains"
)

var errLoadBalancerNotFound = errors.New("failed to fetch loadbalancer domain/IP from ingress status")

// GetNames returns a set of service names.
func GetNames(services []*corev1.Service) sets.String {
	names := make(sets.String, len(services))

	for i := range services {
		names.Insert(services[i].Name)
	}

	return names
}

// SelectorFromRoute creates a label selector given a specific route.
func SelectorFromRoute(route *v1.Route) labels.Selector {
	return labels.SelectorFromSet(labels.Set{serving.RouteLabelKey: route.Name})
}

// MakeK8sPlaceholderService creates a placeholder Service to prevent naming collisions. It's owned by the
// provided v1.Route.
func MakeK8sPlaceholderService(ctx context.Context, route *v1.Route, targetName string) (*corev1.Service, error) {
	hostname, err := domains.HostnameFromTemplate(ctx, route.Name, targetName)
	if err != nil {
		return nil, err
	}
	fullName, err := domains.DomainNameFromTemplate(ctx, route.ObjectMeta, hostname)
	if err != nil {
		return nil, err
	}

	return makeK8sService(ctx, route, &corev1.ServiceSpec{
		Type:            corev1.ServiceTypeExternalName,
		ExternalName:    fullName,
		SessionAffinity: corev1.ServiceAffinityNone,
		Ports: []corev1.ServicePort{{
			Name:       networking.ServicePortNameH2C,
			Port:       int32(80),
			TargetPort: intstr.FromInt(80),
		}},
	}, targetName)
}

// MakeK8sService creates a Service that redirect to the loadbalancer specified
// in Ingress status. It's owned by the provided v1.Route.
func MakeK8sService(ctx context.Context, route *v1.Route,
	targetName string, ingress *netv1alpha1.Ingress, isPrivate bool, clusterIP string) (*corev1.Service, error) {
	svcSpec, err := makeServiceSpec(ingress, isPrivate, clusterIP)
	if err != nil {
		return nil, err
	}

	return makeK8sService(ctx, route, svcSpec, targetName)
}

func makeK8sService(ctx context.Context, route *v1.Route,
	spec *corev1.ServiceSpec, targetName string) (*corev1.Service, error) {
	hostname, err := domains.HostnameFromTemplate(ctx, route.Name, targetName)
	if err != nil {
		return nil, err
	}

	svcLabels := map[string]string{
		serving.RouteLabelKey: route.Name,
	}

	return &corev1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:      hostname,
			Namespace: route.Namespace,
			OwnerReferences: []metav1.OwnerReference{
				// This service is owned by the Route.
				*kmeta.NewControllerRef(route),
			},
			Labels: kmeta.UnionMaps(kmeta.FilterMap(route.GetLabels(), func(key string) bool {
				// Do not propagate the visibility label from Route as users may want to set the label
				// in the specific k8s svc for subroute. see https://github.com/knative/serving/pull/4560.
				return key == network.VisibilityLabelKey
			}), svcLabels),
			Annotations: route.GetAnnotations(),
		},
		Spec: *spec,
	}, nil
}

func makeServiceSpec(ingress *netv1alpha1.Ingress, isPrivate bool, clusterIP string) (*corev1.ServiceSpec, error) {
	ingressStatus := ingress.Status

	lbStatus := ingressStatus.PublicLoadBalancer
	if isPrivate || ingressStatus.PrivateLoadBalancer != nil {
		// Always use private load balancer if it exists,
		// because k8s service is only useful for inter-cluster communication.
		// External communication will be handle via ingress gateway, which won't be affected by what is configured here.
		lbStatus = ingressStatus.PrivateLoadBalancer
	}

	if lbStatus == nil || len(lbStatus.Ingress) == 0 {
		return nil, errLoadBalancerNotFound
	}
	if len(lbStatus.Ingress) > 1 {
		// Return error as we only support one LoadBalancer currently.
		return nil, errors.New(
			"more than one ingress are specified in status(LoadBalancer) of Ingress " + ingress.GetName())
	}
	balancer := lbStatus.Ingress[0]

	// Here we decide LoadBalancer information in the order of
	// DomainInternal > Domain > LoadBalancedIP to prioritize cluster-local,
	// and domain (since it would change less than IP).
	switch {
	case balancer.DomainInternal != "":
		return &corev1.ServiceSpec{
			Type:            corev1.ServiceTypeExternalName,
			ExternalName:    balancer.DomainInternal,
			SessionAffinity: corev1.ServiceAffinityNone,
			Ports: []corev1.ServicePort{{
				Name:       networking.ServicePortNameH2C,
				Port:       int32(80),
				TargetPort: intstr.FromInt(80),
			}},
		}, nil
	case balancer.Domain != "":
		return &corev1.ServiceSpec{
			Type:         corev1.ServiceTypeExternalName,
			ExternalName: balancer.Domain,
			Ports: []corev1.ServicePort{{
				Name:       networking.ServicePortNameH2C,
				Port:       int32(80),
				TargetPort: intstr.FromInt(80),
			}},
		}, nil
	case balancer.MeshOnly:
		// The Ingress is loadbalanced through a Service mesh.
		// We won't have a specific LB endpoint to route traffic to,
		// but we still need to create a ClusterIP service to make
		// sure the domain name is available for access within the
		// mesh.
		return &corev1.ServiceSpec{
			Type:      corev1.ServiceTypeClusterIP,
			ClusterIP: clusterIP,
			Ports: []corev1.ServicePort{{
				Name: networking.ServicePortNameHTTP1,
				Port: networking.ServiceHTTPPort,
			}},
		}, nil
	case balancer.IP != "":
		// TODO(lichuqiang): deal with LoadBalancer IP.
		// We'll also need ports info to make it take effect.
	}
	return nil, errLoadBalancerNotFound
}
<|endoftext|>