<commit_before>// Copyright 2015 go-swagger maintainers
//
// 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 validate

import (
	"reflect"
	"regexp"
	"unicode/utf8"

	"github.com/go-swagger/go-swagger/errors"
	"github.com/go-swagger/go-swagger/strfmt"
	"github.com/go-swagger/go-swagger/swag"
)

// Enum validates if the data is a member of the enum
func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation {
	val := reflect.ValueOf(enum)
	if val.Kind() != reflect.Slice {
		return nil
	}

	var values []interface{}
	for i := 0; i < val.Len(); i++ {
		ele := val.Index(i)
		enumValue := ele.Interface()
		if data != nil && reflect.DeepEqual(data, enumValue) {
			return nil
		}
		values = append(values, enumValue)
	}
	return errors.EnumFail(path, in, data, values)
}

// MinItems validates that there are at least n items in a slice
func MinItems(path, in string, size, min int64) *errors.Validation {
	if size < min {
		return errors.TooFewItems(path, in, min)
	}
	return nil
}

// MaxItems validates that there are at most n items in a slice
func MaxItems(path, in string, size, max int64) *errors.Validation {
	if size > max {
		return errors.TooManyItems(path, in, max)
	}
	return nil
}

// UniqueItems validates that the provided slice has unique elements
func UniqueItems(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Slice {
		return nil
	}
	var unique []interface{}
	for i := 0; i < val.Len(); i++ {
		v := val.Index(i).Interface()
		for _, u := range unique {
			if reflect.DeepEqual(v, u) {
				return errors.DuplicateItems(path, in)
			}
		}
		unique = append(unique, v)
	}
	return nil
}

// MinLength validates a string for minimum length
func MinLength(path, in, data string, minLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen < minLength {
		return errors.TooShort(path, in, minLength)
	}
	return nil
}

// MaxLength validates a string for maximum length
func MaxLength(path, in, data string, maxLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen > maxLength {
		return errors.TooLong(path, in, maxLength)
	}
	return nil
}

// Required validates an interface for requiredness
func Required(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if reflect.DeepEqual(reflect.Zero(val.Type()), val) {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredString validates a string for requiredness
func RequiredString(path, in, data string) *errors.Validation {
	if data == "" {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredNumber validates a number for requiredness
func RequiredNumber(path, in string, data float64) *errors.Validation {
	if data == 0 {
		return errors.Required(path, in)
	}
	return nil
}

// Pattern validates a string against a regular expression
func Pattern(path, in, data, pattern string) *errors.Validation {
	re := regexp.MustCompile(pattern)
	if !re.MatchString(data) {
		return errors.FailedPattern(path, in, pattern)
	}
	return nil
}

// Maximum validates if a number is smaller than a given maximum
func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximum(path, in, max, exclusive)
	}
	return nil
}

// Minimum validates if a number is smaller than a given minimum
func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimum(path, in, min, exclusive)
	}
	return nil
}

// MultipleOf validates if the provided number is a multiple of the factor
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
	if !swag.IsFloat64AJSONInteger(data / factor) {
		return errors.NotMultipleOf(path, in, factor)
	}
	return nil
}

// FormatOf validates if a string matches a format in the format registry
func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation {
	if registry == nil {
		registry = strfmt.Default
	}
	if ok := registry.ContainsName(format); !ok {
		return errors.InvalidTypeName(format)
	}
	if ok := registry.Validates(format, data); !ok {
		return errors.InvalidType(path, in, format, data)
	}

	return nil
}
<commit_msg>fixes #363 add int validation for min/max<commit_after>// Copyright 2015 go-swagger maintainers
//
// 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 validate

import (
	"reflect"
	"regexp"
	"unicode/utf8"

	"github.com/go-swagger/go-swagger/errors"
	"github.com/go-swagger/go-swagger/strfmt"
	"github.com/go-swagger/go-swagger/swag"
)

// Enum validates if the data is a member of the enum
func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation {
	val := reflect.ValueOf(enum)
	if val.Kind() != reflect.Slice {
		return nil
	}

	var values []interface{}
	for i := 0; i < val.Len(); i++ {
		ele := val.Index(i)
		enumValue := ele.Interface()
		if data != nil && reflect.DeepEqual(data, enumValue) {
			return nil
		}
		values = append(values, enumValue)
	}
	return errors.EnumFail(path, in, data, values)
}

// MinItems validates that there are at least n items in a slice
func MinItems(path, in string, size, min int64) *errors.Validation {
	if size < min {
		return errors.TooFewItems(path, in, min)
	}
	return nil
}

// MaxItems validates that there are at most n items in a slice
func MaxItems(path, in string, size, max int64) *errors.Validation {
	if size > max {
		return errors.TooManyItems(path, in, max)
	}
	return nil
}

// UniqueItems validates that the provided slice has unique elements
func UniqueItems(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Slice {
		return nil
	}
	var unique []interface{}
	for i := 0; i < val.Len(); i++ {
		v := val.Index(i).Interface()
		for _, u := range unique {
			if reflect.DeepEqual(v, u) {
				return errors.DuplicateItems(path, in)
			}
		}
		unique = append(unique, v)
	}
	return nil
}

// MinLength validates a string for minimum length
func MinLength(path, in, data string, minLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen < minLength {
		return errors.TooShort(path, in, minLength)
	}
	return nil
}

// MaxLength validates a string for maximum length
func MaxLength(path, in, data string, maxLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen > maxLength {
		return errors.TooLong(path, in, maxLength)
	}
	return nil
}

// Required validates an interface for requiredness
func Required(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if reflect.DeepEqual(reflect.Zero(val.Type()), val) {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredString validates a string for requiredness
func RequiredString(path, in, data string) *errors.Validation {
	if data == "" {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredNumber validates a number for requiredness
func RequiredNumber(path, in string, data float64) *errors.Validation {
	if data == 0 {
		return errors.Required(path, in)
	}
	return nil
}

// Pattern validates a string against a regular expression
func Pattern(path, in, data, pattern string) *errors.Validation {
	re := regexp.MustCompile(pattern)
	if !re.MatchString(data) {
		return errors.FailedPattern(path, in, pattern)
	}
	return nil
}

// MaximumIn validates if a number is smaller than a given maximum
func MaximumInt(path, in string, data, max int64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximumInt(path, in, max, exclusive)
	}
	return nil
}

// MaximumUint validates if a number is smaller than a given maximum
func MaximumUin(path, in string, data, max uint64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximumUint(path, in, max, exclusive)
	}
	return nil
}

// Maximum validates if a number is smaller than a given maximum
func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximum(path, in, max, exclusive)
	}
	return nil
}

// Minimum validates if a number is smaller than a given minimum
func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimum(path, in, min, exclusive)
	}
	return nil
}

// MinimumInt validates if a number is smaller than a given minimum
func MinimumInt(path, in string, data, min int64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimumInt(path, in, min, exclusive)
	}
	return nil
}

// MinimumUint validates if a number is smaller than a given minimum
func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimumUint(path, in, min, exclusive)
	}
	return nil
}

// MultipleOf validates if the provided number is a multiple of the factor
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
	if !swag.IsFloat64AJSONInteger(data / factor) {
		return errors.NotMultipleOf(path, in, factor)
	}
	return nil
}

// FormatOf validates if a string matches a format in the format registry
func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation {
	if registry == nil {
		registry = strfmt.Default
	}
	if ok := registry.ContainsName(format); !ok {
		return errors.InvalidTypeName(format)
	}
	if ok := registry.Validates(format, data); !ok {
		return errors.InvalidType(path, in, format, data)
	}

	return nil
}
<|endoftext|>


<commit_before>package revel

import (
	"fmt"
	"reflect"
	"regexp"
	"strings"
	"testing"
	"time"
)

const (
	errorsMessage   = "validation for %s should not be satisfied with %s\n"
	noErrorsMessage = "validation for %s should be satisfied with %s\n"
)

type Expect struct {
	input          interface{}
	expectedResult bool
	errorMessage   string
}

func performTests(validator Validator, tests []Expect, t *testing.T) {
	for _, test := range tests {
		if validator.IsSatisfied(test.input) != test.expectedResult {
			if test.expectedResult == false {
				t.Errorf(errorsMessage, reflect.TypeOf(validator), test.errorMessage)
			} else {
				t.Errorf(noErrorsMessage, reflect.TypeOf(validator), test.errorMessage)
			}
		}
	}
}

func TestRequired(t *testing.T) {

	tests := []Expect{
		Expect{nil, false, "nil data"},
		Expect{"Testing", true, "non-empty string"},
		Expect{"", false, "empty string"},
		Expect{true, true, "true boolean"},
		Expect{false, false, "false boolean"},
		Expect{1, true, "positive integer"},
		Expect{-1, true, "negative integer"},
		Expect{0, false, "0 integer"},
		Expect{time.Now(), true, "current time"},
		Expect{time.Time{}, false, "a zero time"},
		Expect{func() {}, true, "other non-nil data types"},
	}

	// testing both the struct and the helper method
	for _, required := range []Required{Required{}, ValidRequired()} {
		performTests(required, tests, t)
	}
}

func TestMin(t *testing.T) {
	tests := []Expect{
		Expect{11, true, "val > min"},
		Expect{10, true, "val == min"},
		Expect{9, false, "val < min"},
		Expect{true, false, "TypeOf(val) != int"},
	}
	for _, min := range []Min{Min{10}, ValidMin(10)} {
		performTests(min, tests, t)
	}
}

func TestMax(t *testing.T) {
	tests := []Expect{
		Expect{9, true, "val < max"},
		Expect{10, true, "val == max"},
		Expect{11, false, "val > max"},
		Expect{true, false, "TypeOf(val) != int"},
	}
	for _, max := range []Max{Max{10}, ValidMax(10)} {
		performTests(max, tests, t)
	}
}

func TestRange(t *testing.T) {
	tests := []Expect{
		Expect{50, true, "min <= val <= max"},
		Expect{10, true, "val == min"},
		Expect{100, true, "val == max"},
		Expect{9, false, "val < min"},
		Expect{101, false, "val > max"},
	}

	goodValidators := []Range{
		Range{Min{10}, Max{100}},
		ValidRange(10, 100),
	}
	for _, rangeValidator := range goodValidators {
		performTests(rangeValidator, tests, t)
	}

	tests = []Expect{
		Expect{10, true, "min == val == max"},
		Expect{9, false, "val < min && val < max && min == max"},
		Expect{11, false, "val > min && val > max && min == max"},
	}

	goodValidators = []Range{
		Range{Min{10}, Max{10}},
		ValidRange(10, 10),
	}
	for _, rangeValidator := range goodValidators {
		performTests(rangeValidator, tests, t)
	}

	tests = make([]Expect, 7)
	for i, num := range []int{50, 100, 10, 9, 101, 0, -1} {
		tests[i] = Expect{
			num,
			false,
			"min > val < max",
		}
	}
	// these are min/max with values swapped, so the min is the high
	// and max is the low. rangeValidator.IsSatisfied() should ALWAYS
	// result in false since val can never be greater than min and less
	// than max when min > max
	badValidators := []Range{
		Range{Min{100}, Max{10}},
		ValidRange(100, 10),
	}
	for _, rangeValidator := range badValidators {
		performTests(rangeValidator, tests, t)
	}
}

func TestMinSize(t *testing.T) {
	greaterThanMessage := "len(val) >= min"
	tests := []Expect{
		Expect{"1", true, greaterThanMessage},
		Expect{"12", true, greaterThanMessage},
		Expect{[]int{1}, true, greaterThanMessage},
		Expect{[]int{1, 2}, true, greaterThanMessage},
		Expect{"", false, "len(val) <= min"},
		Expect{[]int{}, false, "len(val) <= min"},
		Expect{nil, false, "TypeOf(val) != string && TypeOf(val) != slice"},
	}

	for _, minSize := range []MinSize{MinSize{1}, ValidMinSize(1)} {
		performTests(minSize, tests, t)
	}
}

