<commit_before>//go:build linux
// +build linux

package sysstat

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/config"
	"github.com/influxdata/telegraf/internal"
	"github.com/influxdata/telegraf/plugins/inputs"
)

var (
	firstTimestamp time.Time
	execCommand    = exec.Command // execCommand is used to mock commands in tests.
	dfltActivities = []string{"DISK"}
)

const parseInterval = 1 // parseInterval is the interval (in seconds) where the parsing of the binary file takes place.

type Sysstat struct {
	// Sadc represents the path to the sadc collector utility.
	Sadc string `toml:"sadc_path"`

	// Force the execution time of sadc
	SadcInterval config.Duration `toml:"sadc_interval"`

	// Sadf represents the path to the sadf cmd.
	Sadf string `toml:"sadf_path"`

	// Activities is a list of activities that are passed as argument to the
	// collector utility (e.g: DISK, SNMP etc...)
	// The more activities that are added, the more data is collected.
	Activities []string

	// Options is a map of options.
	//
	// The key represents the actual option that the Sadf command is called with and
	// the value represents the description for that option.
	//
	// For example, if you have the following options map:
	//    map[string]string{"-C": "cpu", "-d": "disk"}
	// The Sadf command is run with the options -C and -d to extract cpu and
	// disk metrics from the collected binary file.
	//
	// If Group is false (see below), each metric will be prefixed with the corresponding description
	// and represents itself a measurement.
	//
	// If Group is true, metrics are grouped to a single measurement with the corresponding description as name.
	Options map[string]string

	// Group determines if metrics are grouped or not.
	Group bool

	// DeviceTags adds the possibility to add additional tags for devices.
	DeviceTags map[string][]map[string]string `toml:"device_tags"`
	tmpFile    string
	interval   int

	Log telegraf.Logger
}

func (*Sysstat) Description() string {
	return "Sysstat metrics collector"
}

var sampleConfig = `
  ## Path to the sadc command.
  #
  ## Common Defaults:
  ##   Debian/Ubuntu: /usr/lib/sysstat/sadc
  ##   Arch:          /usr/lib/sa/sadc
  ##   RHEL/CentOS:   /usr/lib64/sa/sadc
  sadc_path = "/usr/lib/sa/sadc" # required

  ## Path to the sadf command, if it is not in PATH
  # sadf_path = "/usr/bin/sadf"

  ## Activities is a list of activities, that are passed as argument to the
  ## sadc collector utility (e.g: DISK, SNMP etc...)
  ## The more activities that are added, the more data is collected.
  # activities = ["DISK"]

  ## Group metrics to measurements.
  ##
  ## If group is false each metric will be prefixed with a description
  ## and represents itself a measurement.
  ##
  ## If Group is true, corresponding metrics are grouped to a single measurement.
  # group = true

  ## Options for the sadf command. The values on the left represent the sadf
  ## options and the values on the right their description (which are used for
  ## grouping and prefixing metrics).
  ##
  ## Run 'sar -h' or 'man sar' to find out the supported options for your
  ## sysstat version.
  [inputs.sysstat.options]
    -C = "cpu"
    -B = "paging"
    -b = "io"
    -d = "disk"             # requires DISK activity
    "-n ALL" = "network"
    "-P ALL" = "per_cpu"
    -q = "queue"
    -R = "mem"
    -r = "mem_util"
    -S = "swap_util"
    -u = "cpu_util"
    -v = "inode"
    -W = "swap"
    -w = "task"
  #  -H = "hugepages"        # only available for newer linux distributions
  #  "-I ALL" = "interrupts" # requires INT activity

  ## Device tags can be used to add additional tags for devices.
  ## For example the configuration below adds a tag vg with value rootvg for
  ## all metrics with sda devices.
  # [[inputs.sysstat.device_tags.sda]]
  #  vg = "rootvg"
`

func (*Sysstat) SampleConfig() string {
	return sampleConfig
}

func (s *Sysstat) Gather(acc telegraf.Accumulator) error {
	if time.Duration(s.SadcInterval) != 0 {
		// Collect interval is calculated as interval - parseInterval
		s.interval = int(time.Duration(s.SadcInterval).Seconds()) + parseInterval
	}

	if s.interval == 0 {
		if firstTimestamp.IsZero() {
			firstTimestamp = time.Now()
		} else {
			s.interval = int(time.Since(firstTimestamp).Seconds() + 0.5)
		}
	}
	ts := time.Now().Add(time.Duration(s.interval) * time.Second)
	if err := s.collect(); err != nil {
		return err
	}
	var wg sync.WaitGroup
	for option := range s.Options {
		wg.Add(1)
		go func(acc telegraf.Accumulator, option string) {
			defer wg.Done()
			acc.AddError(s.parse(acc, option, ts))
		}(acc, option)
	}
	wg.Wait()

	if _, err := os.Stat(s.tmpFile); err == nil {
		acc.AddError(os.Remove(s.tmpFile))
	}

	return nil
}

// collect collects sysstat data with the collector utility sadc.
// It runs the following command:
//     Sadc -S <Activity1> -S <Activity2> ... <collectInterval> 2 tmpFile
// The above command collects system metrics during <collectInterval> and
// saves it in binary form to tmpFile.
func (s *Sysstat) collect() error {
	options := []string{}
	for _, act := range s.Activities {
		options = append(options, "-S", act)
	}
	s.tmpFile = path.Join("/tmp", fmt.Sprintf("sysstat-%d", time.Now().Unix()))
	// collectInterval has to be smaller than the telegraf data collection interval
	collectInterval := s.interval - parseInterval

	// If true, interval is not defined yet and Gather is run for the first time.
	if collectInterval < 0 {
		collectInterval = 1 // In that case we only collect for 1 second.
	}

	options = append(options, strconv.Itoa(collectInterval), "2", s.tmpFile)
	cmd := execCommand(s.Sadc, options...)
	out, err := internal.CombinedOutputTimeout(cmd, time.Second*time.Duration(collectInterval+parseInterval))
	if err != nil {
		if err := os.Remove(s.tmpFile); err != nil {
			s.Log.Errorf("Failed to remove tmp file after %q command: %s", strings.Join(cmd.Args, " "), err.Error())
		}
		return fmt.Errorf("failed to run command %s: %s - %s", strings.Join(cmd.Args, " "), err, string(out))
	}
	return nil
}

func filterEnviron(env []string, prefix string) []string {
	newenv := env[:0]
	for _, envvar := range env {
		if !strings.HasPrefix(envvar, prefix) {
			newenv = append(newenv, envvar)
		}
	}
	return newenv
}

// Return the Cmd with its environment configured to use the C locale
func withCLocale(cmd *exec.Cmd) *exec.Cmd {
	var env []string
	if cmd.Env != nil {
		env = cmd.Env
	} else {
		env = os.Environ()
	}
	env = filterEnviron(env, "LANG")
	env = filterEnviron(env, "LC_")
	env = append(env, "LANG=C")
	cmd.Env = env
	return cmd
}

// parse runs Sadf on the previously saved tmpFile:
//    Sadf -p -- -p <option> tmpFile
// and parses the output to add it to the telegraf.Accumulator acc.
func (s *Sysstat) parse(acc telegraf.Accumulator, option string, ts time.Time) error {
	cmd := execCommand(s.Sadf, s.sadfOptions(option)...)
	cmd = withCLocale(cmd)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	if err := cmd.Start(); err != nil {
		return fmt.Errorf("running command '%s' failed: %s", strings.Join(cmd.Args, " "), err)
	}

	r := bufio.NewReader(stdout)
	csvReader := csv.NewReader(r)
	csvReader.Comma = '\t'
	csvReader.FieldsPerRecord = 6
	var measurement string
	// groupData to accumulate data when Group=true
	type groupData struct {
		tags   map[string]string
		fields map[string]interface{}
	}
	m := make(map[string]groupData)
	for {
		record, err := csvReader.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		device := record[3]
		value, err := strconv.ParseFloat(record[5], 64)
		if err != nil {
			return err
		}

		tags := map[string]string{}
		if device != "-" {
			tags["device"] = device
			if addTags, ok := s.DeviceTags[device]; ok {
				for _, tag := range addTags {
					for k, v := range tag {
						tags[k] = v
					}
				}
			}
		}

		if s.Group {
			measurement = s.Options[option]
			if _, ok := m[device]; !ok {
				m[device] = groupData{
					fields: make(map[string]interface{}),
					tags:   make(map[string]string),
				}
			}
			g := m[device]
			if len(g.tags) == 0 {
				for k, v := range tags {
					g.tags[k] = v
				}
			}
			g.fields[escape(record[4])] = value
		} else {
			measurement = s.Options[option] + "_" + escape(record[4])
			fields := map[string]interface{}{
				"value": value,
			}
			acc.AddFields(measurement, fields, tags, ts)
		}
	}
	if s.Group {
		for _, v := range m {
			acc.AddFields(measurement, v.fields, v.tags, ts)
		}
	}
	if err := internal.WaitTimeout(cmd, time.Second*5); err != nil {
		return fmt.Errorf("command %s failed with %s",
			strings.Join(cmd.Args, " "), err)
	}
	return nil
}

// sadfOptions creates the correct options for the sadf utility.
func (s *Sysstat) sadfOptions(activityOption string) []string {
	options := []string{
		"-p",
		"--",
		"-p",
	}

	opts := strings.Split(activityOption, " ")
	options = append(options, opts...)
	options = append(options, s.tmpFile)

	return options
}

// escape removes % and / chars in field names
func escape(dirty string) string {
	var fieldEscaper = strings.NewReplacer(
		`%%`, "pct_",
		`%`, "pct_",
		`/`, "_per_",
	)
	return fieldEscaper.Replace(dirty)
}

func init() {
	s := Sysstat{
		Group:      true,
		Activities: dfltActivities,
	}
	sadf, _ := exec.LookPath("sadf")
	if len(sadf) > 0 {
		s.Sadf = sadf
	}
	inputs.Add("sysstat", func() telegraf.Input {
		return &s
	})
}
<commit_msg>fix: sysstat use unique temp file vs hard-coded (#10165)<commit_after>//go:build linux
// +build linux

package sysstat

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/config"
	"github.com/influxdata/telegraf/internal"
	"github.com/influxdata/telegraf/plugins/inputs"
)

var (
	firstTimestamp time.Time
	execCommand    = exec.Command // execCommand is used to mock commands in tests.
	dfltActivities = []string{"DISK"}
)

const parseInterval = 1 // parseInterval is the interval (in seconds) where the parsing of the binary file takes place.

type Sysstat struct {
	// Sadc represents the path to the sadc collector utility.
	Sadc string `toml:"sadc_path"`

	// Force the execution time of sadc
	SadcInterval config.Duration `toml:"sadc_interval"`

	// Sadf represents the path to the sadf cmd.
	Sadf string `toml:"sadf_path"`

	// Activities is a list of activities that are passed as argument to the
	// collector utility (e.g: DISK, SNMP etc...)
	// The more activities that are added, the more data is collected.
	Activities []string

	// Options is a map of options.
	//
	// The key represents the actual option that the Sadf command is called with and
	// the value represents the description for that option.
	//
	// For example, if you have the following options map:
	//    map[string]string{"-C": "cpu", "-d": "disk"}
	// The Sadf command is run with the options -C and -d to extract cpu and
	// disk metrics from the collected binary file.
	//
	// If Group is false (see below), each metric will be prefixed with the corresponding description
	// and represents itself a measurement.
	//
	// If Group is true, metrics are grouped to a single measurement with the corresponding description as name.
	Options map[string]string

	// Group determines if metrics are grouped or not.
	Group bool

	// DeviceTags adds the possibility to add additional tags for devices.
	DeviceTags map[string][]map[string]string `toml:"device_tags"`
	interval   int

	Log telegraf.Logger
}

func (*Sysstat) Description() string {
	return "Sysstat metrics collector"
}