func TestMaxSize(t *testing.T) {
	lessThanMessage := "len(val) <= max"
	tests := []Expect{
		Expect{"", true, lessThanMessage},
		Expect{"12", true, lessThanMessage},
		Expect{[]int{}, true, lessThanMessage},
		Expect{[]int{1, 2}, true, lessThanMessage},
		Expect{"123", false, "len(val) >= max"},
		Expect{[]int{1, 2, 3}, "len(val) >= max"},
	}
	for _, maxSize := range []MaxSize{MaxSize{2}, ValidMaxSize(2)} {
		performTests(maxSize, tests, t)
	}
}

func TestLength(t *testing.T) {
	tests := []Expect{
		Expect{"12", true, "len(val) == length"},
		Expect{[]int{1, 2}, true, "len(val) == length"},
		Expect{"123", false, "len(val) > length"},
		Expect{[]int{1, 2, 3}, false, "len(val) > length"},
		Expect{"1", false, "len(val) < length"},
		Expect{[]int{1}, false, "len(val) < length"},
		Expect{nil, false, "TypeOf(val) != string && TypeOf(val) != slice"},
	}
	for _, length := range []Length{Length{2}, ValidLength(2)} {
		performTests(length, tests, t)
	}
}

func TestMatch(t *testing.T) {
	tests := []Expect{
		Expect{"bca123", true, `"[abc]{3}\d*" matches "bca123"`},
		Expect{"bc123", false, `"[abc]{3}\d*" does not match "bc123"`},
		Expect{"", false, `"[abc]{3}\d*" does not match ""`},
	}
	regex := regexp.MustCompile(`[abc]{3}\d*`)
	for _, match := range []Match{Match{regex}, ValidMatch(regex)} {
		performTests(match, tests, t)
	}
}

func TestEmail(t *testing.T) {
	// unicode char included
	validStartingCharacters := strings.Split("!#$%^&*_+1234567890abcdefghijklmnopqrstuvwxyzñ", "")
	invalidCharacters := strings.Split(" ()", "")
	definiteInvalidDomains := []string{
		"",                  // any empty string (x@)
		".com",              // only the TLD (x@.com)
		".",                 // only the . (x@.)
		".*",                // TLD containing symbol (x@.*)
		"asdf",              // no TLD
		"a!@#$%^&*()+_.com", // characters which are not ASCII/0-9/dash(-) in a domain
		"-a.com",            // host starting with any symbol
		"a-.com",            // host ending with any symbol
		"aå.com",            // domain containing unicode (however, unicode domains do exist in the state of xn--<POINT>.com e.g. å.com = xn--5ca.com)
	}

	for _, email := range []Email{Email{Match{emailPattern}}, ValidEmail()} {
		var currentEmail string

		// test invalid starting chars
		for _, startingChar := range validStartingCharacters {
			currentEmail = fmt.Sprintf("%sñbc+123@do-main.com", startingChar)
			if email.IsSatisfied(currentEmail) {
				t.Errorf(noErrorsMessage, fmt.Sprintf("email = %s", currentEmail))
			}

			// validation should fail because of multiple @ symbols
			currentEmail = fmt.Sprintf("%s@ñbc+123@do-main.com", startingChar)
			if email.IsSatisfied(currentEmail) {
				t.Errorf(errorsMessage, fmt.Sprintf("email = %s", currentEmail))
			}

			// should fail simply because of the invalid char
			for _, invalidChar := range invalidCharacters {
				currentEmail = fmt.Sprintf("%sñbc%s+123@do-main.com", startingChar, invalidChar)
				if email.IsSatisfied(currentEmail) {
					t.Errorf(errorsMessage, fmt.Sprintf("email = %s", currentEmail))
				}
			}
		}

		// test invalid domains
		for _, invalidDomain := range definiteInvalidDomains {
			currentEmail = fmt.Sprintf("a@%s", invalidDomain)
			if email.IsSatisfied(currentEmail) {
				t.Errorf(errorsMessage, fmt.Sprintf("email = %s", currentEmail))
			}
		}

		// should always be satisfied
		if !email.IsSatisfied("t0.est+email123@1abc0-def.com") {
			t.Errorf(noErrorsMessage, fmt.Sprintf("email = %s", "t0.est+email123@1abc0-def.com"))
		}

		// should never be satisfied (this is redundant given the loops above)
		if email.IsSatisfied("a@xcom") {
			t.Errorf(noErrorsMessage, fmt.Sprintf("email = %s", "a@xcom"))
		}
		if email.IsSatisfied("a@@x.com") {
			t.Errorf(noErrorsMessage, fmt.Sprintf("email = %s", "a@@x.com"))
		}
	}
}
<commit_msg>Fix missing field in Expect struct<commit_after>package revel

import (
	"fmt"
	"reflect"
	"regexp"
	"strings"
	"testing"
	"time"
)

const (
	errorsMessage   = "validation for %s should not be satisfied with %s\n"
	noErrorsMessage = "validation for %s should be satisfied with %s\n"
)

type Expect struct {
	input          interface{}
	expectedResult bool
	errorMessage   string
}

func performTests(validator Validator, tests []Expect, t *testing.T) {
	for _, test := range tests {
		if validator.IsSatisfied(test.input) != test.expectedResult {
			if test.expectedResult == false {
				t.Errorf(errorsMessage, reflect.TypeOf(validator), test.errorMessage)
			} else {
				t.Errorf(noErrorsMessage, reflect.TypeOf(validator), test.errorMessage)
			}
		}
	}
}

func TestRequired(t *testing.T) {

	tests := []Expect{
		Expect{nil, false, "nil data"},
		Expect{"Testing", true, "non-empty string"},
		Expect{"", false, "empty string"},
		Expect{true, true, "true boolean"},
		Expect{false, false, "false boolean"},
		Expect{1, true, "positive integer"},
		Expect{-1, true, "negative integer"},
		Expect{0, false, "0 integer"},
		Expect{time.Now(), true, "current time"},
		Expect{time.Time{}, false, "a zero time"},
		Expect{func() {}, true, "other non-nil data types"},
	}

	// testing both the struct and the helper method
	for _, required := range []Required{Required{}, ValidRequired()} {
		performTests(required, tests, t)
	}
}

func TestMin(t *testing.T) {
	tests := []Expect{
		Expect{11, true, "val > min"},
		Expect{10, true, "val == min"},
		Expect{9, false, "val < min"},
		Expect{true, false, "TypeOf(val) != int"},
	}
	for _, min := range []Min{Min{10}, ValidMin(10)} {
		performTests(min, tests, t)
	}
}

func TestMax(t *testing.T) {
	tests := []Expect{
		Expect{9, true, "val < max"},
		Expect{10, true, "val == max"},
		Expect{11, false, "val > max"},
		Expect{true, false, "TypeOf(val) != int"},
	}
	for _, max := range []Max{Max{10}, ValidMax(10)} {
		performTests(max, tests, t)
	}
}

func TestRange(t *testing.T) {
	tests := []Expect{
		Expect{50, true, "min <= val <= max"},
		Expect{10, true, "val == min"},
		Expect{100, true, "val == max"},
		Expect{9, false, "val < min"},
		Expect{101, false, "val > max"},
	}

	goodValidators := []Range{
		Range{Min{10}, Max{100}},
		ValidRange(10, 100),
	}
	for _, rangeValidator := range goodValidators {
		performTests(rangeValidator, tests, t)
	}

	tests = []Expect{
		Expect{10, true, "min == val == max"},
		Expect{9, false, "val < min && val < max && min == max"},
		Expect{11, false, "val > min && val > max && min == max"},
	}

	goodValidators = []Range{
		Range{Min{10}, Max{10}},
		ValidRange(10, 10),
	}
	for _, rangeValidator := range goodValidators {
		performTests(rangeValidator, tests, t)
	}

	tests = make([]Expect, 7)
	for i, num := range []int{50, 100, 10, 9, 101, 0, -1} {
		tests[i] = Expect{
			num,
			false,
			"min > val < max",
		}
	}
	// these are min/max with values swapped, so the min is the high
	// and max is the low. rangeValidator.IsSatisfied() should ALWAYS
	// result in false since val can never be greater than min and less
	// than max when min > max
	badValidators := []Range{
		Range{Min{100}, Max{10}},
		ValidRange(100, 10),
	}
	for _, rangeValidator := range badValidators {
		performTests(rangeValidator, tests, t)
	}
}

func TestMinSize(t *testing.T) {
	greaterThanMessage := "len(val) >= min"
	tests := []Expect{
		Expect{"1", true, greaterThanMessage},
		Expect{"12", true, greaterThanMessage},
		Expect{[]int{1}, true, greaterThanMessage},
		Expect{[]int{1, 2}, true, greaterThanMessage},
		Expect{"", false, "len(val) <= min"},
		Expect{[]int{}, false, "len(val) <= min"},
		Expect{nil, false, "TypeOf(val) != string && TypeOf(val) != slice"},
	}

	for _, minSize := range []MinSize{MinSize{1}, ValidMinSize(1)} {
		performTests(minSize, tests, t)
	}
}

func TestMaxSize(t *testing.T) {
	lessThanMessage := "len(val) <= max"
	tests := []Expect{
		Expect{"", true, lessThanMessage},
		Expect{"12", true, lessThanMessage},
		Expect{[]int{}, true, lessThanMessage},
		Expect{[]int{1, 2}, true, lessThanMessage},
		Expect{"123", false, "len(val) >= max"},
		Expect{[]int{1, 2, 3}, false, "len(val) >= max"},
	}
	for _, maxSize := range []MaxSize{MaxSize{2}, ValidMaxSize(2)} {
		performTests(maxSize, tests, t)
	}
}

func TestLength(t *testing.T) {
	tests := []Expect{
		Expect{"12", true, "len(val) == length"},
		Expect{[]int{1, 2}, true, "len(val) == length"},
		Expect{"123", false, "len(val) > length"},
		Expect{[]int{1, 2, 3}, false, "len(val) > length"},
		Expect{"1", false, "len(val) < length"},
		Expect{[]int{1}, false, "len(val) < length"},
		Expect{nil, false, "TypeOf(val) != string && TypeOf(val) != slice"},
	}
	for _, length := range []Length{Length{2}, ValidLength(2)} {
		performTests(length, tests, t)
	}
}

func TestMatch(t *testing.T) {
	tests := []Expect{
		Expect{"bca123", true, `"[abc]{3}\d*" matches "bca123"`},
		Expect{"bc123", false, `"[abc]{3}\d*" does not match "bc123"`},
		Expect{"", false, `"[abc]{3}\d*" does not match ""`},
	}
	regex := regexp.MustCompile(`[abc]{3}\d*`)
	for _, match := range []Match{Match{regex}, ValidMatch(regex)} {
		performTests(match, tests, t)
	}
}

func TestEmail(t *testing.T) {
	// unicode char included
	validStartingCharacters := strings.Split("!#$%^&*_+1234567890abcdefghijklmnopqrstuvwxyzñ", "")
	invalidCharacters := strings.Split(" ()", "")
	definiteInvalidDomains := []string{
		"",                  // any empty string (x@)
		".com",              // only the TLD (x@.com)
		".",                 // only the . (x@.)
		".*",                // TLD containing symbol (x@.*)
		"asdf",              // no TLD
		"a!@#$%^&*()+_.com", // characters which are not ASCII/0-9/dash(-) in a domain
		"-a.com",            // host starting with any symbol
		"a-.com",            // host ending with any symbol
		"aå.com",            // domain containing unicode (however, unicode domains do exist in the state of xn--<POINT>.com e.g. å.com = xn--5ca.com)
	}

	for _, email := range []Email{Email{Match{emailPattern}}, ValidEmail()} {
		var currentEmail string

		// test invalid starting chars
		for _, startingChar := range validStartingCharacters {
			currentEmail = fmt.Sprintf("%sñbc+123@do-main.com", startingChar)
			if email.IsSatisfied(currentEmail) {
				t.Errorf(noErrorsMessage, fmt.Sprintf("email = %s", currentEmail))
			}

			// validation should fail because of multiple @ symbols
			currentEmail = fmt.Sprintf("%s@ñbc+123@do-main.com", startingChar)
			if email.IsSatisfied(currentEmail) {
				t.Errorf(errorsMessage, fmt.Sprintf("email = %s", currentEmail))
			}

			// should fail simply because of the invalid char
			for _, invalidChar := range invalidCharacters {
				currentEmail = fmt.Sprintf("%sñbc%s+123@do-main.com", startingChar, invalidChar)
				if email.IsSatisfied(currentEmail) {
					t.Errorf(errorsMessage, fmt.Sprintf("email = %s", currentEmail))
				}
			}
		}

		// test invalid domains
		for _, invalidDomain := range definiteInvalidDomains {
			currentEmail = fmt.Sprintf("a@%s", invalidDomain)
			if email.IsSatisfied(currentEmail) {
				t.Errorf(errorsMessage, fmt.Sprintf("email = %s", currentEmail))
			}
		}

		// should always be satisfied
		if !email.IsSatisfied("t0.est+email123@1abc0-def.com") {
			t.Errorf(noErrorsMessage, fmt.Sprintf("email = %s", "t0.est+email123@1abc0-def.com"))
		}

		// should never be satisfied (this is redundant given the loops above)
		if email.IsSatisfied("a@xcom") {
			t.Errorf(noErrorsMessage, fmt.Sprintf("email = %s", "a@xcom"))
		}
		if email.IsSatisfied("a@@x.com") {
			t.Errorf(noErrorsMessage, fmt.Sprintf("email = %s", "a@@x.com"))
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/go-telegram-bot-api/telegram-bot-api"
)

func main() {
	token := os.Getenv("YBOTTOKEN")
	bot, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		log.Panic(err)
	}

	bot.Debug = true

	log.Printf("Authorized on account %s", bot.Self.UserName)

	u := tgbotapi.NewUpdate(0)
	u.Timeout = 60

	updates, err := bot.GetUpdatesChan(u)

	if err != nil {
		log.Panic(err)
	}
	log.Printf("Starting read")
	for update := range updates {
		if update.Message == nil {
			continue
		}

		log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)

		msg := tgbotapi.NewMessage(update.Message.Chat.ID,
			"Send me asciidoc file (.adoc). I don't understand: "+update.Message.Text)
		msg.ReplyToMessageID = update.Message.MessageID

		if update.Message.Document == nil {
			bot.Send(msg)
			continue
		}

		f, err := bot.GetFile(tgbotapi.FileConfig{FileID: update.Message.Document.FileID})
		if err != nil {
			log.Fatal(err)
			msg.Text = "Failed to proceed uploaded file"
			bot.Send(msg)
			continue
		}

		response, err := http.Get(f.Link(token))
		if err != nil {

			log.Fatal(err)
			msg.Text = "Failed to get uploaded file"
			bot.Send(msg)
			continue

		} else {

			defer response.Body.Close()

			lfolder := path.Join("/tmp", path.Dir(f.FilePath))
			lfile := path.Join("/tmp", f.FilePath)
			ext := path.Ext(lfile)
			pdffile := strings.TrimSuffix(lfile, ext) + ".pdf"

			if ext != ".adoc" {
				msg.Text = "Document is not an adoc"
				bot.Send(msg)
				continue
			}

			os.MkdirAll(lfolder, os.ModePerm)

			file, err := os.Create(lfile)
			if err != nil {
				log.Fatal(err)
				msg.Text = "Unable to create new file"
				bot.Send(msg)
				continue
			}
			// Use io.Copy to just dump the response body to the file. This supports huge files
			_, err = io.Copy(file, response.Body)
			if err != nil {
				log.Fatal(err)
				msg.Text = "Unable to buffer uploaded file"
				bot.Send(msg)
				continue
			}
			file.Close()

			msg := tgbotapi.NewMessage(update.Message.Chat.ID, "")
			msg.ReplyToMessageID = update.Message.MessageID

			go func() {
				cmd := exec.Command("Ad", lfile)
				cmd.Dir = lfolder
				out, err := cmd.Output()
				if err != nil {
					log.Fatal(err)
					msg.Text = fmt.Sprintf("Fail %v", err)
				} else {
					msg.Text = fmt.Sprintf("Success %v", out)
				}
				bot.Send(msg)
				bot.Send(tgbotapi.NewDocumentUpload(msg.ChatID, pdffile))

			}()
		}

	}

}
<commit_msg>webhook ready but not proper yet<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/go-telegram-bot-api/telegram-bot-api"
)

var webhook = flag.Bool("webhook", false, "webhook mode")
var debug = flag.Bool("debug", false, "debug")
var token = flag.String("token", "", "token")
var pubip = flag.String("pubip", "", "public ip, get with 'curl -s https://ipinfo.io/ip'")
var port = flag.Int("port", 8443, "webhook server port")
var cert = flag.String("cert", "cert.pem", "cert for webhook https server")
var key = flag.String("key", "key.pem", "priv key for webhook https server")

func handleUpdate(bot *tgbotapi.BotAPI, update tgbotapi.Update) {

	if update.Message == nil {
		return
	}

	log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)

	msg := tgbotapi.NewMessage(update.Message.Chat.ID,
		"Send me asciidoc file (.adoc). I don't understand: "+update.Message.Text)
	msg.ReplyToMessageID = update.Message.MessageID

	if update.Message.Document == nil {
		bot.Send(msg)
		return
	}

	f, err := bot.GetFile(tgbotapi.FileConfig{FileID: update.Message.Document.FileID})
	//log.Printf("DocFile: %s", update.Message.Document.FileName)
	if err != nil {
		log.Fatal(err)
		msg.Text = "Failed to proceed uploaded file"
		bot.Send(msg)
		return
	}

	lfolder := path.Join("/tmp", path.Dir(f.FilePath))
	//lfile := path.Join("/tmp", f.FilePath)
	ext := path.Ext(update.Message.Document.FileName)
	pdffile := path.Join(lfolder, strings.TrimSuffix(update.Message.Document.FileName, ext)+".pdf")
	adocfile := path.Join(lfolder, update.Message.Document.FileName)

	if ext != ".adoc" {
		msg.Text = "Document is not an adoc"
		bot.Send(msg)
		return
	}

	msg.Text = "Looks good, let me work on this file"
	bot.Send(msg)

	response, err := http.Get(f.Link(*token))
	if err != nil {

		log.Fatal(err)
		msg.Text = "Failed to get uploaded file"
		bot.Send(msg)
		return

	}
	defer response.Body.Close()

	os.MkdirAll(lfolder, os.ModePerm)

	file, err := os.Create(adocfile)
	if err != nil {
		log.Fatal(err)
		msg.Text = "Unable to create new file"
		bot.Send(msg)
		return
	}
	// Use io.Copy to just dump the response body to the file. This supports huge files
	_, err = io.Copy(file, response.Body)
	file.Close()
	if err != nil {
		log.Fatal(err)
		msg.Text = "Unable to buffer uploaded file"
		bot.Send(msg)
		return
	}

	go func() {
		cmd := exec.Command("Ad", adocfile)
		cmd.Dir = lfolder
		out, err := cmd.Output()
		if err != nil {
			log.Fatal(err)
			msg.Text = fmt.Sprintf("Fail %v\n%v", out, err)
		} else if len(out) > 0 {
			msg.Text = fmt.Sprintf("Success %v", out)
		} else {
			msg.Text = fmt.Sprintf("Success")
		}
		bot.Send(msg)
		bot.Send(tgbotapi.NewDocumentUpload(msg.ChatID, pdffile))

	}()

}

func main() {

	flag.Parse()

	if *token == "" {
		*token = os.Getenv("YBOTTOKEN")
	}
	bot, err := tgbotapi.NewBotAPI(*token)
	if err != nil {
		log.Panic(err)
	}

	bot.Debug = *debug

	log.Printf("Authorized on account %s", bot.Self.UserName)

	if *webhook {

		url := fmt.Sprintf("https://%s:%d/%s", *pubip, *port, bot.Token)
		//log.Print(url)
		_, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert(url, *cert))
		if err != nil {
			log.Fatal(err)
		}

		updates := bot.ListenForWebhook("/" + bot.Token)
		go http.ListenAndServeTLS(fmt.Sprintf("0.0.0.0:%d", *port), *cert, *key, nil)

		log.Printf("Starting Collect Update from WebHook")
		for update := range updates {
			handleUpdate(bot, update)
		}

	} else {

		u := tgbotapi.NewUpdate(0)
		u.Timeout = 60

		updates, err := bot.GetUpdatesChan(u)

		if err != nil {
			log.Panic(err)
		}

		log.Printf("Starting GetUpdate")
		for update := range updates {
			handleUpdate(bot, update)
		}
	}

}
<|endoftext|>


<commit_before>package siprocket

/*
 RFC 3261 - https://www.ietf.org/rfc/rfc3261.txt

INVITE sip:01798300765@87.252.61.202;user=phone SIP/2.0
SIP/2.0 200 OK

*/

type sipReq struct {
	Method     []byte // Sip Method eg INVITE etc
	UriType    string // Type of URI sip, sips, tel etc
	StatusCode []byte // Status Code eg 100
	StatusDesc []byte // Status Code Description eg trying
	User       []byte // User part
	Host       []byte // Host part
	Port       []byte // Port number
	UserType   []byte // User Type
	Src        []byte // Full source if needed
}

func parseSipReq(v []byte, out *sipReq) {

	pos := 0
	state := 0

	// Init the output area
	out.UriType = ""
	out.Method = nil
	out.StatusCode = nil
	out.User = nil
	out.Host = nil
	out.Port = nil
	out.UserType = nil
	out.Src = nil

	// Keep the source line if needed
	if keep_src {
		out.Src = v
	}

	// Loop through the bytes making up the line
	for pos < len(v) {
		// FSM
		switch state {
		case FIELD_NULL:
			if v[pos] >= 'A' && v[pos] <= 'S' && pos == 0 {
				state = FIELD_METHOD
				continue
			}

		case FIELD_METHOD:
			if v[pos] == ' ' || pos > 9 {
				if string(out.Method) == "SIP/2.0" {
					state = FIELD_STATUS
				} else {
					state = FIELD_BASE
				}
				pos++
				continue
			}
			out.Method = append(out.Method, v[pos])

		case FIELD_BASE:
			if v[pos] != ' ' {
				// Not a space so check for uri types
				if getString(v, pos, pos+4) == "sip:" {
					state = FIELD_USER
					pos = pos + 4
					out.UriType = "sip"
					continue
				}
				if getString(v, pos, pos+5) == "sips:" {
					state = FIELD_USER
					pos = pos + 5
					out.UriType = "sips"
					continue
				}
				if getString(v, pos, pos+4) == "tel:" {
					state = FIELD_USER
					pos = pos + 4
					out.UriType = "tel"
					continue
				}
				if getString(v, pos, pos+5) == "user=" {
					state = FIELD_USERTYPE
					pos = pos + 5
					continue
				}
				if v[pos] == '@' {
					state = FIELD_HOST
					out.User = out.Host // Move host to user
					out.Host = nil      // Clear the host
					pos++
					continue
				}
			}
		case FIELD_USER:
			if v[pos] == ':' {
				state = FIELD_PORT
				pos++
				continue
			}
			if v[pos] == ';' || v[pos] == '>' {
				state = FIELD_BASE
				pos++
				continue
			}
			if v[pos] == '@' {
				state = FIELD_HOST
				out.User = out.Host // Move host to user
				out.Host = nil      // Clear the host
				pos++
				continue
			}
			out.Host = append(out.Host, v[pos]) // Append to host for now

		case FIELD_HOST:
			if v[pos] == ':' {
				state = FIELD_PORT
				pos++
				continue
			}
			if v[pos] == ';' || v[pos] == '>' {
				state = FIELD_BASE
				pos++
				continue
			}
			out.Host = append(out.Host, v[pos])

		case FIELD_PORT:
			if v[pos] == ';' || v[pos] == '>' || v[pos] == ' ' {
				state = FIELD_BASE
				pos++
				continue
			}
			out.Port = append(out.Port, v[pos])

		case FIELD_USERTYPE:
			if v[pos] == ';' || v[pos] == '>' || v[pos] == ' ' {
				state = FIELD_BASE
				pos++
				continue
			}
			out.UserType = append(out.UserType, v[pos])

		case FIELD_STATUS:
			if v[pos] == ';' || v[pos] == '>' {
				state = FIELD_BASE
				pos++
				continue
			}
			if v[pos] == ' '{
				state = FIELD_STATUSDESC
				pos++
				continue
			}
			out.StatusCode = append(out.StatusCode, v[pos])

		case FIELD_STATUSDESC:
			if v[pos] == ';' || v[pos] == '>' {
				state = FIELD_BASE
				pos++
				continue
			}
			out.StatusDesc = append(out.StatusDesc, v[pos])

		}
		pos++
	}
}
<commit_msg>Don't use "SIP/2.0" in request method [negbie]<commit_after>package siprocket