var sampleConfig = `
  ## Path to the sadc command.
  #
  ## Common Defaults:
  ##   Debian/Ubuntu: /usr/lib/sysstat/sadc
  ##   Arch:          /usr/lib/sa/sadc
  ##   RHEL/CentOS:   /usr/lib64/sa/sadc
  sadc_path = "/usr/lib/sa/sadc" # required

  ## Path to the sadf command, if it is not in PATH
  # sadf_path = "/usr/bin/sadf"

  ## Activities is a list of activities, that are passed as argument to the
  ## sadc collector utility (e.g: DISK, SNMP etc...)
  ## The more activities that are added, the more data is collected.
  # activities = ["DISK"]

  ## Group metrics to measurements.
  ##
  ## If group is false each metric will be prefixed with a description
  ## and represents itself a measurement.
  ##
  ## If Group is true, corresponding metrics are grouped to a single measurement.
  # group = true

  ## Options for the sadf command. The values on the left represent the sadf
  ## options and the values on the right their description (which are used for
  ## grouping and prefixing metrics).
  ##
  ## Run 'sar -h' or 'man sar' to find out the supported options for your
  ## sysstat version.
  [inputs.sysstat.options]
    -C = "cpu"
    -B = "paging"
    -b = "io"
    -d = "disk"             # requires DISK activity
    "-n ALL" = "network"
    "-P ALL" = "per_cpu"
    -q = "queue"
    -R = "mem"
    -r = "mem_util"
    -S = "swap_util"
    -u = "cpu_util"
    -v = "inode"
    -W = "swap"
    -w = "task"
  #  -H = "hugepages"        # only available for newer linux distributions
  #  "-I ALL" = "interrupts" # requires INT activity

  ## Device tags can be used to add additional tags for devices.
  ## For example the configuration below adds a tag vg with value rootvg for
  ## all metrics with sda devices.
  # [[inputs.sysstat.device_tags.sda]]
  #  vg = "rootvg"
`

func (*Sysstat) SampleConfig() string {
	return sampleConfig
}

func (s *Sysstat) Gather(acc telegraf.Accumulator) error {
	if time.Duration(s.SadcInterval) != 0 {
		// Collect interval is calculated as interval - parseInterval
		s.interval = int(time.Duration(s.SadcInterval).Seconds()) + parseInterval
	}

	if s.interval == 0 {
		if firstTimestamp.IsZero() {
			firstTimestamp = time.Now()
		} else {
			s.interval = int(time.Since(firstTimestamp).Seconds() + 0.5)
		}
	}

	tmpfile, err := os.CreateTemp("", "sysstat-*")
	if err != nil {
		return fmt.Errorf("failed to create tmp file: %s", err)
	}
	defer os.Remove(tmpfile.Name())

	ts := time.Now().Add(time.Duration(s.interval) * time.Second)
	if err := s.collect(tmpfile.Name()); err != nil {
		return err
	}
	var wg sync.WaitGroup
	for option := range s.Options {
		wg.Add(1)
		go func(acc telegraf.Accumulator, option string) {
			defer wg.Done()
			acc.AddError(s.parse(acc, option, tmpfile.Name(), ts))
		}(acc, option)
	}
	wg.Wait()

	return nil
}

// collect collects sysstat data with the collector utility sadc.
// It runs the following command:
//     Sadc -S <Activity1> -S <Activity2> ... <collectInterval> 2 tmpFile
// The above command collects system metrics during <collectInterval> and
// saves it in binary form to tmpFile.
func (s *Sysstat) collect(tempfile string) error {
	options := []string{}
	for _, act := range s.Activities {
		options = append(options, "-S", act)
	}

	// collectInterval has to be smaller than the telegraf data collection interval
	collectInterval := s.interval - parseInterval

	// If true, interval is not defined yet and Gather is run for the first time.
	if collectInterval < 0 {
		collectInterval = 1 // In that case we only collect for 1 second.
	}

	options = append(options, strconv.Itoa(collectInterval), "2", tempfile)
	cmd := execCommand(s.Sadc, options...)
	out, err := internal.CombinedOutputTimeout(cmd, time.Second*time.Duration(collectInterval+parseInterval))
	if err != nil {
		return fmt.Errorf("failed to run command %s: %s - %s", strings.Join(cmd.Args, " "), err, string(out))
	}
	return nil
}

func filterEnviron(env []string, prefix string) []string {
	newenv := env[:0]
	for _, envvar := range env {
		if !strings.HasPrefix(envvar, prefix) {
			newenv = append(newenv, envvar)
		}
	}
	return newenv
}

// Return the Cmd with its environment configured to use the C locale
func withCLocale(cmd *exec.Cmd) *exec.Cmd {
	var env []string
	if cmd.Env != nil {
		env = cmd.Env
	} else {
		env = os.Environ()
	}
	env = filterEnviron(env, "LANG")
	env = filterEnviron(env, "LC_")
	env = append(env, "LANG=C")
	cmd.Env = env
	return cmd
}

// parse runs Sadf on the previously saved tmpFile:
//    Sadf -p -- -p <option> tmpFile
// and parses the output to add it to the telegraf.Accumulator acc.
func (s *Sysstat) parse(acc telegraf.Accumulator, option string, tmpfile string, ts time.Time) error {
	cmd := execCommand(s.Sadf, s.sadfOptions(option, tmpfile)...)
	cmd = withCLocale(cmd)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	if err := cmd.Start(); err != nil {
		return fmt.Errorf("running command '%s' failed: %s", strings.Join(cmd.Args, " "), err)
	}

	r := bufio.NewReader(stdout)
	csvReader := csv.NewReader(r)
	csvReader.Comma = '\t'
	csvReader.FieldsPerRecord = 6
	var measurement string
	// groupData to accumulate data when Group=true
	type groupData struct {
		tags   map[string]string
		fields map[string]interface{}
	}
	m := make(map[string]groupData)
	for {
		record, err := csvReader.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		device := record[3]
		value, err := strconv.ParseFloat(record[5], 64)
		if err != nil {
			return err
		}

		tags := map[string]string{}
		if device != "-" {
			tags["device"] = device
			if addTags, ok := s.DeviceTags[device]; ok {
				for _, tag := range addTags {
					for k, v := range tag {
						tags[k] = v
					}
				}
			}
		}

		if s.Group {
			measurement = s.Options[option]
			if _, ok := m[device]; !ok {
				m[device] = groupData{
					fields: make(map[string]interface{}),
					tags:   make(map[string]string),
				}
			}
			g := m[device]
			if len(g.tags) == 0 {
				for k, v := range tags {
					g.tags[k] = v
				}
			}
			g.fields[escape(record[4])] = value
		} else {
			measurement = s.Options[option] + "_" + escape(record[4])
			fields := map[string]interface{}{
				"value": value,
			}
			acc.AddFields(measurement, fields, tags, ts)
		}
	}
	if s.Group {
		for _, v := range m {
			acc.AddFields(measurement, v.fields, v.tags, ts)
		}
	}
	if err := internal.WaitTimeout(cmd, time.Second*5); err != nil {
		return fmt.Errorf("command %s failed with %s",
			strings.Join(cmd.Args, " "), err)
	}
	return nil
}

// sadfOptions creates the correct options for the sadf utility.
func (s *Sysstat) sadfOptions(activityOption string, tmpfile string) []string {
	options := []string{
		"-p",
		"--",
		"-p",
	}

	opts := strings.Split(activityOption, " ")
	options = append(options, opts...)
	options = append(options, tmpfile)

	return options
}

// escape removes % and / chars in field names
func escape(dirty string) string {
	var fieldEscaper = strings.NewReplacer(
		`%%`, "pct_",
		`%`, "pct_",
		`/`, "_per_",
	)
	return fieldEscaper.Replace(dirty)
}