/*
 RFC 3261 - https://www.ietf.org/rfc/rfc3261.txt

INVITE sip:01798300765@87.252.61.202;user=phone SIP/2.0
SIP/2.0 200 OK

*/

type sipReq struct {
	Method     []byte // Sip Method eg INVITE etc
	UriType    string // Type of URI sip, sips, tel etc
	StatusCode []byte // Status Code eg 100
	StatusDesc []byte // Status Code Description eg trying
	User       []byte // User part
	Host       []byte // Host part
	Port       []byte // Port number
	UserType   []byte // User Type
	Src        []byte // Full source if needed
}

func parseSipReq(v []byte, out *sipReq) {

	pos := 0
	state := 0

	// Init the output area
	out.UriType = ""
	out.Method = nil
	out.StatusCode = nil
	out.User = nil
	out.Host = nil
	out.Port = nil
	out.UserType = nil
	out.Src = nil

	// Keep the source line if needed
	if keep_src {
		out.Src = v
	}

	// Loop through the bytes making up the line
	for pos < len(v) {
		// FSM
		switch state {
		case FIELD_NULL:
			if v[pos] >= 'A' && v[pos] <= 'S' && pos == 0 {
				state = FIELD_METHOD
				continue
			}

		case FIELD_METHOD:
			if v[pos] == ' ' || pos > 9 {
				if string(out.Method) == "SIP/2.0" {
					state = FIELD_STATUS
					out.Method = []byte{}
				} else {
					state = FIELD_BASE
				}
				pos++
				continue
			}
			out.Method = append(out.Method, v[pos])

		case FIELD_BASE:
			if v[pos] != ' ' {
				// Not a space so check for uri types
				if getString(v, pos, pos+4) == "sip:" {
					state = FIELD_USER
					pos = pos + 4
					out.UriType = "sip"
					continue
				}
				if getString(v, pos, pos+5) == "sips:" {
					state = FIELD_USER
					pos = pos + 5
					out.UriType = "sips"
					continue
				}
				if getString(v, pos, pos+4) == "tel:" {
					state = FIELD_USER
					pos = pos + 4
					out.UriType = "tel"
					continue
				}
				if getString(v, pos, pos+5) == "user=" {
					state = FIELD_USERTYPE
					pos = pos + 5
					continue
				}
				if v[pos] == '@' {
					state = FIELD_HOST
					out.User = out.Host // Move host to user
					out.Host = nil      // Clear the host
					pos++
					continue
				}
			}
		case FIELD_USER:
			if v[pos] == ':' {
				state = FIELD_PORT
				pos++
				continue
			}
			if v[pos] == ';' || v[pos] == '>' {
				state = FIELD_BASE
				pos++
				continue
			}
			if v[pos] == '@' {
				state = FIELD_HOST
				out.User = out.Host // Move host to user
				out.Host = nil      // Clear the host
				pos++
				continue
			}
			out.Host = append(out.Host, v[pos]) // Append to host for now

		case FIELD_HOST:
			if v[pos] == ':' {
				state = FIELD_PORT
				pos++
				continue
			}
			if v[pos] == ';' || v[pos] == '>' {
				state = FIELD_BASE
				pos++
				continue
			}
			out.Host = append(out.Host, v[pos])

		case FIELD_PORT:
			if v[pos] == ';' || v[pos] == '>' || v[pos] == ' ' {
				state = FIELD_BASE
				pos++
				continue
			}
			out.Port = append(out.Port, v[pos])

		case FIELD_USERTYPE:
			if v[pos] == ';' || v[pos] == '>' || v[pos] == ' ' {
				state = FIELD_BASE
				pos++
				continue
			}
			out.UserType = append(out.UserType, v[pos])

		case FIELD_STATUS:
			if v[pos] == ';' || v[pos] == '>' {
				state = FIELD_BASE
				pos++
				continue
			}
			if v[pos] == ' ' {
				state = FIELD_STATUSDESC
				pos++
				continue
			}
			out.StatusCode = append(out.StatusCode, v[pos])

		case FIELD_STATUSDESC:
			if v[pos] == ';' || v[pos] == '>' {
				state = FIELD_BASE
				pos++
				continue
			}
			out.StatusDesc = append(out.StatusDesc, v[pos])

		}
		pos++
	}
}
<|endoftext|>


<commit_before>package metadata

import (
	"context"
	"strings"
	"time"

	"github.com/boltdb/bolt"
	"github.com/containerd/containerd/containers"
	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/filters"
	"github.com/containerd/containerd/identifiers"
	"github.com/containerd/containerd/metadata/boltutil"
	"github.com/containerd/containerd/namespaces"
	"github.com/gogo/protobuf/proto"
	"github.com/gogo/protobuf/types"
	"github.com/pkg/errors"
)

type containerStore struct {
	tx *bolt.Tx
}

func NewContainerStore(tx *bolt.Tx) containers.Store {
	return &containerStore{
		tx: tx,
	}
}

func (s *containerStore) Get(ctx context.Context, id string) (containers.Container, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return containers.Container{}, err
	}

	bkt := getContainerBucket(s.tx, namespace, id)
	if bkt == nil {
		return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "bucket name %q:%q", namespace, id)
	}

	container := containers.Container{ID: id}
	if err := readContainer(&container, bkt); err != nil {
		return containers.Container{}, errors.Wrapf(err, "failed to read container %v", id)
	}

	return container, nil
}

func (s *containerStore) List(ctx context.Context, fs ...string) ([]containers.Container, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return nil, err
	}

	filter, err := filters.ParseAll(fs...)
	if err != nil {
		return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error())
	}

	bkt := getContainersBucket(s.tx, namespace)
	if bkt == nil {
		return nil, nil
	}

	var m []containers.Container
	if err := bkt.ForEach(func(k, v []byte) error {
		cbkt := bkt.Bucket(k)
		if cbkt == nil {
			return nil
		}
		container := containers.Container{ID: string(k)}

		if err := readContainer(&container, cbkt); err != nil {
			return errors.Wrap(err, "failed to read container")
		}

		if filter.Match(adaptContainer(container)) {
			m = append(m, container)
		}
		return nil
	}); err != nil {
		return nil, err
	}

	return m, nil
}

func (s *containerStore) Create(ctx context.Context, container containers.Container) (containers.Container, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return containers.Container{}, err
	}

	if err := identifiers.Validate(container.ID); err != nil {
		return containers.Container{}, err
	}

	bkt, err := createContainersBucket(s.tx, namespace)
	if err != nil {
		return containers.Container{}, err
	}

	cbkt, err := bkt.CreateBucket([]byte(container.ID))
	if err != nil {
		if err == bolt.ErrBucketExists {
			err = errors.Wrapf(errdefs.ErrAlreadyExists, "content %q", container.ID)
		}
		return containers.Container{}, err
	}

	container.CreatedAt = time.Now().UTC()
	container.UpdatedAt = container.CreatedAt
	if err := writeContainer(cbkt, &container); err != nil {
		return containers.Container{}, errors.Wrap(err, "failed to write container")
	}

	return container, nil
}

func (s *containerStore) Update(ctx context.Context, container containers.Container, fieldpaths ...string) (containers.Container, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return containers.Container{}, err
	}

	if container.ID == "" {
		return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "must specify a container id")
	}

	bkt := getContainersBucket(s.tx, namespace)
	if bkt == nil {
		return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
	}

	cbkt := bkt.Bucket([]byte(container.ID))
	if cbkt == nil {
		return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
	}

	var updated containers.Container
	if err := readContainer(&updated, cbkt); err != nil {
		return updated, errors.Wrapf(err, "failed to read container from bucket")
	}
	createdat := updated.CreatedAt
	updated.ID = container.ID

	// apply the field mask. If you update this code, you better follow the
	// field mask rules in field_mask.proto. If you don't know what this
	// is, do not update this code.
	if len(fieldpaths) > 0 {
		// TODO(stevvooe): Move this logic into the store itself.
		for _, path := range fieldpaths {
			if strings.HasPrefix(path, "labels.") {
				if updated.Labels == nil {
					updated.Labels = map[string]string{}
				}
				key := strings.TrimPrefix(path, "labels.")
				updated.Labels[key] = container.Labels[key]
				continue
			}

			switch path {
			case "labels":
				updated.Labels = container.Labels
			case "image":
				updated.Image = container.Image
			case "runtime":
				// TODO(stevvooe): Should this actually be allowed?
				updated.Runtime = container.Runtime
			case "spec":
				updated.Spec = container.Spec
			case "rootfs":
				updated.RootFS = container.RootFS
			default:
				return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
			}
		}
	} else {
		// no field mask present, just replace everything
		updated = container
	}

	updated.CreatedAt = createdat
	updated.UpdatedAt = time.Now().UTC()
	if err := writeContainer(cbkt, &updated); err != nil {
		return containers.Container{}, errors.Wrap(err, "failed to write container")
	}

	return container, nil
}

func (s *containerStore) Delete(ctx context.Context, id string) error {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return err
	}

	bkt := getContainersBucket(s.tx, namespace)
	if bkt == nil {
		return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %v, bucket not present", id)
	}

	if err := bkt.DeleteBucket([]byte(id)); err == bolt.ErrBucketNotFound {
		return errors.Wrapf(errdefs.ErrNotFound, "container %v", id)
	}
	return err
}

func readContainer(container *containers.Container, bkt *bolt.Bucket) error {
	labels, err := boltutil.ReadLabels(bkt)
	if err != nil {
		return err
	}
	container.Labels = labels

	if err := boltutil.ReadTimestamps(bkt, &container.CreatedAt, &container.UpdatedAt); err != nil {
		return err
	}

	return bkt.ForEach(func(k, v []byte) error {
		switch string(k) {
		case string(bucketKeyImage):
			container.Image = string(v)
		case string(bucketKeyRuntime):
			rbkt := bkt.Bucket(bucketKeyRuntime)
			if rbkt == nil {
				return nil // skip runtime. should be an error?
			}

			n := rbkt.Get(bucketKeyName)
			if n != nil {
				container.Runtime.Name = string(n)
			}

			obkt := rbkt.Get(bucketKeyOptions)
			if obkt == nil {
				return nil
			}

			var any types.Any
			if err := proto.Unmarshal(obkt, &any); err != nil {
				return err
			}
			container.Runtime.Options = &any
		case string(bucketKeySpec):
			var any types.Any
			if err := proto.Unmarshal(v, &any); err != nil {
				return err
			}
			container.Spec = &any
		case string(bucketKeyRootFS):
			container.RootFS = string(v)

		}

		return nil
	})
}

func writeContainer(bkt *bolt.Bucket, container *containers.Container) error {
	if err := boltutil.WriteTimestamps(bkt, container.CreatedAt, container.UpdatedAt); err != nil {
		return err
	}

	spec, err := container.Spec.Marshal()
	if err != nil {
		return err
	}

	for _, v := range [][2][]byte{
		{bucketKeyImage, []byte(container.Image)},
		{bucketKeySpec, spec},
		{bucketKeyRootFS, []byte(container.RootFS)},
	} {
		if err := bkt.Put(v[0], v[1]); err != nil {
			return err
		}
	}

	if rbkt := bkt.Bucket(bucketKeyRuntime); rbkt != nil {
		if err := bkt.DeleteBucket(bucketKeyRuntime); err != nil {
			return err
		}
	}

	rbkt, err := bkt.CreateBucket(bucketKeyRuntime)
	if err != nil {
		return err
	}

	if err := rbkt.Put(bucketKeyName, []byte(container.Runtime.Name)); err != nil {
		return err
	}

	obkt, err := rbkt.CreateBucket(bucketKeyOptions)
	if err != nil {
		return err
	}

	if container.Runtime.Options != nil {
		data, err := proto.Marshal(container.Runtime.Options)
		if err != nil {
			return err
		}

		if err := obkt.Put(bucketKeyOptions, data); err != nil {
			return err
		}
	}

	return boltutil.WriteLabels(bkt, container.Labels)
}
<commit_msg>metadata: disallow changing the runtime of an existing container<commit_after>package metadata

import (
	"context"
	"strings"
	"time"

	"github.com/boltdb/bolt"
	"github.com/containerd/containerd/containers"
	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/filters"
	"github.com/containerd/containerd/identifiers"
	"github.com/containerd/containerd/metadata/boltutil"
	"github.com/containerd/containerd/namespaces"
	"github.com/gogo/protobuf/proto"
	"github.com/gogo/protobuf/types"
	"github.com/pkg/errors"
)

type containerStore struct {
	tx *bolt.Tx
}

func NewContainerStore(tx *bolt.Tx) containers.Store {
	return &containerStore{
		tx: tx,
	}
}

func (s *containerStore) Get(ctx context.Context, id string) (containers.Container, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return containers.Container{}, err
	}

	bkt := getContainerBucket(s.tx, namespace, id)
	if bkt == nil {
		return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "bucket name %q:%q", namespace, id)
	}

	container := containers.Container{ID: id}
	if err := readContainer(&container, bkt); err != nil {
		return containers.Container{}, errors.Wrapf(err, "failed to read container %v", id)
	}

	return container, nil
}

func (s *containerStore) List(ctx context.Context, fs ...string) ([]containers.Container, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return nil, err
	}

	filter, err := filters.ParseAll(fs...)
	if err != nil {
		return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error())
	}

	bkt := getContainersBucket(s.tx, namespace)
	if bkt == nil {
		return nil, nil
	}

	var m []containers.Container
	if err := bkt.ForEach(func(k, v []byte) error {
		cbkt := bkt.Bucket(k)
		if cbkt == nil {
			return nil
		}
		container := containers.Container{ID: string(k)}

		if err := readContainer(&container, cbkt); err != nil {
			return errors.Wrap(err, "failed to read container")
		}

		if filter.Match(adaptContainer(container)) {
			m = append(m, container)
		}
		return nil
	}); err != nil {
		return nil, err
	}

	return m, nil
}

func (s *containerStore) Create(ctx context.Context, container containers.Container) (containers.Container, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return containers.Container{}, err
	}

	if err := identifiers.Validate(container.ID); err != nil {
		return containers.Container{}, err
	}

	bkt, err := createContainersBucket(s.tx, namespace)
	if err != nil {
		return containers.Container{}, err
	}

	cbkt, err := bkt.CreateBucket([]byte(container.ID))
	if err != nil {
		if err == bolt.ErrBucketExists {
			err = errors.Wrapf(errdefs.ErrAlreadyExists, "content %q", container.ID)
		}
		return containers.Container{}, err
	}

	container.CreatedAt = time.Now().UTC()
	container.UpdatedAt = container.CreatedAt
	if err := writeContainer(cbkt, &container); err != nil {
		return containers.Container{}, errors.Wrap(err, "failed to write container")
	}

	return container, nil
}

func (s *containerStore) Update(ctx context.Context, container containers.Container, fieldpaths ...string) (containers.Container, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return containers.Container{}, err
	}

	if container.ID == "" {
		return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "must specify a container id")
	}

	bkt := getContainersBucket(s.tx, namespace)
	if bkt == nil {
		return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
	}

	cbkt := bkt.Bucket([]byte(container.ID))
	if cbkt == nil {
		return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
	}

	var updated containers.Container
	if err := readContainer(&updated, cbkt); err != nil {
		return updated, errors.Wrapf(err, "failed to read container from bucket")
	}
	createdat := updated.CreatedAt
	updated.ID = container.ID

	// apply the field mask. If you update this code, you better follow the
	// field mask rules in field_mask.proto. If you don't know what this
	// is, do not update this code.
	if len(fieldpaths) > 0 {
		// TODO(stevvooe): Move this logic into the store itself.
		for _, path := range fieldpaths {
			if strings.HasPrefix(path, "labels.") {
				if updated.Labels == nil {
					updated.Labels = map[string]string{}
				}
				key := strings.TrimPrefix(path, "labels.")
				updated.Labels[key] = container.Labels[key]
				continue
			}

			switch path {
			case "labels":
				updated.Labels = container.Labels
			case "image":
				updated.Image = container.Image
			case "spec":
				updated.Spec = container.Spec
			case "rootfs":
				updated.RootFS = container.RootFS
			default:
				return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
			}
		}
	} else {
		// no field mask present, just replace everything
		updated = container
	}

	updated.CreatedAt = createdat
	updated.UpdatedAt = time.Now().UTC()
	if err := writeContainer(cbkt, &updated); err != nil {
		return containers.Container{}, errors.Wrap(err, "failed to write container")
	}

	return container, nil
}

func (s *containerStore) Delete(ctx context.Context, id string) error {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return err
	}

	bkt := getContainersBucket(s.tx, namespace)
	if bkt == nil {
		return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %v, bucket not present", id)
	}

	if err := bkt.DeleteBucket([]byte(id)); err == bolt.ErrBucketNotFound {
		return errors.Wrapf(errdefs.ErrNotFound, "container %v", id)
	}
	return err
}

func readContainer(container *containers.Container, bkt *bolt.Bucket) error {
	labels, err := boltutil.ReadLabels(bkt)
	if err != nil {
		return err
	}
	container.Labels = labels

	if err := boltutil.ReadTimestamps(bkt, &container.CreatedAt, &container.UpdatedAt); err != nil {
		return err
	}

	return bkt.ForEach(func(k, v []byte) error {
		switch string(k) {
		case string(bucketKeyImage):
			container.Image = string(v)
		case string(bucketKeyRuntime):
			rbkt := bkt.Bucket(bucketKeyRuntime)
			if rbkt == nil {
				return nil // skip runtime. should be an error?
			}

			n := rbkt.Get(bucketKeyName)
			if n != nil {
				container.Runtime.Name = string(n)
			}

			obkt := rbkt.Get(bucketKeyOptions)
			if obkt == nil {
				return nil
			}

			var any types.Any
			if err := proto.Unmarshal(obkt, &any); err != nil {
				return err
			}
			container.Runtime.Options = &any
		case string(bucketKeySpec):
			var any types.Any
			if err := proto.Unmarshal(v, &any); err != nil {
				return err
			}
			container.Spec = &any
		case string(bucketKeyRootFS):
			container.RootFS = string(v)

		}

		return nil
	})
}

func writeContainer(bkt *bolt.Bucket, container *containers.Container) error {
	if err := boltutil.WriteTimestamps(bkt, container.CreatedAt, container.UpdatedAt); err != nil {
		return err
	}

	spec, err := container.Spec.Marshal()
	if err != nil {
		return err
	}

	for _, v := range [][2][]byte{
		{bucketKeyImage, []byte(container.Image)},
		{bucketKeySpec, spec},
		{bucketKeyRootFS, []byte(container.RootFS)},
	} {
		if err := bkt.Put(v[0], v[1]); err != nil {
			return err
		}
	}

	if rbkt := bkt.Bucket(bucketKeyRuntime); rbkt != nil {
		if err := bkt.DeleteBucket(bucketKeyRuntime); err != nil {
			return err
		}
	}

	rbkt, err := bkt.CreateBucket(bucketKeyRuntime)
	if err != nil {
		return err
	}

	if err := rbkt.Put(bucketKeyName, []byte(container.Runtime.Name)); err != nil {
		return err
	}

	obkt, err := rbkt.CreateBucket(bucketKeyOptions)
	if err != nil {
		return err
	}

	if container.Runtime.Options != nil {
		data, err := proto.Marshal(container.Runtime.Options)
		if err != nil {
			return err
		}

		if err := obkt.Put(bucketKeyOptions, data); err != nil {
			return err
		}
	}

	return boltutil.WriteLabels(bkt, container.Labels)
}
<|endoftext|>


<commit_before>package dns

// A structure for handling zone data

import (
	"github.com/miekg/radix"
	"strings"
	"sync"
	"time"
)

// Zone represents a DNS zone. It's safe for concurrent use by
// multilpe goroutines.
type Zone struct {
	Origin       string // Origin of the zone
	Wildcard     int    // Whenever we see a wildcard name, this is incremented
	*radix.Radix        // Zone data
	mutex        *sync.RWMutex
	// timemodified?
	expired bool // Slave zone is expired
}

// SignatureConfig holds the parameters for zone (re)signing. This
// is copied from OpenDNSSEC. See:
// https://wiki.opendnssec.org/display/DOCS/kasp.xml
type SignatureConfig struct {
	// Validity period of the signatures, typically 2 to 4 weeks.
	Validity time.Duration
	// When the end of the validity approaches, how much time should remain
	// before we start to resign. Typical value is 3 days.
	Refresh time.Duration
	// Jitter is an amount of time added or subtracted from the
	// expiration time to ensure not all signatures expire a the same time.
	// Typical value is 12 hours.
	Jitter time.Duration
	// InceptionOffset is subtracted from the inception time to ensure badly
	// calibrated clocks on the internet can still validate a signature.
	// Typical value is 300 seconds.
	InceptionOffset time.Duration
}

func newSignatureConfig() *SignatureConfig {
	return &SignatureConfig{time.Duration(4*7*24) * time.Hour, time.Duration(3*24) * time.Hour, time.Duration(12) * time.Hour, time.Duration(300) * time.Second}
}

// DefaultSignaturePolicy has the following values. Validity is 4 weeks,
// Refresh is set to 3 days, Jitter to 12 hours and InceptionOffset to 300 seconds.
var DefaultSignatureConfig = newSignatureConfig()

// NewZone creates an initialized zone with Origin set to origin.
func NewZone(origin string) *Zone {
	if origin == "" {
		origin = "."
	}
	if _, _, ok := IsDomainName(origin); !ok {
		return nil
	}
	z := new(Zone)
	z.mutex = new(sync.RWMutex)
	z.Origin = Fqdn(origin)
	z.Radix = radix.New()
	return z
}

// ZoneData holds all the RRs having their owner name equal to Name.
type ZoneData struct {
	Name       string                 // Domain name for this node
	RR         map[uint16][]RR        // Map of the RR type to the RR
	Signatures map[uint16][]*RR_RRSIG // DNSSEC signatures for the RRs, stored under type covered
	NonAuth    bool                   // Always false, except for NSsets that differ from z.Origin
	mutex      *sync.RWMutex
}

// newZoneData creates a new zone data element
func newZoneData(s string) *ZoneData {
	zd := new(ZoneData)
	zd.Name = s
	zd.RR = make(map[uint16][]RR)
	zd.Signatures = make(map[uint16][]*RR_RRSIG)
	zd.mutex = new(sync.RWMutex)
	return zd
}

// toRadixName reverses a domain name so that when we store it in the radix tree
// we preserve the nsec ordering of the zone (this idea was stolen from NSD).
// each label is also lowercased.
func toRadixName(d string) string {
	if d == "." {
		return "."
	}
	s := ""
	for _, l := range SplitLabels(d) {
		s = strings.ToLower(l) + "." + s
	}
	return "." + s
}

// Insert inserts an RR into the zone. There is no check for duplicate data, although
// Remove will remove all duplicates.
func (z *Zone) Insert(r RR) error {
	if !IsSubDomain(z.Origin, r.Header().Name) {
		return &Error{Err: "out of zone data", Name: r.Header().Name}
	}

	// TODO(mg): quick check for doubles
	key := toRadixName(r.Header().Name)
	z.mutex.Lock()
	zd := z.Radix.Find(key)
	if zd == nil {
		defer z.mutex.Unlock()
		// Check if it's a wildcard name
		if len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
			z.Wildcard++
		}
		zd := newZoneData(r.Header().Name)
		switch t := r.Header().Rrtype; t {
		case TypeRRSIG:
			sigtype := r.(*RR_RRSIG).TypeCovered
			zd.Signatures[sigtype] = append(zd.Signatures[sigtype], r.(*RR_RRSIG))
		case TypeNS:
			// NS records with other names than z.Origin are non-auth
			if r.Header().Name != z.Origin {
				zd.NonAuth = true
			}
			fallthrough
		default:
			zd.RR[t] = append(zd.RR[t], r)
		}
		z.Radix.Insert(key, zd)
		return nil
	}
	z.mutex.Unlock()
	zd.Value.(*ZoneData).mutex.Lock()
	defer zd.Value.(*ZoneData).mutex.Unlock()
	// Name already there
	switch t := r.Header().Rrtype; t {
	case TypeRRSIG:
		sigtype := r.(*RR_RRSIG).TypeCovered
		zd.Value.(*ZoneData).Signatures[sigtype] = append(zd.Value.(*ZoneData).Signatures[sigtype], r.(*RR_RRSIG))
	case TypeNS:
		if r.Header().Name != z.Origin {
			zd.Value.(*ZoneData).NonAuth = true
		}
		fallthrough
	default:
		zd.Value.(*ZoneData).RR[t] = append(zd.Value.(*ZoneData).RR[t], r)
	}
	return nil
}