func init() {
	s := Sysstat{
		Group:      true,
		Activities: dfltActivities,
	}
	sadf, _ := exec.LookPath("sadf")
	if len(sadf) > 0 {
		s.Sadf = sadf
	}
	inputs.Add("sysstat", func() telegraf.Input {
		return &s
	})
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/pseudomuto/shortify-go/shortify"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

func main() {
	if shortify.Configure(configFilePath()) {
		if !shortify.HandleCommandLine(os.Args) {
			router := shortify.NewRouter()
			log.Fatal(http.ListenAndServe(shortify.ServerPort(), router))
		}
	}
}

func configFilePath() string {
	file, _ := filepath.Abs(os.Args[0])
	return file + ".gcfg"
}
<commit_msg>update package after moving to shortify org<commit_after>package main

import (
	"github.com/shortify/shortify/shortify"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

func main() {
	if shortify.Configure(configFilePath()) {
		if !shortify.HandleCommandLine(os.Args) {
			router := shortify.NewRouter()
			log.Fatal(http.ListenAndServe(shortify.ServerPort(), router))
		}
	}
}

func configFilePath() string {
	file, _ := filepath.Abs(os.Args[0])
	return file + ".gcfg"
}
<|endoftext|>


<commit_before>// Copyright 2015 Matthew Collins
//
// 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 gl

import (
	"unsafe"

	"github.com/go-gl/mathgl/mgl32"
	"github.com/thinkofdeath/gl/v3.2-core/gl"
)

// ShaderType is type of shader to be used, different types run
// at different stages in the pipeline.
type ShaderType uint32

// Valid shader types.
const (
	VertexShader   ShaderType = gl.VERTEX_SHADER
	FragmentShader ShaderType = gl.FRAGMENT_SHADER
)

// ShaderParameter is a parameter that can set or read from a
// shader.
type ShaderParameter uint32

// Valid shader parameters.
const (
	CompileStatus ShaderParameter = gl.COMPILE_STATUS
	InfoLogLength ShaderParameter = gl.INFO_LOG_LENGTH
)

// Program is a collection of shaders which will be run on draw
// operations.
type Program uint32

// CreateProgram allocates a new program.
func CreateProgram() Program {
	return Program(gl.CreateProgram())
}

// AttachShader attaches the passed shader to the program.
func (p Program) AttachShader(s Shader) {
	gl.AttachShader(uint32(p), uint32(s))
}

// Link links the program's shaders.
func (p Program) Link() {
	gl.LinkProgram(uint32(p))
}

var (
	currentProgram Program
)

// Use sets this shader as the active shader. If this shader is
// already active this does nothing.
func (p Program) Use() {
	if p == currentProgram {
		return
	}
	gl.UseProgram(uint32(p))
	currentProgram = p
}

// Uniform is a per-a-draw value that can be passed into the
// program.
type Uniform int32

// UniformLocation returns the uniform with the given name in
// the program.
func (p Program) UniformLocation(name string) Uniform {
	n := gl.Str(name + "\x00")
	return Uniform(gl.GetUniformLocation(uint32(p), n))
}

// Matrix4 sets the value of the uniform to the passed matrix.
func (u Uniform) Matrix4(matrix *mgl32.Mat4) {
	gl.UniformMatrix4fv(int32(u), 1, false, (*float32)(unsafe.Pointer(matrix)))
}

// Matrix4 sets the value of the uniform to the passed matrix.
func (u Uniform) Matrix4Multi(matrix []mgl32.Mat4) {
	gl.UniformMatrix4fv(int32(u), int32(len(matrix)), false, (*float32)(gl.Ptr(matrix)))
}

// Int sets the value of the uniform to the passed integer.
func (u Uniform) Int(val int) {
	gl.Uniform1i(int32(u), int32(val))
}

// Int3 sets the value of the uniform to the passed integers.
func (u Uniform) Int3(x, y, z int) {
	gl.Uniform3i(int32(u), int32(x), int32(y), int32(z))
}

// IntV sets the value of the uniform to the passed integer array.
func (u Uniform) IntV(v ...int) {
	gl.Uniform1iv(int32(u), int32(len(v)), (*int32)(gl.Ptr(v)))
}

// Float sets the value of the uniform to the passed float.
func (u Uniform) Float(val float32) {
	gl.Uniform1f(int32(u), val)
}

// Float2 sets the value of the uniform to the passed floats.
func (u Uniform) Float2(x, y float32) {
	gl.Uniform2f(int32(u), x, y)
}

// Float3 sets the value of the uniform to the passed floats.
func (u Uniform) Float3(x, y, z float32) {
	gl.Uniform3f(int32(u), x, y, z)
}

// Float3 sets the value of the uniform to the passed floats.
func (u Uniform) Float4(x, y, z, w float32) {
	gl.Uniform4f(int32(u), x, y, z, w)
}

func (u Uniform) FloatMutli(a []float32) {
	gl.Uniform4fv(int32(u), int32(len(a)), (*float32)(gl.Ptr(a)))
}

func (u Uniform) FloatMutliRaw(a interface{}, l int) {
	gl.Uniform4fv(int32(u), int32(l), (*float32)(gl.Ptr(a)))
}

// Attribute is a per-a-vertex value that can be passed into the
// program.
type Attribute int32

// AttributeLocation returns the attribute with the given name in
// the program.
func (p Program) AttributeLocation(name string) Attribute {
	n := gl.Str(name + "\x00")
	return Attribute(gl.GetAttribLocation(uint32(p), n))
}

// Enable enables the attribute for use in rendering.
func (a Attribute) Enable() {
	gl.EnableVertexAttribArray(uint32(a))
}

// Disable disables the attribute for use in rendering.
func (a Attribute) Disable() {
	gl.DisableVertexAttribArray(uint32(a))
}

// Pointer is used to specify the format of the data in the buffer. The data will
// be uploaded as floats.
func (a Attribute) Pointer(size int, ty Type, normalized bool, stride, offset int) {
	gl.VertexAttribPointer(uint32(a), int32(size), uint32(ty), normalized, int32(stride), uintptr(offset))
}

// PointerInt is used to specify the format of the data in the buffer. The data will
// be uploaded as integers.
func (a Attribute) PointerInt(size int, ty Type, stride, offset int) {
	gl.VertexAttribIPointer(uint32(a), int32(size), uint32(ty), int32(stride), uintptr(offset))
}

// Shader is code to be run on the gpu at a specific stage in the
// pipeline.
type Shader uint32

// CreateShader creates a new shader of the specifed type.
func CreateShader(t ShaderType) Shader {
	return Shader(gl.CreateShader(uint32(t)))
}

// Source sets the source of the shader.
func (s Shader) Source(src string) {
	ss := gl.Str(src + "\x00")
	gl.ShaderSource(uint32(s), 1, &ss, nil)
}

// Compile compiles the shader.
func (s Shader) Compile() {
	gl.CompileShader(uint32(s))
}

// Parameter returns the integer value of the parameter for
// this shader.
func (s Shader) Parameter(param ShaderParameter) int {
	var p int32
	gl.GetShaderiv(uint32(s), uint32(param), &p)
	return int(p)
}

// InfoLog returns the log from compiling the shader.
func (s Shader) InfoLog() string {
	l := s.Parameter(InfoLogLength)

	buf := make([]byte, l)

	gl.GetShaderInfoLog(uint32(s), int32(l), nil, (*uint8)(gl.Ptr(buf)))
	return string(buf)
}
<commit_msg>render/gl: trim off the null byte at the end of info logs<commit_after>// Copyright 2015 Matthew Collins
//
// 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 gl

import (
	"unsafe"

	"github.com/go-gl/mathgl/mgl32"
	"github.com/thinkofdeath/gl/v3.2-core/gl"
)

// ShaderType is type of shader to be used, different types run
// at different stages in the pipeline.
type ShaderType uint32

// Valid shader types.
const (
	VertexShader   ShaderType = gl.VERTEX_SHADER
	FragmentShader ShaderType = gl.FRAGMENT_SHADER
)

// ShaderParameter is a parameter that can set or read from a
// shader.
type ShaderParameter uint32

// Valid shader parameters.
const (
	CompileStatus ShaderParameter = gl.COMPILE_STATUS
	InfoLogLength ShaderParameter = gl.INFO_LOG_LENGTH
)

// Program is a collection of shaders which will be run on draw
// operations.
type Program uint32

// CreateProgram allocates a new program.
func CreateProgram() Program {
	return Program(gl.CreateProgram())
}

// AttachShader attaches the passed shader to the program.
func (p Program) AttachShader(s Shader) {
	gl.AttachShader(uint32(p), uint32(s))
}

// Link links the program's shaders.
func (p Program) Link() {
	gl.LinkProgram(uint32(p))
}

var (
	currentProgram Program
)

// Use sets this shader as the active shader. If this shader is
// already active this does nothing.
func (p Program) Use() {
	if p == currentProgram {
		return
	}
	gl.UseProgram(uint32(p))
	currentProgram = p
}

// Uniform is a per-a-draw value that can be passed into the
// program.
type Uniform int32

// UniformLocation returns the uniform with the given name in
// the program.
func (p Program) UniformLocation(name string) Uniform {
	n := gl.Str(name + "\x00")
	return Uniform(gl.GetUniformLocation(uint32(p), n))
}

// Matrix4 sets the value of the uniform to the passed matrix.
func (u Uniform) Matrix4(matrix *mgl32.Mat4) {
	gl.UniformMatrix4fv(int32(u), 1, false, (*float32)(unsafe.Pointer(matrix)))
}

// Matrix4 sets the value of the uniform to the passed matrix.
func (u Uniform) Matrix4Multi(matrix []mgl32.Mat4) {
	gl.UniformMatrix4fv(int32(u), int32(len(matrix)), false, (*float32)(gl.Ptr(matrix)))
}

// Int sets the value of the uniform to the passed integer.
func (u Uniform) Int(val int) {
	gl.Uniform1i(int32(u), int32(val))
}

// Int3 sets the value of the uniform to the passed integers.
func (u Uniform) Int3(x, y, z int) {
	gl.Uniform3i(int32(u), int32(x), int32(y), int32(z))
}

// IntV sets the value of the uniform to the passed integer array.
func (u Uniform) IntV(v ...int) {
	gl.Uniform1iv(int32(u), int32(len(v)), (*int32)(gl.Ptr(v)))
}

// Float sets the value of the uniform to the passed float.
func (u Uniform) Float(val float32) {
	gl.Uniform1f(int32(u), val)
}

// Float2 sets the value of the uniform to the passed floats.
func (u Uniform) Float2(x, y float32) {
	gl.Uniform2f(int32(u), x, y)
}

// Float3 sets the value of the uniform to the passed floats.
func (u Uniform) Float3(x, y, z float32) {
	gl.Uniform3f(int32(u), x, y, z)
}

// Float3 sets the value of the uniform to the passed floats.
func (u Uniform) Float4(x, y, z, w float32) {
	gl.Uniform4f(int32(u), x, y, z, w)
}

func (u Uniform) FloatMutli(a []float32) {
	gl.Uniform4fv(int32(u), int32(len(a)), (*float32)(gl.Ptr(a)))
}

func (u Uniform) FloatMutliRaw(a interface{}, l int) {
	gl.Uniform4fv(int32(u), int32(l), (*float32)(gl.Ptr(a)))
}

// Attribute is a per-a-vertex value that can be passed into the
// program.
type Attribute int32

// AttributeLocation returns the attribute with the given name in
// the program.
func (p Program) AttributeLocation(name string) Attribute {
	n := gl.Str(name + "\x00")
	return Attribute(gl.GetAttribLocation(uint32(p), n))
}

// Enable enables the attribute for use in rendering.
func (a Attribute) Enable() {
	gl.EnableVertexAttribArray(uint32(a))
}

// Disable disables the attribute for use in rendering.
func (a Attribute) Disable() {
	gl.DisableVertexAttribArray(uint32(a))
}

// Pointer is used to specify the format of the data in the buffer. The data will
// be uploaded as floats.
func (a Attribute) Pointer(size int, ty Type, normalized bool, stride, offset int) {
	gl.VertexAttribPointer(uint32(a), int32(size), uint32(ty), normalized, int32(stride), uintptr(offset))
}

// PointerInt is used to specify the format of the data in the buffer. The data will
// be uploaded as integers.
func (a Attribute) PointerInt(size int, ty Type, stride, offset int) {
	gl.VertexAttribIPointer(uint32(a), int32(size), uint32(ty), int32(stride), uintptr(offset))
}

// Shader is code to be run on the gpu at a specific stage in the
// pipeline.
type Shader uint32

// CreateShader creates a new shader of the specifed type.
func CreateShader(t ShaderType) Shader {
	return Shader(gl.CreateShader(uint32(t)))
}

// Source sets the source of the shader.
func (s Shader) Source(src string) {
	ss := gl.Str(src + "\x00")
	gl.ShaderSource(uint32(s), 1, &ss, nil)
}

// Compile compiles the shader.
func (s Shader) Compile() {
	gl.CompileShader(uint32(s))
}

// Parameter returns the integer value of the parameter for
// this shader.
func (s Shader) Parameter(param ShaderParameter) int {
	var p int32
	gl.GetShaderiv(uint32(s), uint32(param), &p)
	return int(p)
}

// InfoLog returns the log from compiling the shader.
func (s Shader) InfoLog() string {
	l := s.Parameter(InfoLogLength)

	buf := make([]byte, l)

	gl.GetShaderInfoLog(uint32(s), int32(l), nil, (*uint8)(gl.Ptr(buf)))
	return string(buf[:len(buf)-1])
}
<|endoftext|>


<commit_before>// Test suite for vfs

package vfs

import (
	"context"
	"fmt"
	"io"
	"os"
	"testing"

	"github.com/pkg/errors"
	_ "github.com/rclone/rclone/backend/all" // import all the backends
	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/fstest"
	"github.com/rclone/rclone/vfs/vfscommon"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// Some times used in the tests
var (
	t1 = fstest.Time("2001-02-03T04:05:06.499999999Z")
	t2 = fstest.Time("2011-12-25T12:59:59.123456789Z")
	t3 = fstest.Time("2011-12-30T12:59:59.000000000Z")
)

// TestMain drives the tests
func TestMain(m *testing.M) {
	fstest.TestMain(m)
}

// Check baseHandle performs as advertised
func TestVFSbaseHandle(t *testing.T) {
	fh := baseHandle{}

	err := fh.Chdir()
	assert.Equal(t, ENOSYS, err)

	err = fh.Chmod(0)
	assert.Equal(t, ENOSYS, err)

	err = fh.Chown(0, 0)
	assert.Equal(t, ENOSYS, err)

	err = fh.Close()
	assert.Equal(t, ENOSYS, err)

	fd := fh.Fd()
	assert.Equal(t, uintptr(0), fd)

	name := fh.Name()
	assert.Equal(t, "", name)

	_, err = fh.Read(nil)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.ReadAt(nil, 0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Readdir(0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Readdirnames(0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Seek(0, io.SeekStart)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Stat()
	assert.Equal(t, ENOSYS, err)

	err = fh.Sync()
	assert.Equal(t, nil, err)

	err = fh.Truncate(0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Write(nil)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.WriteAt(nil, 0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.WriteString("")
	assert.Equal(t, ENOSYS, err)

	err = fh.Flush()
	assert.Equal(t, ENOSYS, err)

	err = fh.Release()
	assert.Equal(t, ENOSYS, err)

	node := fh.Node()
	assert.Nil(t, node)
}

// TestNew sees if the New command works properly
func TestVFSNew(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()

	// Check making a VFS with nil options
	vfs := New(r.Fremote, nil)
	var defaultOpt = vfscommon.DefaultOpt
	defaultOpt.DirPerms |= os.ModeDir
	assert.Equal(t, vfs.Opt, defaultOpt)
	assert.Equal(t, vfs.f, r.Fremote)

	// Check the initialisation
	var opt = vfscommon.DefaultOpt
	opt.DirPerms = 0777
	opt.FilePerms = 0666
	opt.Umask = 0002
	vfs = New(r.Fremote, &opt)
	assert.Equal(t, os.FileMode(0775)|os.ModeDir, vfs.Opt.DirPerms)
	assert.Equal(t, os.FileMode(0664), vfs.Opt.FilePerms)
}

// TestRoot checks root directory is present and correct
func TestVFSRoot(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	root, err := vfs.Root()
	require.NoError(t, err)
	assert.Equal(t, vfs.root, root)
	assert.True(t, root.IsDir())
	assert.Equal(t, vfs.Opt.DirPerms.Perm(), root.Mode().Perm())
}

func TestVFSStat(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
	file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
	fstest.CheckItems(t, r.Fremote, file1, file2)

	node, err := vfs.Stat("file1")
	require.NoError(t, err)
	assert.True(t, node.IsFile())
	assert.Equal(t, "file1", node.Name())

	node, err = vfs.Stat("dir")
	require.NoError(t, err)
	assert.True(t, node.IsDir())
	assert.Equal(t, "dir", node.Name())

	node, err = vfs.Stat("dir/file2")
	require.NoError(t, err)
	assert.True(t, node.IsFile())
	assert.Equal(t, "file2", node.Name())

	_, err = vfs.Stat("not found")
	assert.Equal(t, os.ErrNotExist, err)

	_, err = vfs.Stat("dir/not found")
	assert.Equal(t, os.ErrNotExist, err)

	_, err = vfs.Stat("not found/not found")
	assert.Equal(t, os.ErrNotExist, err)

	_, err = vfs.Stat("file1/under a file")
	assert.Equal(t, os.ErrNotExist, err)
}

func TestVFSStatParent(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
	file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
	fstest.CheckItems(t, r.Fremote, file1, file2)

	node, leaf, err := vfs.StatParent("file1")
	require.NoError(t, err)
	assert.True(t, node.IsDir())
	assert.Equal(t, "/", node.Name())
	assert.Equal(t, "file1", leaf)

	node, leaf, err = vfs.StatParent("dir/file2")
	require.NoError(t, err)
	assert.True(t, node.IsDir())
	assert.Equal(t, "dir", node.Name())
	assert.Equal(t, "file2", leaf)

	node, leaf, err = vfs.StatParent("not found")
	require.NoError(t, err)
	assert.True(t, node.IsDir())
	assert.Equal(t, "/", node.Name())
	assert.Equal(t, "not found", leaf)

	_, _, err = vfs.StatParent("not found dir/not found")
	assert.Equal(t, os.ErrNotExist, err)

	_, _, err = vfs.StatParent("file1/under a file")
	assert.Equal(t, os.ErrExist, err)
}

func TestVFSOpenFile(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
	file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
	fstest.CheckItems(t, r.Fremote, file1, file2)

	fd, err := vfs.OpenFile("file1", os.O_RDONLY, 0777)
	require.NoError(t, err)
	assert.NotNil(t, fd)
	require.NoError(t, fd.Close())

	fd, err = vfs.OpenFile("dir", os.O_RDONLY, 0777)
	require.NoError(t, err)
	assert.NotNil(t, fd)
	require.NoError(t, fd.Close())

	fd, err = vfs.OpenFile("dir/new_file.txt", os.O_RDONLY, 0777)
	assert.Equal(t, os.ErrNotExist, err)
	assert.Nil(t, fd)

	fd, err = vfs.OpenFile("dir/new_file.txt", os.O_WRONLY|os.O_CREATE, 0777)
	require.NoError(t, err)
	assert.NotNil(t, fd)
	err = fd.Close()
	if errors.Cause(err) != fs.ErrorCantUploadEmptyFiles {
		require.NoError(t, err)
	}

	fd, err = vfs.OpenFile("not found/new_file.txt", os.O_WRONLY|os.O_CREATE, 0777)
	assert.Equal(t, os.ErrNotExist, err)
	assert.Nil(t, fd)
}

func TestVFSRename(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	features := r.Fremote.Features()
	if features.Move == nil && features.Copy == nil {
		return // skip as can't rename files
	}
	vfs := New(r.Fremote, nil)

	file1 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
	fstest.CheckItems(t, r.Fremote, file1)

	err := vfs.Rename("dir/file2", "dir/file1")
	require.NoError(t, err)
	file1.Path = "dir/file1"
	fstest.CheckItems(t, r.Fremote, file1)

	err = vfs.Rename("dir/file1", "file0")
	require.NoError(t, err)
	file1.Path = "file0"
	fstest.CheckItems(t, r.Fremote, file1)

	err = vfs.Rename("not found/file0", "file0")
	assert.Equal(t, os.ErrNotExist, err)

	err = vfs.Rename("file0", "not found/file0")
	assert.Equal(t, os.ErrNotExist, err)
}

func TestVFSStatfs(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	// pre-conditions
	assert.Nil(t, vfs.usage)
	assert.True(t, vfs.usageTime.IsZero())

	aboutSupported := r.Fremote.Features().About != nil

	// read
	total, used, free := vfs.Statfs()
	if !aboutSupported {
		assert.Equal(t, int64(-1), total)
		assert.Equal(t, int64(-1), free)
		assert.Equal(t, int64(-1), used)
		return // can't test anything else if About not supported
	}
	require.NotNil(t, vfs.usage)
	assert.False(t, vfs.usageTime.IsZero())
	if vfs.usage.Total != nil {
		assert.Equal(t, *vfs.usage.Total, total)
	} else {
		assert.Equal(t, int64(-1), total)
	}
	if vfs.usage.Free != nil {
		assert.Equal(t, *vfs.usage.Free, free)
	} else {
		assert.Equal(t, int64(-1), free)
	}
	if vfs.usage.Used != nil {
		assert.Equal(t, *vfs.usage.Used, used)
	} else {
		assert.Equal(t, int64(-1), used)
	}

	// read cached
	oldUsage := vfs.usage
	oldTime := vfs.usageTime
	total2, used2, free2 := vfs.Statfs()
	assert.Equal(t, oldUsage, vfs.usage)
	assert.Equal(t, total, total2)
	assert.Equal(t, used, used2)
	assert.Equal(t, free, free2)
	assert.Equal(t, oldTime, vfs.usageTime)
}

func TestFillInMissingSizes(t *testing.T) {
	const unknownFree = 10
	for _, test := range []struct {
		total, free, used             int64
		wantTotal, wantUsed, wantFree int64
	}{
		{
			total: 20, free: 5, used: 15,
			wantTotal: 20, wantFree: 5, wantUsed: 15,
		},
		{
			total: 20, free: 5, used: -1,
			wantTotal: 20, wantFree: 5, wantUsed: 15,
		},
		{
			total: 20, free: -1, used: 15,
			wantTotal: 20, wantFree: 5, wantUsed: 15,
		},
		{
			total: 20, free: -1, used: -1,
			wantTotal: 20, wantFree: 20, wantUsed: 0,
		},
		{
			total: -1, free: 5, used: 15,
			wantTotal: 20, wantFree: 5, wantUsed: 15,
		},
		{
			total: -1, free: 15, used: -1,
			wantTotal: 15, wantFree: 15, wantUsed: 0,
		},
		{
			total: -1, free: -1, used: 15,
			wantTotal: 25, wantFree: 10, wantUsed: 15,
		},
		{
			total: -1, free: -1, used: -1,
			wantTotal: 10, wantFree: 10, wantUsed: 0,
		},
	} {
		t.Run(fmt.Sprintf("total=%d,free=%d,used=%d", test.total, test.free, test.used), func(t *testing.T) {
			gotTotal, gotUsed, gotFree := fillInMissingSizes(test.total, test.used, test.free, unknownFree)
			assert.Equal(t, test.wantTotal, gotTotal, "total")
			assert.Equal(t, test.wantUsed, gotUsed, "used")
			assert.Equal(t, test.wantFree, gotFree, "free")
		})
	}
}
<commit_msg>vfs: fix tests for Statfs when running on backends with unknowns<commit_after>// Test suite for vfs

package vfs

import (
	"context"
	"fmt"
	"io"
	"os"
	"testing"

	"github.com/pkg/errors"
	_ "github.com/rclone/rclone/backend/all" // import all the backends
	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/fstest"
	"github.com/rclone/rclone/vfs/vfscommon"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// Some times used in the tests
var (
	t1 = fstest.Time("2001-02-03T04:05:06.499999999Z")
	t2 = fstest.Time("2011-12-25T12:59:59.123456789Z")
	t3 = fstest.Time("2011-12-30T12:59:59.000000000Z")
)

// TestMain drives the tests
func TestMain(m *testing.M) {
	fstest.TestMain(m)
}

// Check baseHandle performs as advertised
func TestVFSbaseHandle(t *testing.T) {
	fh := baseHandle{}

	err := fh.Chdir()
	assert.Equal(t, ENOSYS, err)

	err = fh.Chmod(0)
	assert.Equal(t, ENOSYS, err)

	err = fh.Chown(0, 0)
	assert.Equal(t, ENOSYS, err)

	err = fh.Close()
	assert.Equal(t, ENOSYS, err)

	fd := fh.Fd()
	assert.Equal(t, uintptr(0), fd)

	name := fh.Name()
	assert.Equal(t, "", name)

	_, err = fh.Read(nil)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.ReadAt(nil, 0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Readdir(0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Readdirnames(0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Seek(0, io.SeekStart)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Stat()
	assert.Equal(t, ENOSYS, err)

	err = fh.Sync()
	assert.Equal(t, nil, err)

	err = fh.Truncate(0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.Write(nil)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.WriteAt(nil, 0)
	assert.Equal(t, ENOSYS, err)

	_, err = fh.WriteString("")
	assert.Equal(t, ENOSYS, err)

	err = fh.Flush()
	assert.Equal(t, ENOSYS, err)

	err = fh.Release()
	assert.Equal(t, ENOSYS, err)

	node := fh.Node()
	assert.Nil(t, node)
}

// TestNew sees if the New command works properly
func TestVFSNew(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()

	// Check making a VFS with nil options
	vfs := New(r.Fremote, nil)
	var defaultOpt = vfscommon.DefaultOpt
	defaultOpt.DirPerms |= os.ModeDir
	assert.Equal(t, vfs.Opt, defaultOpt)
	assert.Equal(t, vfs.f, r.Fremote)

	// Check the initialisation
	var opt = vfscommon.DefaultOpt
	opt.DirPerms = 0777
	opt.FilePerms = 0666
	opt.Umask = 0002
	vfs = New(r.Fremote, &opt)
	assert.Equal(t, os.FileMode(0775)|os.ModeDir, vfs.Opt.DirPerms)
	assert.Equal(t, os.FileMode(0664), vfs.Opt.FilePerms)
}

// TestRoot checks root directory is present and correct
func TestVFSRoot(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	root, err := vfs.Root()
	require.NoError(t, err)
	assert.Equal(t, vfs.root, root)
	assert.True(t, root.IsDir())
	assert.Equal(t, vfs.Opt.DirPerms.Perm(), root.Mode().Perm())
}

func TestVFSStat(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
	file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
	fstest.CheckItems(t, r.Fremote, file1, file2)

	node, err := vfs.Stat("file1")
	require.NoError(t, err)
	assert.True(t, node.IsFile())
	assert.Equal(t, "file1", node.Name())

	node, err = vfs.Stat("dir")
	require.NoError(t, err)
	assert.True(t, node.IsDir())
	assert.Equal(t, "dir", node.Name())

	node, err = vfs.Stat("dir/file2")
	require.NoError(t, err)
	assert.True(t, node.IsFile())
	assert.Equal(t, "file2", node.Name())

	_, err = vfs.Stat("not found")
	assert.Equal(t, os.ErrNotExist, err)

	_, err = vfs.Stat("dir/not found")
	assert.Equal(t, os.ErrNotExist, err)

	_, err = vfs.Stat("not found/not found")
	assert.Equal(t, os.ErrNotExist, err)

	_, err = vfs.Stat("file1/under a file")
	assert.Equal(t, os.ErrNotExist, err)
}

func TestVFSStatParent(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
	file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
	fstest.CheckItems(t, r.Fremote, file1, file2)

	node, leaf, err := vfs.StatParent("file1")
	require.NoError(t, err)
	assert.True(t, node.IsDir())
	assert.Equal(t, "/", node.Name())
	assert.Equal(t, "file1", leaf)

	node, leaf, err = vfs.StatParent("dir/file2")
	require.NoError(t, err)
	assert.True(t, node.IsDir())
	assert.Equal(t, "dir", node.Name())
	assert.Equal(t, "file2", leaf)

	node, leaf, err = vfs.StatParent("not found")
	require.NoError(t, err)
	assert.True(t, node.IsDir())
	assert.Equal(t, "/", node.Name())
	assert.Equal(t, "not found", leaf)

	_, _, err = vfs.StatParent("not found dir/not found")
	assert.Equal(t, os.ErrNotExist, err)

	_, _, err = vfs.StatParent("file1/under a file")
	assert.Equal(t, os.ErrExist, err)
}

func TestVFSOpenFile(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
	file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
	fstest.CheckItems(t, r.Fremote, file1, file2)

	fd, err := vfs.OpenFile("file1", os.O_RDONLY, 0777)
	require.NoError(t, err)
	assert.NotNil(t, fd)
	require.NoError(t, fd.Close())

	fd, err = vfs.OpenFile("dir", os.O_RDONLY, 0777)
	require.NoError(t, err)
	assert.NotNil(t, fd)
	require.NoError(t, fd.Close())

	fd, err = vfs.OpenFile("dir/new_file.txt", os.O_RDONLY, 0777)
	assert.Equal(t, os.ErrNotExist, err)
	assert.Nil(t, fd)

	fd, err = vfs.OpenFile("dir/new_file.txt", os.O_WRONLY|os.O_CREATE, 0777)
	require.NoError(t, err)
	assert.NotNil(t, fd)
	err = fd.Close()
	if errors.Cause(err) != fs.ErrorCantUploadEmptyFiles {
		require.NoError(t, err)
	}

	fd, err = vfs.OpenFile("not found/new_file.txt", os.O_WRONLY|os.O_CREATE, 0777)
	assert.Equal(t, os.ErrNotExist, err)
	assert.Nil(t, fd)
}

func TestVFSRename(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	features := r.Fremote.Features()
	if features.Move == nil && features.Copy == nil {
		return // skip as can't rename files
	}
	vfs := New(r.Fremote, nil)

	file1 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
	fstest.CheckItems(t, r.Fremote, file1)

	err := vfs.Rename("dir/file2", "dir/file1")
	require.NoError(t, err)
	file1.Path = "dir/file1"
	fstest.CheckItems(t, r.Fremote, file1)

	err = vfs.Rename("dir/file1", "file0")
	require.NoError(t, err)
	file1.Path = "file0"
	fstest.CheckItems(t, r.Fremote, file1)

	err = vfs.Rename("not found/file0", "file0")
	assert.Equal(t, os.ErrNotExist, err)

	err = vfs.Rename("file0", "not found/file0")
	assert.Equal(t, os.ErrNotExist, err)
}

func TestVFSStatfs(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()
	vfs := New(r.Fremote, nil)

	// pre-conditions
	assert.Nil(t, vfs.usage)
	assert.True(t, vfs.usageTime.IsZero())

	aboutSupported := r.Fremote.Features().About != nil

	// read
	total, used, free := vfs.Statfs()
	if !aboutSupported {
		assert.Equal(t, int64(unknownFreeBytes), total)
		assert.Equal(t, int64(unknownFreeBytes), free)
		assert.Equal(t, int64(0), used)
		return // can't test anything else if About not supported
	}
	require.NotNil(t, vfs.usage)
	assert.False(t, vfs.usageTime.IsZero())
	if vfs.usage.Total != nil {
		assert.Equal(t, *vfs.usage.Total, total)
	} else {
		assert.True(t, total >= int64(unknownFreeBytes))
	}
	if vfs.usage.Free != nil {
		assert.Equal(t, *vfs.usage.Free, free)
	} else {
		assert.True(t, free >= int64(unknownFreeBytes))
	}
	if vfs.usage.Used != nil {
		assert.Equal(t, *vfs.usage.Used, used)
	} else {
		assert.Equal(t, int64(0), used)
	}

	// read cached
	oldUsage := vfs.usage
	oldTime := vfs.usageTime
	total2, used2, free2 := vfs.Statfs()
	assert.Equal(t, oldUsage, vfs.usage)
	assert.Equal(t, total, total2)
	assert.Equal(t, used, used2)
	assert.Equal(t, free, free2)
	assert.Equal(t, oldTime, vfs.usageTime)
}

func TestFillInMissingSizes(t *testing.T) {
	const unknownFree = 10
	for _, test := range []struct {
		total, free, used             int64
		wantTotal, wantUsed, wantFree int64
	}{
		{
			total: 20, free: 5, used: 15,
			wantTotal: 20, wantFree: 5, wantUsed: 15,
		},
		{
			total: 20, free: 5, used: -1,
			wantTotal: 20, wantFree: 5, wantUsed: 15,
		},
		{
			total: 20, free: -1, used: 15,
			wantTotal: 20, wantFree: 5, wantUsed: 15,
		},
		{
			total: 20, free: -1, used: -1,
			wantTotal: 20, wantFree: 20, wantUsed: 0,
		},
		{
			total: -1, free: 5, used: 15,
			wantTotal: 20, wantFree: 5, wantUsed: 15,
		},
		{
			total: -1, free: 15, used: -1,
			wantTotal: 15, wantFree: 15, wantUsed: 0,
		},
		{
			total: -1, free: -1, used: 15,
			wantTotal: 25, wantFree: 10, wantUsed: 15,
		},
		{
			total: -1, free: -1, used: -1,
			wantTotal: 10, wantFree: 10, wantUsed: 0,
		},
	} {
		t.Run(fmt.Sprintf("total=%d,free=%d,used=%d", test.total, test.free, test.used), func(t *testing.T) {
			gotTotal, gotUsed, gotFree := fillInMissingSizes(test.total, test.used, test.free, unknownFree)
			assert.Equal(t, test.wantTotal, gotTotal, "total")
			assert.Equal(t, test.wantUsed, gotUsed, "used")
			assert.Equal(t, test.wantFree, gotFree, "free")
		})
	}
}
<|endoftext|>


<commit_before>package axis

import (
    "sync"
)

type Timer struct {
    position Position
    distance Distance
    channel chan Position
}

type Timers []Timer

type FakeTime struct {
    position Position
    timers map[Position][] chan Position
    mu sync.Mutex
}

func NewFakeTime(position Position) *FakeTime {
    return &FakeTime{
        position: position,
        timers: make(map[Position][] chan Position),
    }
}

func (f *FakeTime) Current() Position {
    return f.position
}

func (f *FakeTime) Sleep(distance Distance) {
    f.Update(addDistance(f.position, distance))
}

func (f *FakeTime) After(distance Distance) <-chan Position {
    c := make(chan Position, 1)
    f.AfterChan(distance, c)
    return c
}

func (f *FakeTime) AfterChan(distance Distance, channel chan Position) *FakeTimeWatcher {
    f.mu.Lock()
    defer f.mu.Unlock()

    until := addDistance(f.position, distance)
    f.timers[until] = append(f.timers[until], channel)
    return &FakeTimeWatcher{can_reset: true, can_stop: true}
}

func (f *FakeTime) Update(position Position) {
    f.position = position

    f.mu.Lock()
    defer f.mu.Unlock()
    for k, v := range f.timers {
        if k < f.position {
            for _, c := range v {
                c <- f.position
            }
            delete(f.timers, k)
        }
    }
}
<commit_msg>Remove unnecessary stuff<commit_after>package axis

import (
    "sync"
)

type FakeTime struct {
    position Position
    timers map[Position][] chan Position
    mu sync.Mutex
}

func NewFakeTime(position Position) *FakeTime {
    return &FakeTime{
        position: position,
        timers: make(map[Position][] chan Position),
    }
}

func (f *FakeTime) Current() Position {
    return f.position
}

func (f *FakeTime) Sleep(distance Distance) {
    f.Update(addDistance(f.position, distance))
}

func (f *FakeTime) After(distance Distance) <-chan Position {
    c := make(chan Position, 1)
    f.AfterChan(distance, c)
    return c
}

func (f *FakeTime) AfterChan(distance Distance, channel chan Position) *FakeTimeWatcher {
    f.mu.Lock()
    defer f.mu.Unlock()

    until := addDistance(f.position, distance)
    f.timers[until] = append(f.timers[until], channel)
    return &FakeTimeWatcher{can_reset: true, can_stop: true}
}

func (f *FakeTime) Update(position Position) {
    f.position = position

    f.mu.Lock()
    defer f.mu.Unlock()
    for k, v := range f.timers {
        if k < f.position {
            for _, c := range v {
                c <- f.position
            }
            delete(f.timers, k)
        }
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2014 The heketi 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 glusterfs

import (
	"errors"
	"fmt"
	"github.com/lpabon/godbc"
	"github.com/lpabon/heketi/requests"
	"github.com/lpabon/heketi/utils"
	"github.com/lpabon/heketi/utils/ssh"
	"strconv"
	"strings"
)

const (
	VGDISPLAY_SIZE_KB                  = 11
	VGDISPLAY_PHYSICAL_EXTENT_SIZE     = 12
	VGDISPLAY_TOTAL_NUMBER_EXTENTS     = 13
	VGDISPLAY_ALLOCATED_NUMBER_EXTENTS = 14
	VGDISPLAY_FREE_NUMBER_EXTENTS      = 15
)

type NodeDB struct {
	Info requests.NodeInfoResp
}

func NewNodeDB(v *requests.NodeAddRequest) *NodeDB {

	node := &NodeDB{}
	node.Info.Id = utils.GenUUID()
	node.Info.Name = v.Name
	node.Info.Zone = v.Zone
	node.Info.Devices = make(map[string]*requests.DeviceResponse)

	return node
}

func (n *NodeDB) DeviceAdd(req *requests.DeviceRequest) error {
	// Setup device object
	dev := &requests.DeviceResponse{}
	dev.Name = req.Name
	dev.Weight = req.Weight
	dev.Id = utils.GenUUID()

	// Add fake info for now
	dev.Free = 10000
	dev.Total = dev.Free

	n.Info.Devices[dev.Id] = dev

	return nil
}

func (n *NodeDB) getVgSizeFromNode(storage *requests.StorageSize, device string) error {

	// Just for now, it will work wih https://github.com/lpabon/vagrant-gfsm
	sshexec := ssh.NewSshExecWithKeyFile("vagrant", "insecure_private_key")
	godbc.Check(sshexec != nil)

	commands := []string{
		fmt.Sprintf("sudo vgdisplay -c %v", "XXXXXXX - FIX ME"),
	}

	b, err := sshexec.ConnectAndExec(n.Info.Name+":22", commands, nil)
	if err != nil {
		return err
	}

	// Example:
	// gfsm:r/w:772:-1:0:0:0:-1:0:4:4:2097135616:4096:511996:0:511996:rJ0bIG-3XNc-NoS0-fkKm-batK-dFyX-xbxHym
	vginfo := strings.Split(b[0], ":")

	// See vgdisplay manpage
	if len(vginfo) < 17 {
		return errors.New("vgdisplay returned an invalid string")
	}

	extent_size, err :=
		strconv.ParseUint(vginfo[VGDISPLAY_PHYSICAL_EXTENT_SIZE], 10, 64)
	if err != nil {
		return err
	}

	free_extents, err :=
		strconv.ParseUint(vginfo[VGDISPLAY_FREE_NUMBER_EXTENTS], 10, 64)
	if err != nil {
		return err
	}

	alloc_extents, err :=
		strconv.ParseUint(vginfo[VGDISPLAY_ALLOCATED_NUMBER_EXTENTS], 10, 64)
	if err != nil {
		return err
	}

	storage.Free = free_extents * extent_size
	storage.Used = alloc_extents * extent_size
	storage.Total, err =
		strconv.ParseUint(vginfo[VGDISPLAY_SIZE_KB], 10, 64)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Setup raw volumes as VGs<commit_after>//
// Copyright (c) 2014 The heketi 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 glusterfs

import (
	"errors"
	"fmt"
	"github.com/lpabon/godbc"
	"github.com/lpabon/heketi/requests"
	"github.com/lpabon/heketi/utils"
	"github.com/lpabon/heketi/utils/ssh"
	"strconv"
	"strings"
)

const (
	VGDISPLAY_SIZE_KB                  = 11
	VGDISPLAY_PHYSICAL_EXTENT_SIZE     = 12
	VGDISPLAY_TOTAL_NUMBER_EXTENTS     = 13
	VGDISPLAY_ALLOCATED_NUMBER_EXTENTS = 14
	VGDISPLAY_FREE_NUMBER_EXTENTS      = 15
)

type NodeDB struct {
	Info requests.NodeInfoResp
}

func NewNodeDB(v *requests.NodeAddRequest) *NodeDB {

	node := &NodeDB{}
	node.Info.Id = utils.GenUUID()
	node.Info.Name = v.Name
	node.Info.Zone = v.Zone
	node.Info.Devices = make(map[string]*requests.DeviceResponse)

	return node
}

func (n *NodeDB) DeviceAdd(req *requests.DeviceRequest) error {
	// Setup device object
	dev := &requests.DeviceResponse{}
	dev.Name = req.Name
	dev.Weight = req.Weight
	dev.Id = utils.GenUUID()

	// Setup --

	// Just for now, it will work wih https://github.com/lpabon/vagrant-gfsm
	sshexec := ssh.NewSshExecWithKeyFile("vagrant", "insecure_private_key")
	godbc.Check(sshexec != nil)

	commands := []string{
		fmt.Sprintf("sudo pvcreate %v", dev.Name),
		fmt.Sprintf("sudo vgcreate vg_%v %v", dev.Id, dev.Name),
	}

	_, err := sshexec.ConnectAndExec(n.Info.Name+":22", commands, nil)
	if err != nil {
		return err
	}

	// Vg info
	err = n.getVgSizeFromNode(dev)
	if err != nil {
		return err
	}

	// Add to db
	n.Info.Devices[dev.Id] = dev

	return nil
}

func (n *NodeDB) getVgSizeFromNode(device *requests.DeviceResponse) error {

	// Just for now, it will work wih https://github.com/lpabon/vagrant-gfsm
	sshexec := ssh.NewSshExecWithKeyFile("vagrant", "insecure_private_key")
	godbc.Check(sshexec != nil)

	commands := []string{
		fmt.Sprintf("sudo vgdisplay -c vg_%v", device.Id),
	}

	b, err := sshexec.ConnectAndExec(n.Info.Name+":22", commands, nil)
	if err != nil {
		return err
	}

	// Example:
	// gfsm:r/w:772:-1:0:0:0:-1:0:4:4:2097135616:4096:511996:0:511996:rJ0bIG-3XNc-NoS0-fkKm-batK-dFyX-xbxHym
	vginfo := strings.Split(b[0], ":")

	// See vgdisplay manpage
	if len(vginfo) < 17 {
		return errors.New("vgdisplay returned an invalid string")
	}

	extent_size, err :=
		strconv.ParseUint(vginfo[VGDISPLAY_PHYSICAL_EXTENT_SIZE], 10, 64)
	if err != nil {
		return err
	}

	free_extents, err :=
		strconv.ParseUint(vginfo[VGDISPLAY_FREE_NUMBER_EXTENTS], 10, 64)
	if err != nil {
		return err
	}

	alloc_extents, err :=
		strconv.ParseUint(vginfo[VGDISPLAY_ALLOCATED_NUMBER_EXTENTS], 10, 64)
	if err != nil {
		return err
	}

	device.Free = free_extents * extent_size
	device.Used = alloc_extents * extent_size
	device.Total, err = strconv.ParseUint(vginfo[VGDISPLAY_SIZE_KB], 10, 64)
	if err != nil {
		return err
	}

	n.Info.Storage.Free += device.Free
	n.Info.Storage.Used += device.Used
	n.Info.Storage.Total += device.Total

	return nil
}
<|endoftext|>


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

package mq

import (
	"context"
	"encoding/json"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"github.com/shawnfeng/sutil/scontext"
)

type Payload struct {
	Carrier opentracing.TextMapCarrier `json:"c"`
	Value   string                     `json:"v"`
	Head    interface{}                `json:"h"`
	Control interface{}                `json:"t"`
}

func generatePayload(ctx context.Context, value interface{}) (*Payload, error) {
	carrier := opentracing.TextMapCarrier(make(map[string]string))
	span := opentracing.SpanFromContext(ctx)
	if span != nil {
		opentracing.GlobalTracer().Inject(
			span.Context(),
			opentracing.TextMap,
			carrier)
	}

	msg, err := json.Marshal(value)
	if err != nil {
		return nil, err
	}
	head := ctx.Value(scontext.ContextKeyHead)
	control := ctx.Value(scontext.ContextKeyControl)

	return &Payload{
		Carrier: carrier,
		Value:   string(msg),
		Head:    head,
		Control: control,
	}, nil
}

func generateMsgsPayload(ctx context.Context, msgs ...Message) ([]Message, error) {
	carrier := opentracing.TextMapCarrier(make(map[string]string))
	span := opentracing.SpanFromContext(ctx)
	if span != nil {
		opentracing.GlobalTracer().Inject(
			span.Context(),
			opentracing.TextMap,
			carrier)
	}
	head := ctx.Value(scontext.ContextKeyHead)
	control := ctx.Value(scontext.ContextKeyControl)

	var nmsgs []Message
	for _, msg := range msgs {
		body, err := json.Marshal(msg.Value)
		if err != nil {
			return nil, err
		}
		nmsgs = append(nmsgs, Message{
			Key: msg.Key,
			Value: &Payload{
				Carrier: carrier,
				Value:   string(body),
				Head:    head,
				Control: control,
			},
		})
	}

	return nmsgs, nil
}

func parsePayload(payload *Payload, opName string, value interface{}) (context.Context, error) {
	tracer := opentracing.GlobalTracer()
	spanCtx, err := tracer.Extract(opentracing.TextMap, opentracing.TextMapCarrier(payload.Carrier))
	var span opentracing.Span
	if err == nil {
		span = tracer.StartSpan(opName, ext.RPCServerOption(spanCtx))
	} else {
		span = tracer.StartSpan(opName)
	}
	ctx := context.Background()
	ctx = opentracing.ContextWithSpan(ctx, span)
	ctx = context.WithValue(ctx, scontext.ContextKeyHead, payload.Head)
	ctx = context.WithValue(ctx, scontext.ContextKeyControl, payload.Control)

	err = json.Unmarshal([]byte(payload.Value), value)
	if err != nil {
		return nil, err
	}

	return ctx, nil
}
<commit_msg>bugfix: return context when parsePayload failed<commit_after>// Copyright 2014 The mqrouter Author. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mq

import (
	"context"
	"encoding/json"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"github.com/shawnfeng/sutil/scontext"
)

type Payload struct {
	Carrier opentracing.TextMapCarrier `json:"c"`
	Value   string                     `json:"v"`
	Head    interface{}                `json:"h"`
	Control interface{}                `json:"t"`
}

func generatePayload(ctx context.Context, value interface{}) (*Payload, error) {
	carrier := opentracing.TextMapCarrier(make(map[string]string))
	span := opentracing.SpanFromContext(ctx)
	if span != nil {
		opentracing.GlobalTracer().Inject(
			span.Context(),
			opentracing.TextMap,
			carrier)
	}

	msg, err := json.Marshal(value)
	if err != nil {
		return nil, err
	}
	head := ctx.Value(scontext.ContextKeyHead)
	control := ctx.Value(scontext.ContextKeyControl)

	return &Payload{
		Carrier: carrier,
		Value:   string(msg),
		Head:    head,
		Control: control,
	}, nil
}

func generateMsgsPayload(ctx context.Context, msgs ...Message) ([]Message, error) {
	carrier := opentracing.TextMapCarrier(make(map[string]string))
	span := opentracing.SpanFromContext(ctx)
	if span != nil {
		opentracing.GlobalTracer().Inject(
			span.Context(),
			opentracing.TextMap,
			carrier)
	}
	head := ctx.Value(scontext.ContextKeyHead)
	control := ctx.Value(scontext.ContextKeyControl)

	var nmsgs []Message
	for _, msg := range msgs {
		body, err := json.Marshal(msg.Value)
		if err != nil {
			return nil, err
		}
		nmsgs = append(nmsgs, Message{
			Key: msg.Key,
			Value: &Payload{
				Carrier: carrier,
				Value:   string(body),
				Head:    head,
				Control: control,
			},
		})
	}

	return nmsgs, nil
}

func parsePayload(payload *Payload, opName string, value interface{}) (context.Context, error) {
	tracer := opentracing.GlobalTracer()
	spanCtx, err := tracer.Extract(opentracing.TextMap, opentracing.TextMapCarrier(payload.Carrier))
	var span opentracing.Span
	if err == nil {
		span = tracer.StartSpan(opName, ext.RPCServerOption(spanCtx))
	} else {
		span = tracer.StartSpan(opName)
	}
	ctx := context.Background()
	ctx = opentracing.ContextWithSpan(ctx, span)
	ctx = context.WithValue(ctx, scontext.ContextKeyHead, payload.Head)
	ctx = context.WithValue(ctx, scontext.ContextKeyControl, payload.Control)

	err = json.Unmarshal([]byte(payload.Value), value)
	if err != nil {
		return ctx, err
	}

	return ctx, nil
}
<|endoftext|>


<commit_before>package main

import "github.com/cnf/go-claw/targets/denon"
import "github.com/cnf/go-claw/targets/plex"
import "github.com/cnf/go-claw/targets/linux"

func registerAllTargets() {
    denon.Register()
    plex.Register()
    linux.Register()
}
<commit_msg>Added onkyo module registration<commit_after>package main

import "github.com/cnf/go-claw/targets/denon"
import "github.com/cnf/go-claw/targets/plex"
import "github.com/cnf/go-claw/targets/linux"
import "github.com/cnf/go-claw/targets/onkyo"

func registerAllTargets() {
    denon.Register()
    plex.Register()
    linux.Register()
    onkyo.Register()
}
<|endoftext|>


<commit_before>package usecase

import (
	"context"
	"strings"
	"time"

	"github.com/oinume/lekcije/backend/domain/repository"
	"github.com/oinume/lekcije/backend/model2"
)

type Lesson struct {
	lessonRepo          repository.Lesson
	lessonStatusLogRepo repository.LessonStatusLog
}

func NewLesson(
	lessonRepo repository.Lesson,
	lessonStatusLogRepo repository.LessonStatusLog,
) *Lesson {
	return &Lesson{
		lessonRepo:          lessonRepo,
		lessonStatusLogRepo: lessonStatusLogRepo,
	}
}

func (u *Lesson) FindLessons(
	ctx context.Context,
	teacherID uint, fromDate, toDate time.Time,
) ([]*model2.Lesson, error) {
	return u.lessonRepo.FindAllByTeacherIDsDatetimeBetween(ctx, teacherID, fromDate, toDate)
}

func (u *Lesson) GetNewAvailableLessons(ctx context.Context, oldLessons, newLessons []*model2.Lesson) []*model2.Lesson {
	return u.lessonRepo.GetNewAvailableLessons(ctx, oldLessons, newLessons)
}

func (u *Lesson) UpdateLessons(ctx context.Context, lessons []*model2.Lesson) (int, error) {
	if len(lessons) == 0 {
		return 0, nil
	}

	existingLessons, err := u.lessonRepo.FindAllByTeacherIDAndDatetimeAsMap(ctx, lessons[0].TeacherID, lessons)
	if err != nil {
		return 0, err
	}

	rowsAffected := 0
	now := time.Now().UTC()
	for _, lesson := range lessons {
		lesson.Status = strings.ToLower(lesson.Status)
		if l, ok := existingLessons[model2.LessonDatetime(lesson.Datetime).String()]; ok {
			if lesson.Status == l.Status {
				continue
			}
			// UPDATE
			if err := u.lessonRepo.UpdateStatus(ctx, lesson.ID, lesson.Status); err != nil {
				return 0, err
			}
			if err := u.createLessonStatusLog(ctx, lesson.ID, lesson.Status, now); err != nil {
				return 0, err
			}
		} else {
			// INSERT
			dt := lesson.Datetime
			lesson.Datetime = time.Date(dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), dt.Second(), 0, time.UTC)
			if err := u.lessonRepo.Create(ctx, lesson, true); err != nil {
				return 0, err
			}
			// TODO: transaction
			if err := u.createLessonStatusLog(ctx, lesson.ID, lesson.Status, now); err != nil {
				return 0, err
			}
		}
		rowsAffected++
	}

	return rowsAffected, nil
}

func (u *Lesson) createLessonStatusLog(ctx context.Context, lessonID uint64, status string, createdAt time.Time) error {
	log := &model2.LessonStatusLog{
		LessonID:  lessonID,
		Status:    status,
		CreatedAt: createdAt,
	}
	if err := u.lessonStatusLogRepo.Create(ctx, log); err != nil {
		return err
	}
	return nil
}
<commit_msg>Use FindOrCreate<commit_after>package usecase

import (
	"context"
	"strings"
	"time"

	"github.com/oinume/lekcije/backend/domain/repository"
	"github.com/oinume/lekcije/backend/model2"
)

type Lesson struct {
	lessonRepo          repository.Lesson
	lessonStatusLogRepo repository.LessonStatusLog
}

func NewLesson(
	lessonRepo repository.Lesson,
	lessonStatusLogRepo repository.LessonStatusLog,
) *Lesson {
	return &Lesson{
		lessonRepo:          lessonRepo,
		lessonStatusLogRepo: lessonStatusLogRepo,
	}
}

func (u *Lesson) FindLessons(
	ctx context.Context,
	teacherID uint, fromDate, toDate time.Time,
) ([]*model2.Lesson, error) {
	return u.lessonRepo.FindAllByTeacherIDsDatetimeBetween(ctx, teacherID, fromDate, toDate)
}

func (u *Lesson) GetNewAvailableLessons(ctx context.Context, oldLessons, newLessons []*model2.Lesson) []*model2.Lesson {
	return u.lessonRepo.GetNewAvailableLessons(ctx, oldLessons, newLessons)
}

func (u *Lesson) UpdateLessons(ctx context.Context, lessons []*model2.Lesson) (int, error) {
	if len(lessons) == 0 {
		return 0, nil
	}

	existingLessons, err := u.lessonRepo.FindAllByTeacherIDAndDatetimeAsMap(ctx, lessons[0].TeacherID, lessons)
	if err != nil {
		return 0, err
	}

	rowsAffected := 0
	now := time.Now().UTC()
	for _, lesson := range lessons {
		lesson.Status = strings.ToLower(lesson.Status)
		if existing, ok := existingLessons[model2.LessonDatetime(lesson.Datetime).String()]; ok {
			if lesson.Status == existing.Status {
				continue
			}
			// UPDATE
			if err := u.lessonRepo.UpdateStatus(ctx, lesson.ID, lesson.Status); err != nil {
				return 0, err
			}
			if err := u.createLessonStatusLog(ctx, lesson.ID, lesson.Status, now); err != nil {
				return 0, err
			}
		} else {
			// INSERT
			dt := lesson.Datetime
			lesson.Datetime = time.Date(dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), dt.Second(), 0, time.UTC)
			l, err := u.lessonRepo.FindOrCreate(ctx, lesson, true)
			if err != nil {
				return 0, err
			}
			// TODO: transaction
			if err := u.createLessonStatusLog(ctx, l.ID, l.Status, now); err != nil {
				return 0, err
			}
		}
		rowsAffected++
	}

	return rowsAffected, nil
}

func (u *Lesson) createLessonStatusLog(ctx context.Context, lessonID uint64, status string, createdAt time.Time) error {
	log := &model2.LessonStatusLog{
		LessonID:  lessonID,
		Status:    status,
		CreatedAt: createdAt,
	}
	if err := u.lessonStatusLogRepo.Create(ctx, log); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package networkinterface

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"strings"

	"github.com/r3labs/terraform/helper/hashcode"
	"github.com/r3labs/terraform/helper/schema"

	aes "github.com/ernestio/crypto/aes"
	"github.com/ernestio/ernestprovider/event"
	"github.com/ernestio/ernestprovider/providers/azure"
	"github.com/r3labs/terraform/builtin/providers/azurerm"
)

// Event : This is the Ernest representation of an azure networkinterface
type Event struct {
	event.Base
	ID                     string            `json:"id"`
	Name                   string            `json:"name" validate:"required"`
	ResourceGroupName      string            `json:"resource_group_name" validate:"required"`
	Location               string            `json:"location"`
	NetworkSecurityGroup   string            `json:"network_security_group"`
	NetworkSecurityGroupID string            `json:"network_security_group_id"`
	MacAddress             string            `json:"mac_address"`
	PrivateIPAddress       string            `json:"private_ip_address"`
	VirtualMachineID       string            `json:"virtual_machine_id"`
	IPConfigurations       []IPConfiguration `json:"ip_configuration" structs:"ip_configuration"` // validate:"min=1,dive"`
	DNSServers             []string          `json:"dns_servers" validate:"dive,ip"`
	InternalDNSNameLabel   string            `json:"internal_dns_name_label"`
	AppliedDNSServers      []string          `json:"applied_dns_servers"`
	InternalFQDN           string            `json:"internal_fqdn"`
	EnableIPForwarding     bool              `json:"enable_ip_forwarding"`
	Tags                   map[string]string `json:"tags"`
	ClientID               string            `json:"azure_client_id"`
	ClientSecret           string            `json:"azure_client_secret"`
	TenantID               string            `json:"azure_tenant_id"`
	SubscriptionID         string            `json:"azure_subscription_id"`
	Environment            string            `json:"environment"`
	ErrorMessage           string            `json:"error,omitempty"`
	Components             []json.RawMessage `json:"components"`
	CryptoKey              string            `json:"-"`
	Validator              *event.Validator  `json:"-"`
	GenericEvent           event.Event       `json:"-" validate:"-"`
}

// IPConfiguration : ...
type IPConfiguration struct {
	Name                              string   `json:"name" validate:"required" structs:"name"`
	Subnet                            string   `json:"subnet" validate:"required" structs:"-"`
	SubnetID                          string   `json:"subnet_id" validate:"required" structs:"subnet_id"`
	PublicIPAddress                   string   `json:"public_ip_address" structs:"-"`
	PrivateIPAddress                  string   `json:"private_ip_address" structs:"private_ip_address"`
	PrivateIPAddressAllocation        string   `json:"private_ip_address_allocation" validate:"required" structs:"private_ip_address_allocation"`
	PublicIPAddressID                 string   `json:"public_ip_address_id" structs:"public_ip_address_id"`
	LoadBalancerBackendAddressPools   []string `json:"load_balancer_backend_address_pools" structs:"-"`
	LoadBalancerBackendAddressPoolIDs []string `json:"load_balancer_backend_address_pools_ids" structs:"load_balancer_backend_address_pools_ids,omitempty"`
	LoadBalancerInboundNatRules       []string `json:"load_balancer_inbound_nat_rules_ids" structs:"load_balancer_inbound_nat_rules_ids,omitempty"`
}

// New : Constructor
func New(subject, cryptoKey string, body []byte, val *event.Validator) (event.Event, error) {
	// var ev event.Resource
	ev := &Event{CryptoKey: cryptoKey, Validator: val}
	body = []byte(strings.Replace(string(body), `"_component":"network_interfaces"`, `"_component":"network_interface"`, 1))
	if err := json.Unmarshal(body, &ev); err != nil {
		err := fmt.Errorf("Error on input message : %s", err)
		return nil, err
	}

	ev.GenericEvent, _ = azure.New(subject, "azurerm_network_interface", body, val, ev)
	return ev.GenericEvent, nil
}

// SetComponents : ....
func (ev *Event) SetComponents(components []event.Event) {
	for _, v := range components {
		ev.Components = append(ev.Components, v.GetBody())
	}
}

// ValidateID : determines if the given id is valid for this resource type
func (ev *Event) ValidateID(id string) bool {
	parts := strings.Split(strings.ToLower(id), "/")
	if len(parts) != 9 {
		return false
	}
	if parts[6] != "microsoft.network" {
		return false
	}
	if parts[7] != "networkinterfaces" {
		return false
	}
	return true
}

// SetID : id setter
func (ev *Event) SetID(id string) {
	ev.ID = id
}

// GetID : id getter
func (ev *Event) GetID() string {
	return ev.ID
}

// SetState : state setter
func (ev *Event) SetState(state string) {
	ev.State = state
}

// ResourceDataToEvent : Translates a ResourceData on a valid Ernest Event
func (ev *Event) ResourceDataToEvent(d *schema.ResourceData) error {

	ev.ID = d.Id()
	if ev.ID == "" {
		ev.Name = d.Get("name").(string)
	} else {
		parts := strings.Split(ev.ID, "/")
		ev.Name = parts[8]
	}
	ev.ComponentID = "network_interface::" + ev.Name
	ev.ResourceGroupName = d.Get("resource_group_name").(string)
	ev.Location = d.Get("location").(string)
	ev.NetworkSecurityGroupID = d.Get("network_security_group_id").(string)
	ev.MacAddress = d.Get("mac_address").(string)
	ev.PrivateIPAddress = d.Get("private_ip_address").(string)
	ev.VirtualMachineID = d.Get("virtual_machine_id").(string)

	configs := []IPConfiguration{}

	cli, _ := ev.GenericEvent.Client()
	list := cli.ListNetworkInterfaceConfigurations(ev.ResourceGroupName, ev.Name)

	for _, mo := range list {
		configs = append(configs, IPConfiguration{
			Name:                              mo["name"],
			SubnetID:                          mo["subnet_id"],
			PrivateIPAddress:                  mo["private_ip_address"],
			PrivateIPAddressAllocation:        mo["private_ip_address_allocation"],
			PublicIPAddressID:                 mo["public_ip_address_id"],
			LoadBalancerBackendAddressPoolIDs: strings.Split(mo["load_balancer_backend_address_pools_ids"], ","),
			LoadBalancerInboundNatRules:       strings.Split(mo["load_balancer_inbound_nat_rules_ids"], ","),
		})
	}
	ev.IPConfigurations = configs
	ev.DNSServers = make([]string, 0)
	for _, v := range d.Get("dns_servers").(*schema.Set).List() {
		ev.DNSServers = append(ev.DNSServers, v.(string))
	}

	ev.InternalDNSNameLabel = d.Get("internal_dns_name_label").(string)
	ev.AppliedDNSServers = make([]string, 0)
	for _, v := range d.Get("applied_dns_servers").(*schema.Set).List() {
		ev.AppliedDNSServers = append(ev.AppliedDNSServers, v.(string))
	}

	ev.InternalFQDN = d.Get("internal_fqdn").(string)
	ev.EnableIPForwarding = d.Get("enable_ip_forwarding").(bool)

	tags := d.Get("tags").(map[string]interface{})
	ev.Tags = make(map[string]string, 0)
	for k, v := range tags {
		ev.Tags[k] = v.(string)
	}

	return nil
}

// EventToResourceData : Translates the current event on a valid ResourceData
func (ev *Event) EventToResourceData(d *schema.ResourceData) error {
	crypto := aes.New()

	encFields := make(map[string]string)
	encFields["subscription_id"] = ev.SubscriptionID
	encFields["client_id"] = ev.ClientID
	encFields["client_secret"] = ev.ClientSecret
	encFields["tenant_id"] = ev.TenantID
	encFields["environment"] = ev.Environment
	for k, v := range encFields {
		dec, err := crypto.Decrypt(v, ev.CryptoKey)
		if err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
		if err := d.Set(k, dec); err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
	}

	fields := make(map[string]interface{})
	fields["name"] = ev.Name
	fields["resource_group_name"] = ev.ResourceGroupName
	fields["location"] = ev.Location
	fields["network_security_group_id"] = ev.NetworkSecurityGroupID
	fields["mac_address"] = ev.MacAddress
	fields["private_ip_address"] = ev.PrivateIPAddress
	fields["virtual_machine_id"] = ev.VirtualMachineID
	fields["ip_configuration"] = ev.mapIPConfigurations()
	fields["dns_servers"] = ev.DNSServers
	fields["internal_dns_name_label"] = ev.InternalDNSNameLabel
	fields["applied_dns_servers"] = ev.AppliedDNSServers
	fields["internal_fqdn"] = ev.InternalFQDN
	fields["enable_ip_forwarding"] = ev.EnableIPForwarding
	fields["tags"] = ev.Tags
	for k, v := range fields {
		if err := d.Set(k, v); err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
	}

	return nil
}

func (ev *Event) mapIPConfigurations() *schema.Set {
	list := &schema.Set{
		F: resourceArmNetworkInterfaceIPConfigurationHash,
	}
	for _, c := range ev.IPConfigurations {
		conf := map[string]interface{}{}
		conf["name"] = c.Name
		conf["subnet_id"] = c.SubnetID
		conf["private_ip_address"] = c.PrivateIPAddress
		conf["private_ip_address_allocation"] = c.PrivateIPAddressAllocation
		conf["public_ip_address_id"] = c.PublicIPAddressID
		l1 := schema.Set{
			F: resourceHashArnString,
		}
		for _, v := range c.LoadBalancerBackendAddressPoolIDs {
			l1.Add(v)
		}
		conf["load_balancer_backend_address_pools_ids"] = &l1
		l2 := schema.Set{
			F: resourceHashArnString,
		}
		for _, v := range c.LoadBalancerInboundNatRules {
			l2.Add(v)
		}
		conf["load_balancer_inbound_nat_rules_ids"] = &l2
		list.Add(conf)
	}
	return list
}

func resourceArmNetworkInterfaceIPConfigurationHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["subnet_id"].(string)))
	if m["private_ip_address"] != nil {
		buf.WriteString(fmt.Sprintf("%s-", m["private_ip_address"].(string)))
	}
	buf.WriteString(fmt.Sprintf("%s-", m["private_ip_address_allocation"].(string)))
	if m["public_ip_address_id"] != nil {
		buf.WriteString(fmt.Sprintf("%s-", m["public_ip_address_id"].(string)))
	}
	if m["load_balancer_backend_address_pools_ids"] != nil {
		str := fmt.Sprintf("*Set(%s)", m["load_balancer_backend_address_pools_ids"].(*schema.Set))
		buf.WriteString(fmt.Sprintf("%s-", str))
	}
	if m["load_balancer_inbound_nat_rules_ids"] != nil {
		str := fmt.Sprintf("*Set(%s)", m["load_balancer_inbound_nat_rules_ids"].(*schema.Set))
		buf.WriteString(fmt.Sprintf("%s-", str))
	}

	return hashcode.String(buf.String())
}

func resourceHashArnString(v interface{}) int {
	var buf bytes.Buffer

	buf.WriteString(fmt.Sprintf("%d-", schema.HashString(v.(string))))

	return hashcode.String(buf.String())
}

// Clone : will mark the event as errored
func (ev *Event) Clone() (event.Event, error) {
	body, _ := json.Marshal(ev)
	return New(ev.Subject, ev.CryptoKey, body, ev.Validator)
}

// Error : will mark the event as errored
func (ev *Event) Error(err error) {
	ev.ErrorMessage = err.Error()
	ev.Body, err = json.Marshal(ev)
}

// Client : not implemented
func (ev *Event) Client() (*azurerm.ArmClient, error) {
	return nil, errors.New("Not implemented")
}
<commit_msg>Filter network.ip_configurations when importing<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package networkinterface

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"strings"

	"github.com/r3labs/terraform/helper/hashcode"
	"github.com/r3labs/terraform/helper/schema"

	aes "github.com/ernestio/crypto/aes"
	"github.com/ernestio/ernestprovider/event"
	"github.com/ernestio/ernestprovider/providers/azure"
	"github.com/r3labs/terraform/builtin/providers/azurerm"
)

// Event : This is the Ernest representation of an azure networkinterface
type Event struct {
	event.Base
	ID                     string            `json:"id"`
	Name                   string            `json:"name" validate:"required"`
	ResourceGroupName      string            `json:"resource_group_name" validate:"required"`
	Location               string            `json:"location"`
	NetworkSecurityGroup   string            `json:"network_security_group"`
	NetworkSecurityGroupID string            `json:"network_security_group_id"`
	MacAddress             string            `json:"mac_address"`
	PrivateIPAddress       string            `json:"private_ip_address"`
	VirtualMachineID       string            `json:"virtual_machine_id"`
	IPConfigurations       []IPConfiguration `json:"ip_configuration" structs:"ip_configuration"` // validate:"min=1,dive"`
	DNSServers             []string          `json:"dns_servers" validate:"dive,ip"`
	InternalDNSNameLabel   string            `json:"internal_dns_name_label"`
	AppliedDNSServers      []string          `json:"applied_dns_servers"`
	InternalFQDN           string            `json:"internal_fqdn"`
	EnableIPForwarding     bool              `json:"enable_ip_forwarding"`
	Tags                   map[string]string `json:"tags"`
	ClientID               string            `json:"azure_client_id"`
	ClientSecret           string            `json:"azure_client_secret"`
	TenantID               string            `json:"azure_tenant_id"`
	SubscriptionID         string            `json:"azure_subscription_id"`
	Environment            string            `json:"environment"`
	ErrorMessage           string            `json:"error,omitempty"`
	Components             []json.RawMessage `json:"components"`
	CryptoKey              string            `json:"-"`
	Validator              *event.Validator  `json:"-"`
	GenericEvent           event.Event       `json:"-" validate:"-"`
}

// IPConfiguration : ...
type IPConfiguration struct {
	Name                              string   `json:"name" validate:"required" structs:"name"`
	Subnet                            string   `json:"subnet" validate:"required" structs:"-"`
	SubnetID                          string   `json:"subnet_id" validate:"required" structs:"subnet_id"`
	PublicIPAddress                   string   `json:"public_ip_address" structs:"-"`
	PrivateIPAddress                  string   `json:"private_ip_address" structs:"private_ip_address"`
	PrivateIPAddressAllocation        string   `json:"private_ip_address_allocation" validate:"required" structs:"private_ip_address_allocation"`
	PublicIPAddressID                 string   `json:"public_ip_address_id" structs:"public_ip_address_id"`
	LoadBalancerBackendAddressPools   []string `json:"load_balancer_backend_address_pools" structs:"-"`
	LoadBalancerBackendAddressPoolIDs []string `json:"load_balancer_backend_address_pools_ids" structs:"load_balancer_backend_address_pools_ids,omitempty"`
	LoadBalancerInboundNatRules       []string `json:"load_balancer_inbound_nat_rules_ids" structs:"load_balancer_inbound_nat_rules_ids,omitempty"`
}

// New : Constructor
func New(subject, cryptoKey string, body []byte, val *event.Validator) (event.Event, error) {
	// var ev event.Resource
	ev := &Event{CryptoKey: cryptoKey, Validator: val}
	body = []byte(strings.Replace(string(body), `"_component":"network_interfaces"`, `"_component":"network_interface"`, 1))
	if err := json.Unmarshal(body, &ev); err != nil {
		err := fmt.Errorf("Error on input message : %s", err)
		return nil, err
	}

	ev.GenericEvent, _ = azure.New(subject, "azurerm_network_interface", body, val, ev)
	return ev.GenericEvent, nil
}

// SetComponents : ....
func (ev *Event) SetComponents(components []event.Event) {
	for _, v := range components {
		ev.Components = append(ev.Components, v.GetBody())
	}
}

// ValidateID : determines if the given id is valid for this resource type
func (ev *Event) ValidateID(id string) bool {
	parts := strings.Split(strings.ToLower(id), "/")
	if len(parts) != 9 {
		return false
	}
	if parts[6] != "microsoft.network" {
		return false
	}
	if parts[7] != "networkinterfaces" {
		return false
	}
	return true
}

// SetID : id setter
func (ev *Event) SetID(id string) {
	ev.ID = id
}

// GetID : id getter
func (ev *Event) GetID() string {
	return ev.ID
}

// SetState : state setter
func (ev *Event) SetState(state string) {
	ev.State = state
}

// ResourceDataToEvent : Translates a ResourceData on a valid Ernest Event
func (ev *Event) ResourceDataToEvent(d *schema.ResourceData) error {

	ev.ID = d.Id()
	if ev.ID == "" {
		ev.Name = d.Get("name").(string)
	} else {
		parts := strings.Split(ev.ID, "/")
		ev.Name = parts[8]
	}
	ev.ComponentID = "network_interface::" + ev.Name
	ev.ResourceGroupName = d.Get("resource_group_name").(string)
	ev.Location = d.Get("location").(string)
	ev.NetworkSecurityGroupID = d.Get("network_security_group_id").(string)
	ev.MacAddress = d.Get("mac_address").(string)
	ev.PrivateIPAddress = d.Get("private_ip_address").(string)
	ev.VirtualMachineID = d.Get("virtual_machine_id").(string)

	configs := []IPConfiguration{}

	cli, _ := ev.GenericEvent.Client()
	list := cli.ListNetworkInterfaceConfigurations(ev.ResourceGroupName, ev.Name)

	for _, mo := range list {
		parts := strings.Split(mo["public_ip_address_id"], "/")
		parts = strings.Split(parts[len(parts)-1], "-")
		parts = parts[:len(parts)-1]
		name := strings.Join(parts, "-")

		if name == ev.Name {
			configs = append(configs, IPConfiguration{
				Name:                              mo["name"],
				SubnetID:                          mo["subnet_id"],
				PrivateIPAddress:                  mo["private_ip_address"],
				PrivateIPAddressAllocation:        mo["private_ip_address_allocation"],
				PublicIPAddressID:                 mo["public_ip_address_id"],
				LoadBalancerBackendAddressPoolIDs: strings.Split(mo["load_balancer_backend_address_pools_ids"], ","),
				LoadBalancerInboundNatRules:       strings.Split(mo["load_balancer_inbound_nat_rules_ids"], ","),
			})
		}
	}
	ev.IPConfigurations = configs
	ev.DNSServers = make([]string, 0)
	for _, v := range d.Get("dns_servers").(*schema.Set).List() {
		ev.DNSServers = append(ev.DNSServers, v.(string))
	}

	ev.InternalDNSNameLabel = d.Get("internal_dns_name_label").(string)
	ev.AppliedDNSServers = make([]string, 0)
	for _, v := range d.Get("applied_dns_servers").(*schema.Set).List() {
		ev.AppliedDNSServers = append(ev.AppliedDNSServers, v.(string))
	}

	ev.InternalFQDN = d.Get("internal_fqdn").(string)
	ev.EnableIPForwarding = d.Get("enable_ip_forwarding").(bool)

	tags := d.Get("tags").(map[string]interface{})
	ev.Tags = make(map[string]string, 0)
	for k, v := range tags {
		ev.Tags[k] = v.(string)
	}

	return nil
}

// EventToResourceData : Translates the current event on a valid ResourceData
func (ev *Event) EventToResourceData(d *schema.ResourceData) error {
	crypto := aes.New()

	encFields := make(map[string]string)
	encFields["subscription_id"] = ev.SubscriptionID
	encFields["client_id"] = ev.ClientID
	encFields["client_secret"] = ev.ClientSecret
	encFields["tenant_id"] = ev.TenantID
	encFields["environment"] = ev.Environment
	for k, v := range encFields {
		dec, err := crypto.Decrypt(v, ev.CryptoKey)
		if err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
		if err := d.Set(k, dec); err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
	}

	fields := make(map[string]interface{})
	fields["name"] = ev.Name
	fields["resource_group_name"] = ev.ResourceGroupName
	fields["location"] = ev.Location
	fields["network_security_group_id"] = ev.NetworkSecurityGroupID
	fields["mac_address"] = ev.MacAddress
	fields["private_ip_address"] = ev.PrivateIPAddress
	fields["virtual_machine_id"] = ev.VirtualMachineID
	fields["ip_configuration"] = ev.mapIPConfigurations()
	fields["dns_servers"] = ev.DNSServers
	fields["internal_dns_name_label"] = ev.InternalDNSNameLabel
	fields["applied_dns_servers"] = ev.AppliedDNSServers
	fields["internal_fqdn"] = ev.InternalFQDN
	fields["enable_ip_forwarding"] = ev.EnableIPForwarding
	fields["tags"] = ev.Tags
	for k, v := range fields {
		if err := d.Set(k, v); err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
	}

	return nil
}

func (ev *Event) mapIPConfigurations() *schema.Set {
	list := &schema.Set{
		F: resourceArmNetworkInterfaceIPConfigurationHash,
	}
	for _, c := range ev.IPConfigurations {
		conf := map[string]interface{}{}
		conf["name"] = c.Name
		conf["subnet_id"] = c.SubnetID
		conf["private_ip_address"] = c.PrivateIPAddress
		conf["private_ip_address_allocation"] = c.PrivateIPAddressAllocation
		conf["public_ip_address_id"] = c.PublicIPAddressID
		l1 := schema.Set{
			F: resourceHashArnString,
		}
		for _, v := range c.LoadBalancerBackendAddressPoolIDs {
			l1.Add(v)
		}
		conf["load_balancer_backend_address_pools_ids"] = &l1
		l2 := schema.Set{
			F: resourceHashArnString,
		}
		for _, v := range c.LoadBalancerInboundNatRules {
			l2.Add(v)
		}
		conf["load_balancer_inbound_nat_rules_ids"] = &l2
		list.Add(conf)
	}
	return list
}

func resourceArmNetworkInterfaceIPConfigurationHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["subnet_id"].(string)))
	if m["private_ip_address"] != nil {
		buf.WriteString(fmt.Sprintf("%s-", m["private_ip_address"].(string)))
	}
	buf.WriteString(fmt.Sprintf("%s-", m["private_ip_address_allocation"].(string)))
	if m["public_ip_address_id"] != nil {
		buf.WriteString(fmt.Sprintf("%s-", m["public_ip_address_id"].(string)))
	}
	if m["load_balancer_backend_address_pools_ids"] != nil {
		str := fmt.Sprintf("*Set(%s)", m["load_balancer_backend_address_pools_ids"].(*schema.Set))
		buf.WriteString(fmt.Sprintf("%s-", str))
	}
	if m["load_balancer_inbound_nat_rules_ids"] != nil {
		str := fmt.Sprintf("*Set(%s)", m["load_balancer_inbound_nat_rules_ids"].(*schema.Set))
		buf.WriteString(fmt.Sprintf("%s-", str))
	}

	return hashcode.String(buf.String())
}

func resourceHashArnString(v interface{}) int {
	var buf bytes.Buffer

	buf.WriteString(fmt.Sprintf("%d-", schema.HashString(v.(string))))

	return hashcode.String(buf.String())
}

// Clone : will mark the event as errored
func (ev *Event) Clone() (event.Event, error) {
	body, _ := json.Marshal(ev)
	return New(ev.Subject, ev.CryptoKey, body, ev.Validator)
}

// Error : will mark the event as errored
func (ev *Event) Error(err error) {
	ev.ErrorMessage = err.Error()
	ev.Body, err = json.Marshal(ev)
}

// Client : not implemented
func (ev *Event) Client() (*azurerm.ArmClient, error) {
	return nil, errors.New("Not implemented")
}
<|endoftext|>