// Remove removes the RR r from the zone. If the RR can not be found,
// this is a no-op.
func (z *Zone) Remove(r RR) error {
	key := toRadixName(r.Header().Name)
	z.mutex.Lock()
	zd := z.Radix.Find(key)
	if zd == nil {
		defer z.mutex.Unlock()
		return nil
	}
	z.mutex.Unlock()
	zd.Value.(*ZoneData).mutex.Lock()
	defer zd.Value.(*ZoneData).mutex.Unlock()
	remove := false
	switch t := r.Header().Rrtype; t {
	case TypeRRSIG:
		sigtype := r.(*RR_RRSIG).TypeCovered
		for i, zr := range zd.Value.(*ZoneData).RR[sigtype] {
			if r == zr {
				zd.Value.(*ZoneData).RR[sigtype] = append(zd.Value.(*ZoneData).RR[sigtype][:i], zd.Value.(*ZoneData).RR[sigtype][i+1:]...)
				remove = true
			}
		}
	default:
		for i, zr := range zd.Value.(*ZoneData).RR[t] {
			if r == zr {
				zd.Value.(*ZoneData).RR[t] = append(zd.Value.(*ZoneData).RR[t][:i], zd.Value.(*ZoneData).RR[t][i+1:]...)
				remove = true
			}
		}
	}
	if remove && len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
		z.Wildcard--
		if z.Wildcard < 0 {
			z.Wildcard = 0
		}
	}
	// TODO(mg): what to do if the whole structure is empty? Set it to nil?
	return nil
}

// Find looks up the ownername s in the zone and returns the
// data when found or nil when nothing is found.
func (z *Zone) Find(s string) *ZoneData {
	z.mutex.RLock()
	defer z.mutex.RUnlock()
	zd := z.Radix.Find(toRadixName(s))
	if zd == nil {
		return nil
	}
	return zd.Value.(*ZoneData)
}

// Predecessor searches the zone for a name shorter than s.
func (z *Zone) Predecessor(s string) *ZoneData {
	z.mutex.RLock()
	defer z.mutex.RUnlock()
	zd := z.Radix.Predecessor(toRadixName(s))
	if zd == nil {
		return nil
	}
	return zd.Value.(*ZoneData)
}

// Sign (re)signes the zone z. It adds keys to the zone (if not already there)
// and signs the keys with the KSKs and the rest of the zone with the ZSKs.
// NSEC is used for authenticated denial
// of existence. If config is nil DefaultSignatureConfig is used.
// TODO(mg): allow interaction with hsm
func (z *Zone) Sign(keys []*RR_DNSKEY, privkeys []PrivateKey, config *SignatureConfig) error {
	if config == nil {
		config = DefaultSignatureConfig
	}
	// TODO(mg): concurrently walk the zone and sign the rrsets
	// TODO(mg): nsec, or next pointer. Need to be a single tree-op

	return nil
}

// Sign each ZoneData in place.
// TODO(mg): assume not signed
func signZoneData(zd *ZoneData, privkeys []PrivateKey, config *SignatureConfig) {
	if zd.NonAuth == true {
		return
	}
	s := new(RR_RRSIG)
	// signername

}
<commit_msg>trying to work out something nice<commit_after>package dns

// A structure for handling zone data

import (
	"github.com/miekg/radix"
	"strings"
	"sync"
	"time"
)

// Zone represents a DNS zone. It's safe for concurrent use by
// multilpe goroutines.
type Zone struct {
	Origin       string // Origin of the zone
	Wildcard     int    // Whenever we see a wildcard name, this is incremented
	*radix.Radix        // Zone data
	mutex        *sync.RWMutex
	// timemodified?
	expired bool // Slave zone is expired
}

// SignatureConfig holds the parameters for zone (re)signing. This
// is copied from OpenDNSSEC. See:
// https://wiki.opendnssec.org/display/DOCS/kasp.xml
type SignatureConfig struct {
	// Validity period of the signatures, typically 2 to 4 weeks.
	Validity time.Duration
	// When the end of the validity approaches, how much time should remain
	// before we start to resign. Typical value is 3 days.
	Refresh time.Duration
	// Jitter is an amount of time added or subtracted from the
	// expiration time to ensure not all signatures expire a the same time.
	// Typical value is 12 hours.
	Jitter time.Duration
	// InceptionOffset is subtracted from the inception time to ensure badly
	// calibrated clocks on the internet can still validate a signature.
	// Typical value is 300 seconds.
	InceptionOffset time.Duration
}

func newSignatureConfig() *SignatureConfig {
	return &SignatureConfig{time.Duration(4*7*24) * time.Hour, time.Duration(3*24) * time.Hour, time.Duration(12) * time.Hour, time.Duration(300) * time.Second}
}

// DefaultSignaturePolicy has the following values. Validity is 4 weeks,
// Refresh is set to 3 days, Jitter to 12 hours and InceptionOffset to 300 seconds.
var DefaultSignatureConfig = newSignatureConfig()

// NewZone creates an initialized zone with Origin set to origin.
func NewZone(origin string) *Zone {
	if origin == "" {
		origin = "."
	}
	if _, _, ok := IsDomainName(origin); !ok {
		return nil
	}
	z := new(Zone)
	z.mutex = new(sync.RWMutex)
	z.Origin = Fqdn(origin)
	z.Radix = radix.New()
	return z
}

// ZoneData holds all the RRs having their owner name equal to Name.
type ZoneData struct {
	Name       string                 // Domain name for this node
	RR         map[uint16][]RR        // Map of the RR type to the RR
	Signatures map[uint16][]*RR_RRSIG // DNSSEC signatures for the RRs, stored under type covered
	NonAuth    bool                   // Always false, except for NSsets that differ from z.Origin
	mutex      *sync.RWMutex
}

// newZoneData creates a new zone data element
func newZoneData(s string) *ZoneData {
	zd := new(ZoneData)
	zd.Name = s
	zd.RR = make(map[uint16][]RR)
	zd.Signatures = make(map[uint16][]*RR_RRSIG)
	zd.mutex = new(sync.RWMutex)
	return zd
}

// toRadixName reverses a domain name so that when we store it in the radix tree
// we preserve the nsec ordering of the zone (this idea was stolen from NSD).
// each label is also lowercased.
func toRadixName(d string) string {
	if d == "." {
		return "."
	}
	s := ""
	for _, l := range SplitLabels(d) {
		s = strings.ToLower(l) + "." + s
	}
	return "." + s
}

// Insert inserts an RR into the zone. There is no check for duplicate data, although
// Remove will remove all duplicates.
func (z *Zone) Insert(r RR) error {
	if !IsSubDomain(z.Origin, r.Header().Name) {
		return &Error{Err: "out of zone data", Name: r.Header().Name}
	}

	// TODO(mg): quick check for doubles
	key := toRadixName(r.Header().Name)
	z.mutex.Lock()
	zd := z.Radix.Find(key)
	if zd == nil {
		defer z.mutex.Unlock()
		// Check if it's a wildcard name
		if len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
			z.Wildcard++
		}
		zd := newZoneData(r.Header().Name)
		switch t := r.Header().Rrtype; t {
		case TypeRRSIG:
			sigtype := r.(*RR_RRSIG).TypeCovered
			zd.Signatures[sigtype] = append(zd.Signatures[sigtype], r.(*RR_RRSIG))
		case TypeNS:
			// NS records with other names than z.Origin are non-auth
			if r.Header().Name != z.Origin {
				zd.NonAuth = true
			}
			fallthrough
		default:
			zd.RR[t] = append(zd.RR[t], r)
		}
		z.Radix.Insert(key, zd)
		return nil
	}
	z.mutex.Unlock()
	zd.Value.(*ZoneData).mutex.Lock()
	defer zd.Value.(*ZoneData).mutex.Unlock()
	// Name already there
	switch t := r.Header().Rrtype; t {
	case TypeRRSIG:
		sigtype := r.(*RR_RRSIG).TypeCovered
		zd.Value.(*ZoneData).Signatures[sigtype] = append(zd.Value.(*ZoneData).Signatures[sigtype], r.(*RR_RRSIG))
	case TypeNS:
		if r.Header().Name != z.Origin {
			zd.Value.(*ZoneData).NonAuth = true
		}
		fallthrough
	default:
		zd.Value.(*ZoneData).RR[t] = append(zd.Value.(*ZoneData).RR[t], r)
	}
	return nil
}

// Remove removes the RR r from the zone. If the RR can not be found,
// this is a no-op.
func (z *Zone) Remove(r RR) error {
	key := toRadixName(r.Header().Name)
	z.mutex.Lock()
	zd := z.Radix.Find(key)
	if zd == nil {
		defer z.mutex.Unlock()
		return nil
	}
	z.mutex.Unlock()
	zd.Value.(*ZoneData).mutex.Lock()
	defer zd.Value.(*ZoneData).mutex.Unlock()
	remove := false
	switch t := r.Header().Rrtype; t {
	case TypeRRSIG:
		sigtype := r.(*RR_RRSIG).TypeCovered
		for i, zr := range zd.Value.(*ZoneData).RR[sigtype] {
			if r == zr {
				zd.Value.(*ZoneData).RR[sigtype] = append(zd.Value.(*ZoneData).RR[sigtype][:i], zd.Value.(*ZoneData).RR[sigtype][i+1:]...)
				remove = true
			}
		}
	default:
		for i, zr := range zd.Value.(*ZoneData).RR[t] {
			if r == zr {
				zd.Value.(*ZoneData).RR[t] = append(zd.Value.(*ZoneData).RR[t][:i], zd.Value.(*ZoneData).RR[t][i+1:]...)
				remove = true
			}
		}
	}
	if remove && len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
		z.Wildcard--
		if z.Wildcard < 0 {
			z.Wildcard = 0
		}
	}
	// TODO(mg): what to do if the whole structure is empty? Set it to nil?
	return nil
}

// Find looks up the ownername s in the zone and returns the
// data when found or nil when nothing is found.
func (z *Zone) Find(s string) *ZoneData {
	z.mutex.RLock()
	defer z.mutex.RUnlock()
	zd := z.Radix.Find(toRadixName(s))
	if zd == nil {
		return nil
	}
	return zd.Value.(*ZoneData)
}

// Predecessor searches the zone for a name shorter than s.
func (z *Zone) Predecessor(s string) *ZoneData {
	z.mutex.RLock()
	defer z.mutex.RUnlock()
	zd := z.Radix.Predecessor(toRadixName(s))
	if zd == nil {
		return nil
	}
	return zd.Value.(*ZoneData)
}

// Sign (re)signes the zone z. It adds keys to the zone (if not already there)
// and signs the keys with the KSKs and the rest of the zone with the ZSKs.
// NSEC is used for authenticated denial
// of existence. If config is nil DefaultSignatureConfig is used.
// TODO(mg): allow interaction with hsm
func (z *Zone) Sign(keys []*RR_DNSKEY, privkeys []PrivateKey, config *SignatureConfig) error {
	if config == nil {
		config = DefaultSignatureConfig
	}
	// TODO(mg): concurrently walk the zone and sign the rrsets
	// TODO(mg): nsec, or next pointer. Need to be a single tree-op

	return nil
}

// Sign each ZoneData in place.
// TODO(mg): assume not signed
func signZoneData(zd *ZoneData, privkeys []PrivateKey, signername string, config *SignatureConfig) {
	if zd.NonAuth == true {
		return
	}
	s := new(RR_RRSIG)
	// signername

}
<|endoftext|>


<commit_before>package main

import (
	"./dns"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

func createRequests(rname string) {
	workerPool.Input <- WorkerInput{Name: rname, Type: dns.TypeA}
	workerPool.Input <- WorkerInput{Name: rname, Type: dns.TypeAAAA}
	workerPool.Input <- WorkerInput{Name: rname, Type: dns.TypeMX}
	workerPool.Input <- WorkerInput{Name: rname, Type: dns.TypeTXT}
}

func loadWords(fn string) ([]string, error) {
	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, err
	}
	return strings.Split(string(b), "\n"), nil
}

func zoneCmd(dom, fnWords string) {
	words, err := loadWords(fnWords)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}

	go func() {
		createRequests(dom + ".")

		for _, w := range words {
			rname := w + "." + dom + "."
			if len(w) == 0 {
				continue
			}

			createRequests(rname)

			for i := 0; i < 20; i++ {
				createRequests(w + strconv.Itoa(i) + "." + dom + ".")
			}

		}
		workerPool.Shutdown()
	}()

	for out, ok := <-workerPool.Output; ok; out, ok = <-workerPool.Output {
		if out.Error == nil {
			for _, a := range out.Answer {
				fmt.Println(a)
			}
		} else {
			if err, ok := out.Error.(*DNSError); !ok || err.Rcode != dns.RcodeNameError {
				fmt.Println(out.Name, out.Error)
			}
		}
	}
}
<commit_msg>Abort program when words file cannot be opened<commit_after>package main

import (
	"./dns"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

func createRequests(rname string) {
	workerPool.Input <- WorkerInput{Name: rname, Type: dns.TypeA}
	workerPool.Input <- WorkerInput{Name: rname, Type: dns.TypeAAAA}
	workerPool.Input <- WorkerInput{Name: rname, Type: dns.TypeMX}
	workerPool.Input <- WorkerInput{Name: rname, Type: dns.TypeTXT}
}

func loadWords(fn string) ([]string, error) {
	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, err
	}
	return strings.Split(string(b), "\n"), nil
}

func zoneCmd(dom, fnWords string) {
	words, err := loadWords(fnWords)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}

	go func() {
		createRequests(dom + ".")

		for _, w := range words {
			rname := w + "." + dom + "."
			if len(w) == 0 {
				continue
			}

			createRequests(rname)

			for i := 0; i < 20; i++ {
				createRequests(w + strconv.Itoa(i) + "." + dom + ".")
			}

		}
		workerPool.Shutdown()
	}()

	for out, ok := <-workerPool.Output; ok; out, ok = <-workerPool.Output {
		if out.Error == nil {
			for _, a := range out.Answer {
				fmt.Println(a)
			}
		} else {
			if err, ok := out.Error.(*DNSError); !ok || err.Rcode != dns.RcodeNameError {
				fmt.Println(out.Name, out.Error)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package migration

import (
	"io"
	"io/ioutil"
	"os"

	"github.com/juju/errors"
	"github.com/juju/juju/version"
	"github.com/juju/loggo"
	"github.com/juju/utils/set"
	"gopkg.in/juju/charm.v6-unstable"
	"gopkg.in/mgo.v2"

	"github.com/juju/juju/api"
	"github.com/juju/juju/core/description"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/state"
	"github.com/juju/juju/state/storage"
	"github.com/juju/juju/state/toolstorage"
	"github.com/juju/juju/tools"
)

var logger = loggo.GetLogger("juju.migration")

// ImportModel deserializes a model description from the bytes, transforms
// the model config based on information from the controller model, and then
// imports that as a new database model.
func ImportModel(st *state.State, bytes []byte) (*state.Model, *state.State, error) {
	model, err := description.Deserialize(bytes)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	controllerModel, err := st.ControllerModel()
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	controllerConfig, err := controllerModel.Config()
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	model.UpdateConfig(controllerValues(controllerConfig))

	if err := updateConfigFromProvider(model, controllerConfig); err != nil {
		return nil, nil, errors.Trace(err)
	}

	dbModel, dbState, err := st.Import(model)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	return dbModel, dbState, nil
}

func controllerValues(config *config.Config) map[string]interface{} {
	result := make(map[string]interface{})

	result["state-port"] = config.StatePort()
	result["api-port"] = config.APIPort()
	// We ignore the second bool param from the CACert check as if there
	// wasn't a CACert, there is no way we'd be importing a new model
	// into the controller
	result["ca-cert"], _ = config.CACert()

	return result
}

func updateConfigFromProvider(model description.Model, controllerConfig *config.Config) error {
	newConfig, err := config.New(config.NoDefaults, model.Config())
	if err != nil {
		return errors.Trace(err)
	}

	provider, err := environs.New(newConfig)
	if err != nil {
		return errors.Trace(err)
	}

	updater, ok := provider.(environs.MigrationConfigUpdater)
	if !ok {
		return nil
	}

	model.UpdateConfig(updater.MigrationConfigUpdate(controllerConfig))
	return nil
}

// UploadBackend define the methods on *state.State that are needed for
// uploading the tools and charms from the current controller to a different
// controller.
type UploadBackend interface {
	Charm(*charm.URL) (*state.Charm, error)
	ModelUUID() string
	MongoSession() *mgo.Session
	ToolsStorage() (toolstorage.StorageCloser, error)
}

// CharmUploader defines a simple single method interface that is used to
// upload a charm to the target controller
type CharmUploader interface {
	UploadCharm(*charm.URL, io.ReadSeeker) (*charm.URL, error)
}

// ToolsUploader defines a simple single method interface that is used to
// upload tools to the target controller
type ToolsUploader interface {
	UploadTools(io.ReadSeeker, version.Binary, ...string) (*tools.Tools, error)
}

// UploadBinariesConfig provides all the configuration that the UploadBinaries
// function needs to operate. The functions are configurable for testing
// purposes. To construct the config with the default functions, use
// `NewUploadBinariesConfig`.
type UploadBinariesConfig struct {
	State  UploadBackend
	Model  description.Model
	Target api.Connection

	GetCharmUploader func(api.Connection) CharmUploader
	GetToolsUploader func(api.Connection) ToolsUploader

	GetStateStorage     func(UploadBackend) storage.Storage
	GetCharmStoragePath func(UploadBackend, *charm.URL) (string, error)
}

// NewUploadBinariesConfig constructs a `UploadBinariesConfig` with the default
// functions to get the uploaders for the target api connection, and functions
// used to get the charm data out of the database.
func NewUploadBinariesConfig(backend UploadBackend, model description.Model, target api.Connection) UploadBinariesConfig {
	return UploadBinariesConfig{
		State:  backend,
		Model:  model,
		Target: target,

		GetCharmUploader:    getCharmUploader,
		GetStateStorage:     getStateStorage,
		GetToolsUploader:    getToolsUploader,
		GetCharmStoragePath: getCharmStoragePath,
	}
}

// Validate makes sure that all the config values are non-nil.
func (c *UploadBinariesConfig) Validate() error {
	if c.State == nil {
		return errors.NotValidf("missing UploadBackend")
	}
	if c.Model == nil {
		return errors.NotValidf("missing Model")
	}
	if c.Target == nil {
		return errors.NotValidf("missing Target")
	}
	if c.GetCharmUploader == nil {
		return errors.NotValidf("missing GetCharmUploader")
	}
	if c.GetStateStorage == nil {
		return errors.NotValidf("missing GetStateStorage")
	}
	if c.GetToolsUploader == nil {
		return errors.NotValidf("missing GetToolsUploader")
	}
	if c.GetCharmStoragePath == nil {
		return errors.NotValidf("missing GetCharmStoragePath")
	}
	return nil
}

// UploadBinaries will send binaries stored in the source blobstore to
// the target controller.
func UploadBinaries(config UploadBinariesConfig) error {
	if err := config.Validate(); err != nil {
		return errors.Trace(err)
	}
	if err := streamTools(config); err != nil {
		return errors.Trace(err)
	}

	if err := streamCharms(config); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func getStateStorage(backend UploadBackend) storage.Storage {
	return storage.NewStorage(backend.ModelUUID(), backend.MongoSession())
}

func getToolsUploader(target api.Connection) ToolsUploader {
	return target.Client()
}

func getCharmUploader(target api.Connection) CharmUploader {
	return target.Client()
}

func streamTools(config UploadBinariesConfig) error {
	storage, err := config.State.ToolsStorage()
	if err != nil {
		return errors.Trace(err)
	}
	defer storage.Close()

	usedVersions := getUsedToolsVersions(config.Model)
	toolsUploader := config.GetToolsUploader(config.Target)

	for toolsVersion := range usedVersions {
		logger.Debugf("send tools version %s to target", toolsVersion)
		_, reader, err := storage.Tools(toolsVersion)
		if err != nil {
			return errors.Trace(err)
		}
		defer reader.Close()

		content, cleanup, err := streamThroughTempFile(reader)
		if err != nil {
			return errors.Trace(err)
		}
		defer cleanup()

		// UploadTools encapsulates the HTTP POST necessary to send the tools
		// to the target API server.
		if _, err := toolsUploader.UploadTools(content, toolsVersion); err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}

func streamThroughTempFile(r io.Reader) (_ io.ReadSeeker, cleanup func(), err error) {
	tempFile, err := ioutil.TempFile("", "juju-tools")
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	defer func() {
		if err != nil {
			os.Remove(tempFile.Name())
		}
	}()
	_, err = io.Copy(tempFile, r)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	tempFile.Seek(0, 0)
	rmTempFile := func() {
		filename := tempFile.Name()
		tempFile.Close()
		os.Remove(filename)
	}

	return tempFile, rmTempFile, nil
}

func getUsedToolsVersions(model description.Model) map[version.Binary]bool {
	// Iterate through the model for all tools, and make a map of them.
	usedVersions := make(map[version.Binary]bool)
	// It is most likely that the preconditions will limit the number of
	// tools versions in use, but that is not depended on here.
	for _, machine := range model.Machines() {
		addToolsVersionForMachine(machine, usedVersions)
	}

	for _, service := range model.Services() {
		for _, unit := range service.Units() {
			tools := unit.Tools()
			usedVersions[tools.Version()] = true
		}
	}
	return usedVersions
}

func addToolsVersionForMachine(machine description.Machine, usedVersions map[version.Binary]bool) {
	tools := machine.Tools()
	usedVersions[tools.Version()] = true
	for _, container := range machine.Containers() {
		addToolsVersionForMachine(container, usedVersions)
	}
}

func streamCharms(config UploadBinariesConfig) error {
	storage := config.GetStateStorage(config.State)
	usedCharms := getUsedCharms(config.Model)
	charmUploader := config.GetCharmUploader(config.Target)

	for _, charmUrl := range usedCharms.Values() {
		logger.Debugf("send charm %s to target", charmUrl)

		curl, err := charm.ParseURL(charmUrl)
		if err != nil {
			return errors.Annotate(err, "bad charm URL")
		}

		path, err := config.GetCharmStoragePath(config.State, curl)
		if err != nil {
			return errors.Trace(err)
		}

		reader, _, err := storage.Get(path)
		if err != nil {
			return errors.Annotate(err, "cannot get charm from storage")
		}
		defer reader.Close()

		content, cleanup, err := streamThroughTempFile(reader)
		if err != nil {
			return errors.Trace(err)
		}
		defer cleanup()

		if _, err := charmUploader.UploadCharm(curl, content); err != nil {
			return errors.Annotate(err, "cannot upload charm")
		}
	}
	return nil
}

func getUsedCharms(model description.Model) set.Strings {
	result := set.NewStrings()
	for _, service := range model.Services() {
		result.Add(service.CharmURL())
	}
	return result
}

func getCharmStoragePath(st UploadBackend, curl *charm.URL) (string, error) {
	ch, err := st.Charm(curl)
	if err != nil {
		return "", errors.Annotate(err, "cannot get charm from state")
	}

	return ch.StoragePath(), nil
}
<commit_msg>s/stream/upload/<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package migration

import (
	"io"
	"io/ioutil"
	"os"

	"github.com/juju/errors"
	"github.com/juju/juju/version"
	"github.com/juju/loggo"
	"github.com/juju/utils/set"
	"gopkg.in/juju/charm.v6-unstable"
	"gopkg.in/mgo.v2"

	"github.com/juju/juju/api"
	"github.com/juju/juju/core/description"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/state"
	"github.com/juju/juju/state/storage"
	"github.com/juju/juju/state/toolstorage"
	"github.com/juju/juju/tools"
)

var logger = loggo.GetLogger("juju.migration")

// ImportModel deserializes a model description from the bytes, transforms
// the model config based on information from the controller model, and then
// imports that as a new database model.
func ImportModel(st *state.State, bytes []byte) (*state.Model, *state.State, error) {
	model, err := description.Deserialize(bytes)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	controllerModel, err := st.ControllerModel()
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	controllerConfig, err := controllerModel.Config()
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	model.UpdateConfig(controllerValues(controllerConfig))

	if err := updateConfigFromProvider(model, controllerConfig); err != nil {
		return nil, nil, errors.Trace(err)
	}

	dbModel, dbState, err := st.Import(model)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	return dbModel, dbState, nil
}

func controllerValues(config *config.Config) map[string]interface{} {
	result := make(map[string]interface{})

	result["state-port"] = config.StatePort()
	result["api-port"] = config.APIPort()
	// We ignore the second bool param from the CACert check as if there
	// wasn't a CACert, there is no way we'd be importing a new model
	// into the controller
	result["ca-cert"], _ = config.CACert()

	return result
}

func updateConfigFromProvider(model description.Model, controllerConfig *config.Config) error {
	newConfig, err := config.New(config.NoDefaults, model.Config())
	if err != nil {
		return errors.Trace(err)
	}

	provider, err := environs.New(newConfig)
	if err != nil {
		return errors.Trace(err)
	}

	updater, ok := provider.(environs.MigrationConfigUpdater)
	if !ok {
		return nil
	}

	model.UpdateConfig(updater.MigrationConfigUpdate(controllerConfig))
	return nil
}

// UploadBackend define the methods on *state.State that are needed for
// uploading the tools and charms from the current controller to a different
// controller.
type UploadBackend interface {
	Charm(*charm.URL) (*state.Charm, error)
	ModelUUID() string
	MongoSession() *mgo.Session
	ToolsStorage() (toolstorage.StorageCloser, error)
}

// CharmUploader defines a simple single method interface that is used to
// upload a charm to the target controller
type CharmUploader interface {
	UploadCharm(*charm.URL, io.ReadSeeker) (*charm.URL, error)
}

// ToolsUploader defines a simple single method interface that is used to
// upload tools to the target controller
type ToolsUploader interface {
	UploadTools(io.ReadSeeker, version.Binary, ...string) (*tools.Tools, error)
}

// UploadBinariesConfig provides all the configuration that the UploadBinaries
// function needs to operate. The functions are configurable for testing
// purposes. To construct the config with the default functions, use
// `NewUploadBinariesConfig`.
type UploadBinariesConfig struct {
	State  UploadBackend
	Model  description.Model
	Target api.Connection

	GetCharmUploader func(api.Connection) CharmUploader
	GetToolsUploader func(api.Connection) ToolsUploader

	GetStateStorage     func(UploadBackend) storage.Storage
	GetCharmStoragePath func(UploadBackend, *charm.URL) (string, error)
}

// NewUploadBinariesConfig constructs a `UploadBinariesConfig` with the default
// functions to get the uploaders for the target api connection, and functions
// used to get the charm data out of the database.
func NewUploadBinariesConfig(backend UploadBackend, model description.Model, target api.Connection) UploadBinariesConfig {
	return UploadBinariesConfig{
		State:  backend,
		Model:  model,
		Target: target,

		GetCharmUploader:    getCharmUploader,
		GetStateStorage:     getStateStorage,
		GetToolsUploader:    getToolsUploader,
		GetCharmStoragePath: getCharmStoragePath,
	}
}

// Validate makes sure that all the config values are non-nil.
func (c *UploadBinariesConfig) Validate() error {
	if c.State == nil {
		return errors.NotValidf("missing UploadBackend")
	}
	if c.Model == nil {
		return errors.NotValidf("missing Model")
	}
	if c.Target == nil {
		return errors.NotValidf("missing Target")
	}
	if c.GetCharmUploader == nil {
		return errors.NotValidf("missing GetCharmUploader")
	}
	if c.GetStateStorage == nil {
		return errors.NotValidf("missing GetStateStorage")
	}
	if c.GetToolsUploader == nil {
		return errors.NotValidf("missing GetToolsUploader")
	}
	if c.GetCharmStoragePath == nil {
		return errors.NotValidf("missing GetCharmStoragePath")
	}
	return nil
}

// UploadBinaries will send binaries stored in the source blobstore to
// the target controller.
func UploadBinaries(config UploadBinariesConfig) error {
	if err := config.Validate(); err != nil {
		return errors.Trace(err)
	}
	if err := uploadTools(config); err != nil {
		return errors.Trace(err)
	}

	if err := uploadCharms(config); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func getStateStorage(backend UploadBackend) storage.Storage {
	return storage.NewStorage(backend.ModelUUID(), backend.MongoSession())
}

func getToolsUploader(target api.Connection) ToolsUploader {
	return target.Client()
}

func getCharmUploader(target api.Connection) CharmUploader {
	return target.Client()
}

func uploadTools(config UploadBinariesConfig) error {
	storage, err := config.State.ToolsStorage()
	if err != nil {
		return errors.Trace(err)
	}
	defer storage.Close()

	usedVersions := getUsedToolsVersions(config.Model)
	toolsUploader := config.GetToolsUploader(config.Target)

	for toolsVersion := range usedVersions {
		logger.Debugf("send tools version %s to target", toolsVersion)
		_, reader, err := storage.Tools(toolsVersion)
		if err != nil {
			return errors.Trace(err)
		}
		defer reader.Close()

		content, cleanup, err := streamThroughTempFile(reader)
		if err != nil {
			return errors.Trace(err)
		}
		defer cleanup()

		// UploadTools encapsulates the HTTP POST necessary to send the tools
		// to the target API server.
		if _, err := toolsUploader.UploadTools(content, toolsVersion); err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}

func streamThroughTempFile(r io.Reader) (_ io.ReadSeeker, cleanup func(), err error) {
	tempFile, err := ioutil.TempFile("", "juju-tools")
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	defer func() {
		if err != nil {
			os.Remove(tempFile.Name())
		}
	}()
	_, err = io.Copy(tempFile, r)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	tempFile.Seek(0, 0)
	rmTempFile := func() {
		filename := tempFile.Name()
		tempFile.Close()
		os.Remove(filename)
	}

	return tempFile, rmTempFile, nil
}

func getUsedToolsVersions(model description.Model) map[version.Binary]bool {
	// Iterate through the model for all tools, and make a map of them.
	usedVersions := make(map[version.Binary]bool)
	// It is most likely that the preconditions will limit the number of
	// tools versions in use, but that is not depended on here.
	for _, machine := range model.Machines() {
		addToolsVersionForMachine(machine, usedVersions)
	}

	for _, service := range model.Services() {
		for _, unit := range service.Units() {
			tools := unit.Tools()
			usedVersions[tools.Version()] = true
		}
	}
	return usedVersions
}

func addToolsVersionForMachine(machine description.Machine, usedVersions map[version.Binary]bool) {
	tools := machine.Tools()
	usedVersions[tools.Version()] = true
	for _, container := range machine.Containers() {
		addToolsVersionForMachine(container, usedVersions)
	}
}

func uploadCharms(config UploadBinariesConfig) error {
	storage := config.GetStateStorage(config.State)
	usedCharms := getUsedCharms(config.Model)
	charmUploader := config.GetCharmUploader(config.Target)

	for _, charmUrl := range usedCharms.Values() {
		logger.Debugf("send charm %s to target", charmUrl)

		curl, err := charm.ParseURL(charmUrl)
		if err != nil {
			return errors.Annotate(err, "bad charm URL")
		}

		path, err := config.GetCharmStoragePath(config.State, curl)
		if err != nil {
			return errors.Trace(err)
		}

		reader, _, err := storage.Get(path)
		if err != nil {
			return errors.Annotate(err, "cannot get charm from storage")
		}
		defer reader.Close()

		content, cleanup, err := streamThroughTempFile(reader)
		if err != nil {
			return errors.Trace(err)
		}
		defer cleanup()

		if _, err := charmUploader.UploadCharm(curl, content); err != nil {
			return errors.Annotate(err, "cannot upload charm")
		}
	}
	return nil
}

func getUsedCharms(model description.Model) set.Strings {
	result := set.NewStrings()
	for _, service := range model.Services() {
		result.Add(service.CharmURL())
	}
	return result
}

func getCharmStoragePath(st UploadBackend, curl *charm.URL) (string, error) {
	ch, err := st.Charm(curl)
	if err != nil {
		return "", errors.Annotate(err, "cannot get charm from state")
	}

	return ch.StoragePath(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"time"
)

type HourObservation struct {
	Year_rtm sql.NullInt64
	Datetime time.Time
}

func (d *HourObservation) mawnHeader() []string {
	values := []string{
		"#code",
		"year",
		"day of year",
		"report hour minute",
		"air temperature",
		"relative humidity",
		"solar radiation",
		"soil temperature at 5 cm",
		"soil temperature at 10 cm",
		"soil  moisture at 5 cm",
		"soil moisture at 20 cm",
		"wind direction",
		"wind speed",
		"maximum hourly wind speed",
		"time of maximum wind speed",
		"precipitation",
		"leaf0",
		"leaf1",
		"battery voltage minimum",
		"timestamp",
	}
	return values
}

func (d *HourObservation) mawnUnit() []string {
	values := []string{
		"#",
		"",
		"",
		"",
		"C",
		"%",
		"kJ/m^2",
		"C",
		"C",
		"%",
		"%",
		"degrees",
		"m/s",
		"m/s",
		"",
		"mm",
		"",
		"",
		"",
		"V",
	}
	return values
}
<commit_msg>filled out hour observation type<commit_after>package main

import (
	"database/sql"
	"time"
)

type HourObservation struct {
	Year_rtm              sql.NullInt64
	Day_rtm               sql.NullInt64
	Hourminute_rtm        sql.NullInt64
	Air_temp107_avg       sql.NullFloat64
	Relative_humidity_avg sql.NullFloat64
	Solar_radiation_avg   sql.NullFloat64
	Soil_temp_q_avg       sql.NullFloat64
	Soil_moisture_5_cm    sql.NullFloat64
	Soil_moisture_20_cm   sql.NullFloat64
	Wind_direction_d1_wvt sql.NullFloat64
	Wind_speed_wvt        sql.NullFloat64
	Rain_mm               sql.NullFloat64
	Battery_voltage_min   sql.NullFloat64
	Datetime              time.Time
}

func (d *HourObservation) toMawn() []string {
	values := []string{
		"60",
		intToString(d.Year_rtm),
		intToString(d.Day_rtm),
		intToString(d.Hourminute_rtm),
		floatToString(d.Air_temp107_avg),
		floatToString(d.Relative_humidity_avg),
		floatToString(d.Solar_radiation_avg),
		floatToString(d.Soil_temp_q_avg),
		floatToString(d.Soil_moisture_5_cm),
		floatToString(d.Soil_moisture_20_cm),
		floatToString(d.Wind_direction_d1_wvt),
		floatToString(d.Wind_speed_wvt),
		floatToString(d.Rain_mm),
		floatToString(d.Battery_voltage_min),
		d.Datetime,
	}
	return values
}

func (d *HourObservation) mawnHeader() []string {
	values := []string{
		"#code",
		"year",
		"day of year",
		"report hour minute",
		"air temperature",
		"relative humidity",
		"solar radiation",
		"soil temperature at 5 cm",
		"soil temperature at 10 cm",
		"soil  moisture at 5 cm",
		"soil moisture at 20 cm",
		"wind direction",
		"wind speed",
		"maximum hourly wind speed",
		"time of maximum wind speed",
		"precipitation",
		"leaf0",
		"leaf1",
		"battery voltage minimum",
		"timestamp",
	}
	return values
}

func (d *HourObservation) mawnUnit() []string {
	values := []string{
		"#",
		"",
		"",
		"",
		"C",
		"%",
		"kJ/m^2",
		"C",
		"C",
		"%",
		"%",
		"degrees",
		"m/s",
		"m/s",
		"",
		"mm",
		"",
		"",
		"",
		"V",
	}
	return values
}
<|endoftext|>