<commit_before>// Copyright 2015 CNI authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/binary"
	"fmt"
	"net"
	"strconv"
	"time"

	"github.com/containernetworking/cni/pkg/types"
	"github.com/d2g/dhcp4"
)

var optionNameToID = map[string]dhcp4.OptionCode{
	"dhcp-client-identifier": dhcp4.OptionClientIdentifier,
	"subnet-mask":            dhcp4.OptionSubnetMask,
	"routers":                dhcp4.OptionRouter,
	"host-name":              dhcp4.OptionHostName,
}

func parseOptionName(option string) (dhcp4.OptionCode, error) {
	if val, ok := optionNameToID[option]; ok {
		return val, nil
	}
	i, err := strconv.ParseUint(option, 10, 8)
	if err != nil {
		return 0, fmt.Errorf("Can not parse option: %w", err)
	}
	return dhcp4.OptionCode(i), nil
}

func parseRouter(opts dhcp4.Options) net.IP {
	if opts, ok := opts[dhcp4.OptionRouter]; ok {
		if len(opts) == 4 {
			return net.IP(opts)
		}
	}
	return nil
}

func classfulSubnet(sn net.IP) net.IPNet {
	return net.IPNet{
		IP:   sn,
		Mask: sn.DefaultMask(),
	}
}

func parseRoutes(opts dhcp4.Options) []*types.Route {
	// StaticRoutes format: pairs of:
	// Dest = 4 bytes; Classful IP subnet
	// Router = 4 bytes; IP address of router

	routes := []*types.Route{}
	if opt, ok := opts[dhcp4.OptionStaticRoute]; ok {
		for len(opt) >= 8 {
			sn := opt[0:4]
			r := opt[4:8]
			rt := &types.Route{
				Dst: classfulSubnet(sn),
				GW:  r,
			}
			routes = append(routes, rt)
			opt = opt[8:]
		}
	}

	return routes
}

func parseCIDRRoutes(opts dhcp4.Options) []*types.Route {
	// See RFC4332 for format (http://tools.ietf.org/html/rfc3442)

	routes := []*types.Route{}
	if opt, ok := opts[dhcp4.OptionClasslessRouteFormat]; ok {
		for len(opt) >= 5 {
			width := int(opt[0])
			if width > 32 {
				// error: can't have more than /32
				return nil
			}
			// network bits are compacted to avoid zeros
			octets := 0
			if width > 0 {
				octets = (width-1)/8 + 1
			}

			if len(opt) < 1+octets+4 {
				// error: too short
				return nil
			}

			sn := make([]byte, 4)
			copy(sn, opt[1:octets+1])

			gw := net.IP(opt[octets+1 : octets+5])

			rt := &types.Route{
				Dst: net.IPNet{
					IP:   net.IP(sn),
					Mask: net.CIDRMask(width, 32),
				},
				GW: gw,
			}
			routes = append(routes, rt)

			opt = opt[octets+5:]
		}
	}
	return routes
}

func parseSubnetMask(opts dhcp4.Options) net.IPMask {
	mask, ok := opts[dhcp4.OptionSubnetMask]
	if !ok {
		return nil
	}

	return net.IPMask(mask)
}

func parseDuration(opts dhcp4.Options, code dhcp4.OptionCode, optName string) (time.Duration, error) {
	val, ok := opts[code]
	if !ok {
		return 0, fmt.Errorf("option %v not found", optName)
	}
	if len(val) != 4 {
		return 0, fmt.Errorf("option %v is not 4 bytes", optName)
	}

	secs := binary.BigEndian.Uint32(val)
	return time.Duration(secs) * time.Second, nil
}

func parseLeaseTime(opts dhcp4.Options) (time.Duration, error) {
	return parseDuration(opts, dhcp4.OptionIPAddressLeaseTime, "LeaseTime")
}

func parseRenewalTime(opts dhcp4.Options) (time.Duration, error) {
	return parseDuration(opts, dhcp4.OptionRenewalTimeValue, "RenewalTime")
}

func parseRebindingTime(opts dhcp4.Options) (time.Duration, error) {
	return parseDuration(opts, dhcp4.OptionRebindingTimeValue, "RebindingTime")
}
<commit_msg>dhcp ipam: add more options capable for sending<commit_after>// Copyright 2015 CNI authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/binary"
	"fmt"
	"net"
	"strconv"
	"time"

	"github.com/containernetworking/cni/pkg/types"
	"github.com/d2g/dhcp4"
)

var optionNameToID = map[string]dhcp4.OptionCode{
	"dhcp-client-identifier":  dhcp4.OptionClientIdentifier,
	"subnet-mask":             dhcp4.OptionSubnetMask,
	"routers":                 dhcp4.OptionRouter,
	"host-name":               dhcp4.OptionHostName,
	"user-class":              dhcp4.OptionUserClass,
	"vendor-class-identifier": dhcp4.OptionVendorClassIdentifier,
}

func parseOptionName(option string) (dhcp4.OptionCode, error) {
	if val, ok := optionNameToID[option]; ok {
		return val, nil
	}
	i, err := strconv.ParseUint(option, 10, 8)
	if err != nil {
		return 0, fmt.Errorf("Can not parse option: %w", err)
	}
	return dhcp4.OptionCode(i), nil
}

func parseRouter(opts dhcp4.Options) net.IP {
	if opts, ok := opts[dhcp4.OptionRouter]; ok {
		if len(opts) == 4 {
			return net.IP(opts)
		}
	}
	return nil
}

func classfulSubnet(sn net.IP) net.IPNet {
	return net.IPNet{
		IP:   sn,
		Mask: sn.DefaultMask(),
	}
}

func parseRoutes(opts dhcp4.Options) []*types.Route {
	// StaticRoutes format: pairs of:
	// Dest = 4 bytes; Classful IP subnet
	// Router = 4 bytes; IP address of router

	routes := []*types.Route{}
	if opt, ok := opts[dhcp4.OptionStaticRoute]; ok {
		for len(opt) >= 8 {
			sn := opt[0:4]
			r := opt[4:8]
			rt := &types.Route{
				Dst: classfulSubnet(sn),
				GW:  r,
			}
			routes = append(routes, rt)
			opt = opt[8:]
		}
	}

	return routes
}

func parseCIDRRoutes(opts dhcp4.Options) []*types.Route {
	// See RFC4332 for format (http://tools.ietf.org/html/rfc3442)

	routes := []*types.Route{}
	if opt, ok := opts[dhcp4.OptionClasslessRouteFormat]; ok {
		for len(opt) >= 5 {
			width := int(opt[0])
			if width > 32 {
				// error: can't have more than /32
				return nil
			}
			// network bits are compacted to avoid zeros
			octets := 0
			if width > 0 {
				octets = (width-1)/8 + 1
			}

			if len(opt) < 1+octets+4 {
				// error: too short
				return nil
			}

			sn := make([]byte, 4)
			copy(sn, opt[1:octets+1])

			gw := net.IP(opt[octets+1 : octets+5])

			rt := &types.Route{
				Dst: net.IPNet{
					IP:   net.IP(sn),
					Mask: net.CIDRMask(width, 32),
				},
				GW: gw,
			}
			routes = append(routes, rt)

			opt = opt[octets+5:]
		}
	}
	return routes
}

func parseSubnetMask(opts dhcp4.Options) net.IPMask {
	mask, ok := opts[dhcp4.OptionSubnetMask]
	if !ok {
		return nil
	}

	return net.IPMask(mask)
}

func parseDuration(opts dhcp4.Options, code dhcp4.OptionCode, optName string) (time.Duration, error) {
	val, ok := opts[code]
	if !ok {
		return 0, fmt.Errorf("option %v not found", optName)
	}
	if len(val) != 4 {
		return 0, fmt.Errorf("option %v is not 4 bytes", optName)
	}

	secs := binary.BigEndian.Uint32(val)
	return time.Duration(secs) * time.Second, nil
}

func parseLeaseTime(opts dhcp4.Options) (time.Duration, error) {
	return parseDuration(opts, dhcp4.OptionIPAddressLeaseTime, "LeaseTime")
}

func parseRenewalTime(opts dhcp4.Options) (time.Duration, error) {
	return parseDuration(opts, dhcp4.OptionRenewalTimeValue, "RenewalTime")
}

func parseRebindingTime(opts dhcp4.Options) (time.Duration, error) {
	return parseDuration(opts, dhcp4.OptionRebindingTimeValue, "RebindingTime")
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"math/rand"
	"strings"
	"testing"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/elasticache"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSElasticacheCluster_basic(t *testing.T) {
	var ec elasticache.CacheCluster
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSElasticacheClusterDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccAWSElasticacheClusterConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSElasticacheSecurityGroupExists("aws_elasticache_security_group.bar"),
					testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "cache_nodes.0.id", "0001"),
				),
			},
		},
	})
}

func TestAccAWSElasticacheCluster_snapshotsWithUpdates(t *testing.T) {
	var ec elasticache.CacheCluster

	ri := genRandInt()
	preConfig := fmt.Sprintf(testAccAWSElasticacheClusterConfig_snapshots, ri, ri, ri)
	postConfig := fmt.Sprintf(testAccAWSElasticacheClusterConfig_snapshotsUpdated, ri, ri, ri)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSElasticacheClusterDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: preConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSElasticacheSecurityGroupExists("aws_elasticache_security_group.bar"),
					testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "snapshot_window", "05:00-09:00"),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "snapshot_retention_limit", "3"),
				),
			},

			resource.TestStep{
				Config: postConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSElasticacheSecurityGroupExists("aws_elasticache_security_group.bar"),
					testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "snapshot_window", "07:00-09:00"),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "snapshot_retention_limit", "7"),
				),
			},
		},
	})
}

func TestAccAWSElasticacheCluster_vpc(t *testing.T) {
	var csg elasticache.CacheSubnetGroup
	var ec elasticache.CacheCluster
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSElasticacheClusterDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccAWSElasticacheClusterInVPCConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSElasticacheSubnetGroupExists("aws_elasticache_subnet_group.bar", &csg),
					testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
					testAccCheckAWSElasticacheClusterAttributes(&ec),
				),
			},
		},
	})
}

func testAccCheckAWSElasticacheClusterAttributes(v *elasticache.CacheCluster) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if v.NotificationConfiguration == nil {
			return fmt.Errorf("Expected NotificationConfiguration for ElastiCache Cluster (%s)", *v.CacheClusterId)
		}

		if strings.ToLower(*v.NotificationConfiguration.TopicStatus) != "active" {
			return fmt.Errorf("Expected NotificationConfiguration status to be 'active', got (%s)", *v.NotificationConfiguration.TopicStatus)
		}

		return nil
	}
}

func testAccCheckAWSElasticacheClusterDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).elasticacheconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_elasticache_cluster" {
			continue
		}
		res, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{
			CacheClusterId: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return err
		}
		if len(res.CacheClusters) > 0 {
			return fmt.Errorf("still exist.")
		}
	}
	return nil
}

func testAccCheckAWSElasticacheClusterExists(n string, v *elasticache.CacheCluster) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No cache cluster ID is set")
		}

		conn := testAccProvider.Meta().(*AWSClient).elasticacheconn
		resp, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{
			CacheClusterId: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return fmt.Errorf("Elasticache error: %v", err)
		}

		for _, c := range resp.CacheClusters {
			if *c.CacheClusterId == rs.Primary.ID {
				*v = *c
			}
		}

		return nil
	}
}

func genRandInt() int {
	return rand.New(rand.NewSource(time.Now().UnixNano())).Int() % 1000
}

var testAccAWSElasticacheClusterConfig = fmt.Sprintf(`
provider "aws" {
	region = "us-east-1"
}
resource "aws_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_elasticache_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    security_group_names = ["${aws_security_group.bar.name}"]
}

resource "aws_elasticache_cluster" "bar" {
    cluster_id = "tf-test-%03d"
    engine = "memcached"
    node_type = "cache.m1.small"
    num_cache_nodes = 1
    port = 11211
    parameter_group_name = "default.memcached1.4"
    security_group_names = ["${aws_elasticache_security_group.bar.name}"]
}
`, genRandInt(), genRandInt(), genRandInt())

var testAccAWSElasticacheClusterConfig_snapshots = `
provider "aws" {
	region = "us-east-1"
}
resource "aws_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_elasticache_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    security_group_names = ["${aws_security_group.bar.name}"]
}

resource "aws_elasticache_cluster" "bar" {
    cluster_id = "tf-test-%03d"
    engine = "redis"
    node_type = "cache.t2.small"
    num_cache_nodes = 1
    port = 6379
  	parameter_group_name = "default.redis2.8"
    security_group_names = ["${aws_elasticache_security_group.bar.name}"]
    snapshot_window = "05:00-09:00"
    snapshot_retention_limit = 3
}
`

var testAccAWSElasticacheClusterConfig_snapshotsUpdated = `
provider "aws" {
	region = "us-east-1"
}
resource "aws_security_group" "bar" {
    name = "tf-test-security-group"
    description = "tf-test-security-group-descr"
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_elasticache_security_group" "bar" {
    name = "tf-test-security-group"
    description = "tf-test-security-group-descr"
    security_group_names = ["${aws_security_group.bar.name}"]
}

resource "aws_elasticache_cluster" "bar" {
    cluster_id = "tf-test-%03d"
    engine = "redis"
    node_type = "cache.m1.small"
    num_cache_nodes = 1
    port = 6379
  	parameter_group_name = "default.redis2.8"
    security_group_names = ["${aws_elasticache_security_group.bar.name}"]
    snapshot_window = "07:00-09:00"
    snapshot_retention_limit = 7
    apply_immediately = true
}
`

var testAccAWSElasticacheClusterInVPCConfig = fmt.Sprintf(`
resource "aws_vpc" "foo" {
    cidr_block = "192.168.0.0/16"
    tags {
            Name = "tf-test"
    }
}

resource "aws_subnet" "foo" {
    vpc_id = "${aws_vpc.foo.id}"
    cidr_block = "192.168.0.0/20"
    availability_zone = "us-west-2a"
    tags {
            Name = "tf-test"
    }
}

resource "aws_elasticache_subnet_group" "bar" {
    name = "tf-test-cache-subnet-%03d"
    description = "tf-test-cache-subnet-group-descr"
    subnet_ids = ["${aws_subnet.foo.id}"]
}

resource "aws_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    vpc_id = "${aws_vpc.foo.id}"
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_elasticache_cluster" "bar" {
    // Including uppercase letters in this name to ensure
    // that we correctly handle the fact that the API
    // normalizes names to lowercase.
    cluster_id = "tf-TEST-%03d"
    node_type = "cache.m1.small"
    num_cache_nodes = 1
    engine = "redis"
    engine_version = "2.8.19"
    port = 6379
    subnet_group_name = "${aws_elasticache_subnet_group.bar.name}"
    security_group_ids = ["${aws_security_group.bar.id}"]
    parameter_group_name = "default.redis2.8"
    notification_topic_arn      = "${aws_sns_topic.topic_example.arn}"
}

resource "aws_sns_topic" "topic_example" {
  name = "tf-ecache-cluster-test"
}
`, genRandInt(), genRandInt(), genRandInt())
<commit_msg>config updates for ElastiCache test<commit_after>package aws

import (
	"fmt"
	"math/rand"
	"strings"
	"testing"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/elasticache"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSElasticacheCluster_basic(t *testing.T) {
	var ec elasticache.CacheCluster
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSElasticacheClusterDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccAWSElasticacheClusterConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSElasticacheSecurityGroupExists("aws_elasticache_security_group.bar"),
					testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "cache_nodes.0.id", "0001"),
				),
			},
		},
	})
}

func TestAccAWSElasticacheCluster_snapshotsWithUpdates(t *testing.T) {
	var ec elasticache.CacheCluster

	ri := genRandInt()
	preConfig := fmt.Sprintf(testAccAWSElasticacheClusterConfig_snapshots, ri, ri, ri)
	postConfig := fmt.Sprintf(testAccAWSElasticacheClusterConfig_snapshotsUpdated, ri, ri, ri)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSElasticacheClusterDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: preConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSElasticacheSecurityGroupExists("aws_elasticache_security_group.bar"),
					testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "snapshot_window", "05:00-09:00"),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "snapshot_retention_limit", "3"),
				),
			},

			resource.TestStep{
				Config: postConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSElasticacheSecurityGroupExists("aws_elasticache_security_group.bar"),
					testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "snapshot_window", "07:00-09:00"),
					resource.TestCheckResourceAttr(
						"aws_elasticache_cluster.bar", "snapshot_retention_limit", "7"),
				),
			},
		},
	})
}

func TestAccAWSElasticacheCluster_vpc(t *testing.T) {
	var csg elasticache.CacheSubnetGroup
	var ec elasticache.CacheCluster
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSElasticacheClusterDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccAWSElasticacheClusterInVPCConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSElasticacheSubnetGroupExists("aws_elasticache_subnet_group.bar", &csg),
					testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
					testAccCheckAWSElasticacheClusterAttributes(&ec),
				),
			},
		},
	})
}

func testAccCheckAWSElasticacheClusterAttributes(v *elasticache.CacheCluster) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if v.NotificationConfiguration == nil {
			return fmt.Errorf("Expected NotificationConfiguration for ElastiCache Cluster (%s)", *v.CacheClusterId)
		}

		if strings.ToLower(*v.NotificationConfiguration.TopicStatus) != "active" {
			return fmt.Errorf("Expected NotificationConfiguration status to be 'active', got (%s)", *v.NotificationConfiguration.TopicStatus)
		}

		return nil
	}
}

func testAccCheckAWSElasticacheClusterDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).elasticacheconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_elasticache_cluster" {
			continue
		}
		res, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{
			CacheClusterId: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return err
		}
		if len(res.CacheClusters) > 0 {
			return fmt.Errorf("still exist.")
		}
	}
	return nil
}

func testAccCheckAWSElasticacheClusterExists(n string, v *elasticache.CacheCluster) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No cache cluster ID is set")
		}

		conn := testAccProvider.Meta().(*AWSClient).elasticacheconn
		resp, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{
			CacheClusterId: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return fmt.Errorf("Elasticache error: %v", err)
		}

		for _, c := range resp.CacheClusters {
			if *c.CacheClusterId == rs.Primary.ID {
				*v = *c
			}
		}

		return nil
	}
}

func genRandInt() int {
	return rand.New(rand.NewSource(time.Now().UnixNano())).Int() % 1000
}

var testAccAWSElasticacheClusterConfig = fmt.Sprintf(`
provider "aws" {
	region = "us-east-1"
}
resource "aws_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_elasticache_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    security_group_names = ["${aws_security_group.bar.name}"]
}

resource "aws_elasticache_cluster" "bar" {
    cluster_id = "tf-test-%03d"
    engine = "memcached"
    node_type = "cache.m1.small"
    num_cache_nodes = 1
    port = 11211
    parameter_group_name = "default.memcached1.4"
    security_group_names = ["${aws_elasticache_security_group.bar.name}"]
}
`, genRandInt(), genRandInt(), genRandInt())

var testAccAWSElasticacheClusterConfig_snapshots = `
provider "aws" {
	region = "us-east-1"
}
resource "aws_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_elasticache_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    security_group_names = ["${aws_security_group.bar.name}"]
}

resource "aws_elasticache_cluster" "bar" {
    cluster_id = "tf-test-%03d"
    engine = "redis"
    node_type = "cache.m1.small"
    num_cache_nodes = 1
    port = 6379
  	parameter_group_name = "default.redis2.8"
    security_group_names = ["${aws_elasticache_security_group.bar.name}"]
    snapshot_window = "05:00-09:00"
    snapshot_retention_limit = 3
}
`

var testAccAWSElasticacheClusterConfig_snapshotsUpdated = `
provider "aws" {
	region = "us-east-1"
}
resource "aws_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_elasticache_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    security_group_names = ["${aws_security_group.bar.name}"]
}

resource "aws_elasticache_cluster" "bar" {
    cluster_id = "tf-test-%03d"
    engine = "redis"
    node_type = "cache.m1.small"
    num_cache_nodes = 1
    port = 6379
  	parameter_group_name = "default.redis2.8"
    security_group_names = ["${aws_elasticache_security_group.bar.name}"]
    snapshot_window = "07:00-09:00"
    snapshot_retention_limit = 7
    apply_immediately = true
}
`

var testAccAWSElasticacheClusterInVPCConfig = fmt.Sprintf(`
resource "aws_vpc" "foo" {
    cidr_block = "192.168.0.0/16"
    tags {
            Name = "tf-test"
    }
}

resource "aws_subnet" "foo" {
    vpc_id = "${aws_vpc.foo.id}"
    cidr_block = "192.168.0.0/20"
    availability_zone = "us-west-2a"
    tags {
            Name = "tf-test"
    }
}

resource "aws_elasticache_subnet_group" "bar" {
    name = "tf-test-cache-subnet-%03d"
    description = "tf-test-cache-subnet-group-descr"
    subnet_ids = ["${aws_subnet.foo.id}"]
}

resource "aws_security_group" "bar" {
    name = "tf-test-security-group-%03d"
    description = "tf-test-security-group-descr"
    vpc_id = "${aws_vpc.foo.id}"
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_elasticache_cluster" "bar" {
    // Including uppercase letters in this name to ensure
    // that we correctly handle the fact that the API
    // normalizes names to lowercase.
    cluster_id = "tf-TEST-%03d"
    node_type = "cache.m1.small"
    num_cache_nodes = 1
    engine = "redis"
    engine_version = "2.8.19"
    port = 6379
    subnet_group_name = "${aws_elasticache_subnet_group.bar.name}"
    security_group_ids = ["${aws_security_group.bar.id}"]
    parameter_group_name = "default.redis2.8"
    notification_topic_arn      = "${aws_sns_topic.topic_example.arn}"
}

resource "aws_sns_topic" "topic_example" {
  name = "tf-ecache-cluster-test"
}
`, genRandInt(), genRandInt(), genRandInt())
<|endoftext|>


<commit_before>package chroot

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/mitchellh/multistep"
	awscommon "github.com/mitchellh/packer/builder/amazon/common"
	"github.com/mitchellh/packer/packer"
)

// StepRegisterAMI creates the AMI.
type StepRegisterAMI struct{}

func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction {
	config := state.Get("config").(*Config)
	ec2conn := state.Get("ec2").(*ec2.EC2)
	image := state.Get("source_image").(*ec2.Image)
	snapshotId := state.Get("snapshot_id").(string)
	ui := state.Get("ui").(packer.Ui)

	ui.Say("Registering the AMI...")
	blockDevices := make([]*ec2.BlockDeviceMapping, len(image.BlockDeviceMappings))
	for i, device := range image.BlockDeviceMappings {
		newDevice := device
		if *newDevice.DeviceName == *image.RootDeviceName {
			if newDevice.EBS != nil {
				newDevice.EBS.SnapshotID = aws.String(snapshotId)
			} else {
				newDevice.EBS = &ec2.EBSBlockDevice{SnapshotID: aws.String(snapshotId)}
			}
		}

		// assume working from a snapshot, so we unset the Encrypted field if set,
		// otherwise AWS API will return InvalidParameter
		if newDevice.EBS.Encrypted != nil {
			newDevice.EBS.Encrypted = nil
		}

		blockDevices[i] = newDevice
	}

	registerOpts := buildRegisterOpts(config, image, blockDevices)

	// Set SriovNetSupport to "simple". See http://goo.gl/icuXh5
	if config.AMIEnhancedNetworking {
		registerOpts.SRIOVNetSupport = aws.String("simple")
	}

	registerResp, err := ec2conn.RegisterImage(registerOpts)
	if err != nil {
		state.Put("error", fmt.Errorf("Error registering AMI: %s", err))
		ui.Error(state.Get("error").(error).Error())
		return multistep.ActionHalt
	}

	// Set the AMI ID in the state
	ui.Say(fmt.Sprintf("AMI: %s", *registerResp.ImageID))
	amis := make(map[string]string)
	amis[ec2conn.Config.Region] = *registerResp.ImageID
	state.Put("amis", amis)

	// Wait for the image to become ready
	stateChange := awscommon.StateChangeConf{
		Pending:   []string{"pending"},
		Target:    "available",
		Refresh:   awscommon.AMIStateRefreshFunc(ec2conn, *registerResp.ImageID),
		StepState: state,
	}

	ui.Say("Waiting for AMI to become ready...")
	if _, err := awscommon.WaitForState(&stateChange); err != nil {
		err := fmt.Errorf("Error waiting for AMI: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	return multistep.ActionContinue
}

func (s *StepRegisterAMI) Cleanup(state multistep.StateBag) {}

func buildRegisterOpts(config *Config, image *ec2.Image, blockDevices []*ec2.BlockDeviceMapping) *ec2.RegisterImageInput {
	registerOpts := &ec2.RegisterImageInput{
		Name:                &config.AMIName,
		Architecture:        image.Architecture,
		RootDeviceName:      image.RootDeviceName,
		BlockDeviceMappings: blockDevices,
		VirtualizationType:  image.VirtualizationType,
	}

	if config.AMIVirtType != "" {
		registerOpts.VirtualizationType = aws.String(config.AMIVirtType)
	}

	if config.AMIVirtType != "hvm" {
		registerOpts.KernelID = image.KernelID
		registerOpts.RAMDiskID = image.RAMDiskID
	}

	return registerOpts
}
<commit_msg>check if newDevice.EBS is nil<commit_after>package chroot

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/mitchellh/multistep"
	awscommon "github.com/mitchellh/packer/builder/amazon/common"
	"github.com/mitchellh/packer/packer"
)

// StepRegisterAMI creates the AMI.
type StepRegisterAMI struct{}

func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction {
	config := state.Get("config").(*Config)
	ec2conn := state.Get("ec2").(*ec2.EC2)
	image := state.Get("source_image").(*ec2.Image)
	snapshotId := state.Get("snapshot_id").(string)
	ui := state.Get("ui").(packer.Ui)

	ui.Say("Registering the AMI...")
	blockDevices := make([]*ec2.BlockDeviceMapping, len(image.BlockDeviceMappings))
	for i, device := range image.BlockDeviceMappings {
		newDevice := device
		if *newDevice.DeviceName == *image.RootDeviceName {
			if newDevice.EBS != nil {
				newDevice.EBS.SnapshotID = aws.String(snapshotId)
			} else {
				newDevice.EBS = &ec2.EBSBlockDevice{SnapshotID: aws.String(snapshotId)}
			}
		}

		// assume working from a snapshot, so we unset the Encrypted field if set,
		// otherwise AWS API will return InvalidParameter
		if newDevice.EBS != nil && newDevice.EBS.Encrypted != nil {
			newDevice.EBS.Encrypted = nil
		}

		blockDevices[i] = newDevice
	}

	registerOpts := buildRegisterOpts(config, image, blockDevices)

	// Set SriovNetSupport to "simple". See http://goo.gl/icuXh5
	if config.AMIEnhancedNetworking {
		registerOpts.SRIOVNetSupport = aws.String("simple")
	}

	registerResp, err := ec2conn.RegisterImage(registerOpts)
	if err != nil {
		state.Put("error", fmt.Errorf("Error registering AMI: %s", err))
		ui.Error(state.Get("error").(error).Error())
		return multistep.ActionHalt
	}

	// Set the AMI ID in the state
	ui.Say(fmt.Sprintf("AMI: %s", *registerResp.ImageID))
	amis := make(map[string]string)
	amis[ec2conn.Config.Region] = *registerResp.ImageID
	state.Put("amis", amis)

	// Wait for the image to become ready
	stateChange := awscommon.StateChangeConf{
		Pending:   []string{"pending"},
		Target:    "available",
		Refresh:   awscommon.AMIStateRefreshFunc(ec2conn, *registerResp.ImageID),
		StepState: state,
	}

	ui.Say("Waiting for AMI to become ready...")
	if _, err := awscommon.WaitForState(&stateChange); err != nil {
		err := fmt.Errorf("Error waiting for AMI: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	return multistep.ActionContinue
}

func (s *StepRegisterAMI) Cleanup(state multistep.StateBag) {}

func buildRegisterOpts(config *Config, image *ec2.Image, blockDevices []*ec2.BlockDeviceMapping) *ec2.RegisterImageInput {
	registerOpts := &ec2.RegisterImageInput{
		Name:                &config.AMIName,
		Architecture:        image.Architecture,
		RootDeviceName:      image.RootDeviceName,
		BlockDeviceMappings: blockDevices,
		VirtualizationType:  image.VirtualizationType,
	}

	if config.AMIVirtType != "" {
		registerOpts.VirtualizationType = aws.String(config.AMIVirtType)
	}

	if config.AMIVirtType != "hvm" {
		registerOpts.KernelID = image.KernelID
		registerOpts.RAMDiskID = image.RAMDiskID
	}

	return registerOpts
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"reflect"
	"sort"
	"strings"
	"testing"
	"text/template"
)

var (
	output   = flag.String("o", "", "output filename")
	pkg      = flag.String("pkg", "", "test package")
	exitCode = 0
)

type data struct {
	Package                 string
	Tests                   []string
	HasMain                 bool
	MainStartTakesInterface bool
}

func findTests(srcs []string) (tests []string, hasMain bool) {
	for _, src := range srcs {
		f, err := parser.ParseFile(token.NewFileSet(), src, nil, 0)
		if err != nil {
			panic(err)
		}
		for _, obj := range f.Scope.Objects {
			if obj.Kind != ast.Fun || !strings.HasPrefix(obj.Name, "Test") {
				continue
			}
			if obj.Name == "TestMain" {
				hasMain = true
			} else {
				tests = append(tests, obj.Name)
			}
		}
	}
	sort.Strings(tests)
	return
}

// Returns true for go1.8+, where testing.MainStart takes an interface instead of a function
// as its first argument.
func mainStartTakesInterface() bool {
	return reflect.TypeOf(testing.MainStart).In(0).Kind() == reflect.Interface
}

func main() {
	flag.Parse()

	if flag.NArg() == 0 {
		fmt.Fprintln(os.Stderr, "error: must pass at least one input")
		exitCode = 1
		return
	}

	buf := &bytes.Buffer{}

	tests, hasMain := findTests(flag.Args())

	d := data{
		Package:                 *pkg,
		Tests:                   tests,
		HasMain:                 hasMain,
		MainStartTakesInterface: mainStartTakesInterface(),
	}

	err := testMainTmpl.Execute(buf, d)
	if err != nil {
		panic(err)
	}

	err = ioutil.WriteFile(*output, buf.Bytes(), 0666)
	if err != nil {
		panic(err)
	}
}

var testMainTmpl = template.Must(template.New("testMain").Parse(`
package main

import (
	"io"
{{if not .HasMain}}
	"os"
{{end}}
	"regexp"
	"testing"

	pkg "{{.Package}}"
)

var t = []testing.InternalTest{
{{range .Tests}}
	{"{{.}}", pkg.{{.}}},
{{end}}
}

var matchPat string
var matchRe *regexp.Regexp

type matchString struct{}

func MatchString(pat, str string) (result bool, err error) {
	if matchRe == nil || matchPat != pat {
		matchPat = pat
		matchRe, err = regexp.Compile(matchPat)
		if err != nil {
			return
		}
	}
	return matchRe.MatchString(str), nil
}

func (matchString) MatchString(pat, str string) (bool, error) {
	return MatchString(pat, str)
}

func (matchString) StartCPUProfile(w io.Writer) error {
	panic("shouldn't get here")
}

func (matchString) StopCPUProfile() {
}

func (matchString) WriteHeapProfile(w io.Writer) error {
    panic("shouldn't get here")
}

func (matchString) WriteProfileTo(string, io.Writer, int) error {
    panic("shouldn't get here")
}

func (matchString) ImportPath() string {
	return "{{.Package}}"
}

func (matchString) StartTestLog(io.Writer) {
	panic("shouldn't get here")
}

func (matchString) StopTestLog() error {
	panic("shouldn't get here")
}

func main() {
{{if .MainStartTakesInterface}}
	m := testing.MainStart(matchString{}, t, nil, nil)
{{else}}
	m := testing.MainStart(MatchString, t, nil, nil)
{{end}}
{{if .HasMain}}
	pkg.TestMain(m)
{{else}}
	os.Exit(m.Run())
{{end}}
}
`))
<commit_msg>Support examples as tests<commit_after>// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/doc"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"reflect"
	"sort"
	"strings"
	"testing"
	"text/template"
)

var (
	output   = flag.String("o", "", "output filename")
	pkg      = flag.String("pkg", "", "test package")
	exitCode = 0
)

type data struct {
	Package                 string
	Tests                   []string
	Examples                []*doc.Example
	HasMain                 bool
	MainStartTakesInterface bool
}

func findTests(srcs []string) (tests []string, examples []*doc.Example, hasMain bool) {
	for _, src := range srcs {
		f, err := parser.ParseFile(token.NewFileSet(), src, nil, parser.ParseComments)
		if err != nil {
			panic(err)
		}
		for _, obj := range f.Scope.Objects {
			if obj.Kind != ast.Fun || !strings.HasPrefix(obj.Name, "Test") {
				continue
			}
			if obj.Name == "TestMain" {
				hasMain = true
			} else {
				tests = append(tests, obj.Name)
			}
		}

		examples = append(examples, doc.Examples(f)...)
	}
	sort.Strings(tests)
	return
}

// Returns true for go1.8+, where testing.MainStart takes an interface instead of a function
// as its first argument.
func mainStartTakesInterface() bool {
	return reflect.TypeOf(testing.MainStart).In(0).Kind() == reflect.Interface
}

func main() {
	flag.Parse()

	if flag.NArg() == 0 {
		fmt.Fprintln(os.Stderr, "error: must pass at least one input")
		exitCode = 1
		return
	}

	buf := &bytes.Buffer{}

	tests, examples, hasMain := findTests(flag.Args())

	d := data{
		Package:                 *pkg,
		Tests:                   tests,
		Examples:                examples,
		HasMain:                 hasMain,
		MainStartTakesInterface: mainStartTakesInterface(),
	}

	err := testMainTmpl.Execute(buf, d)
	if err != nil {
		panic(err)
	}

	err = ioutil.WriteFile(*output, buf.Bytes(), 0666)
	if err != nil {
		panic(err)
	}
}

var testMainTmpl = template.Must(template.New("testMain").Parse(`
package main

import (
	"io"
{{if not .HasMain}}
	"os"
{{end}}
	"regexp"
	"testing"

	pkg "{{.Package}}"
)

var t = []testing.InternalTest{
{{range .Tests}}
	{"{{.}}", pkg.{{.}}},
{{end}}
}

var e = []testing.InternalExample{
{{range .Examples}}
	{{if or .Output .EmptyOutput}}
		{"{{.Name}}", pkg.Example{{.Name}}, {{.Output | printf "%q" }}, {{.Unordered}}},
	{{end}}
{{end}}
}

var matchPat string
var matchRe *regexp.Regexp

type matchString struct{}

func MatchString(pat, str string) (result bool, err error) {
	if matchRe == nil || matchPat != pat {
		matchPat = pat
		matchRe, err = regexp.Compile(matchPat)
		if err != nil {
			return
		}
	}
	return matchRe.MatchString(str), nil
}

func (matchString) MatchString(pat, str string) (bool, error) {
	return MatchString(pat, str)
}

func (matchString) StartCPUProfile(w io.Writer) error {
	panic("shouldn't get here")
}

func (matchString) StopCPUProfile() {
}

func (matchString) WriteHeapProfile(w io.Writer) error {
    panic("shouldn't get here")
}

func (matchString) WriteProfileTo(string, io.Writer, int) error {
    panic("shouldn't get here")
}

func (matchString) ImportPath() string {
	return "{{.Package}}"
}

func (matchString) StartTestLog(io.Writer) {
	panic("shouldn't get here")
}

func (matchString) StopTestLog() error {
	panic("shouldn't get here")
}

func main() {
{{if .MainStartTakesInterface}}
	m := testing.MainStart(matchString{}, t, nil, e)
{{else}}
	m := testing.MainStart(MatchString, t, nil, e)
{{end}}
{{if .HasMain}}
	pkg.TestMain(m)
{{else}}
	os.Exit(m.Run())
{{end}}
}
`))
<|endoftext|>


<commit_before>package admin

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	_path "path"
	"strconv"
)

// Reference represents a specific location in Database
type Reference struct {
	database *Database
	path     string

	// queries
	startAt      interface{}
	endAt        interface{}
	orderBy      interface{}
	equalTo      interface{}
	limitToFirst int
	limitToLast  int
}

func marshalJSON(v interface{}) (string, error) {
	b, err := json.Marshal(v)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func addQueryJSON(q url.Values, name string, value interface{}) error {
	s, err := marshalJSON(value)
	if err != nil {
		return err
	}
	q.Add(name, s)
	return nil
}

func addQueryInt(q url.Values, name string, value int) {
	s := strconv.Itoa(value)
	q.Add(name, s)
}

func (ref *Reference) buildQuery(q url.Values) error {
	var err error

	if ref.startAt != nil {
		err = addQueryJSON(q, "startAt", ref.startAt)
		if err != nil {
			return err
		}
	}

	if ref.endAt != nil {
		err = addQueryJSON(q, "endAt", ref.endAt)
		if err != nil {
			return err
		}
	}

	if ref.orderBy != nil {
		err = addQueryJSON(q, "orderBy", ref.orderBy)
		if err != nil {
			return err
		}
	}

	if ref.equalTo != nil {
		err = addQueryJSON(q, "equalTo", ref.equalTo)
		if err != nil {
			return err
		}
	}

	if ref.limitToFirst != 0 {
		addQueryInt(q, "limitToFirst", ref.limitToFirst)
	}

	if ref.limitToLast != 0 {
		addQueryInt(q, "limitToLast", ref.limitToLast)
	}

	return nil
}

func (ref *Reference) url() (*url.URL, error) {
	u, err := url.Parse(ref.database.app.databaseURL + "/" + ref.path + ".json")
	if err != nil {
		return nil, err
	}
	q := u.Query()
	err = ref.buildQuery(q)
	if err != nil {
		return nil, err
	}

	u.RawQuery = q.Encode()
	return u, nil
}

func (ref *Reference) invokeRequest(method string, body io.Reader) ([]byte, error) {
	url, err := ref.url()
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest(method, url.String(), body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	resp, err := ref.database.app.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusOK {
		var e struct {
			Error string `json:"error"`
		}
		err = json.Unmarshal(b, &e)
		if err != nil {
			e.Error = resp.Status
		}
		return nil, fmt.Errorf("firebasedatabase: %s", e.Error)
	}
	return bytes.TrimSpace(b), nil
}

// Set writes data to current location
func (ref *Reference) Set(value interface{}) error {
	buf := bytes.NewBuffer([]byte{})
	err := json.NewEncoder(buf).Encode(value)
	if err != nil {
		return err
	}
	_, err = ref.invokeRequest(http.MethodPut, buf)
	if err != nil {
		return err
	}
	return nil
}

// Push pushs data to current location
func (ref Reference) Push(value interface{}) (*Reference, error) {
	buf := bytes.NewBuffer([]byte{})
	err := json.NewEncoder(buf).Encode(value)
	if err != nil {
		return nil, err
	}
	b, err := ref.invokeRequest(http.MethodPost, buf)
	if err != nil {
		return nil, err
	}

	var r struct {
		Name string `json:"name"`
	}
	err = json.Unmarshal(b, &r)
	if err != nil {
		return nil, err
	}

	nRef := ref
	nRef.path = _path.Join(ref.path, r.Name)

	return &nRef, nil
}

// Remove removes data from current location
func (ref *Reference) Remove() error {
	_, err := ref.invokeRequest(http.MethodDelete, nil)
	if err != nil {
		return err
	}
	return nil
}

// Key returns the last path of Reference
func (ref *Reference) Key() string {
	_, p := _path.Split(ref.path)
	return p
}

// Ref returns a copy
func (ref Reference) Ref() *Reference {
	return &ref
}

// Root returns the root location of database
func (ref *Reference) Root() *Reference {
	return &Reference{
		database: ref.database,
	}
}

// Child returns a Reference for relative path
func (ref Reference) Child(path string) *Reference {
	ref.path = _path.Join(ref.path, path)
	return &ref
}

// Parent returns the parent location of Reference
func (ref Reference) Parent() *Reference {
	ref.path, _ = _path.Split(ref.path)
	return &ref
}

// EndAt implements Query interface
func (ref Reference) EndAt(value interface{}) Query {
	ref.endAt = value
	return &ref
}

// StartAt implements Query interface
func (ref Reference) StartAt(value interface{}) Query {
	ref.startAt = value
	return &ref
}

// EqualTo implements Query interface
func (ref Reference) EqualTo(value interface{}) Query {
	ref.equalTo = value
	return &ref
}

// IsEqual returns true if current and provided query is the same location,
// save query params, and same App instance
func (ref *Reference) IsEqual(other Query) bool {
	r := other.Ref()

	// check app instance
	if ref.database.app != r.database.app {
		return false
	}

	// check location
	if ref.path != r.path {
		return false
	}

	// check queries
	q1, q2 := url.Values{}, url.Values{}
	ref.buildQuery(q1)
	r.buildQuery(q2)
	if len(q1) != len(q2) || q1.Encode() != q2.Encode() {
		return false
	}

	return true
}

// LimitToFirst implements Query interface
func (ref Reference) LimitToFirst(limit int) Query {
	ref.limitToFirst = limit
	return &ref
}

// LimitToLast implements Query interface
func (ref Reference) LimitToLast(limit int) Query {
	ref.limitToLast = limit
	return &ref
}

// OrderByChild implements Query interface
func (ref Reference) OrderByChild(path interface{}) Query {
	ref.orderBy = path
	return &ref
}

// OrderByKey implements Query interface
func (ref Reference) OrderByKey() Query {
	ref.orderBy = "$key"
	return &ref
}

// OrderByPriority implements Query interface
func (ref Reference) OrderByPriority() Query {
	ref.orderBy = "$priority"
	return &ref
}

// OrderByValue implements Query interface
func (ref Reference) OrderByValue() Query {
	ref.orderBy = "$value"
	return &ref
}

// OnValue implements Query interface
func (ref *Reference) OnValue(event chan *DataSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnChildAdded implements Query interface
func (ref *Reference) OnChildAdded(event chan *ChildSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnChildRemoved implements Query interface
func (ref *Reference) OnChildRemoved(event chan *OldChildSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnChildChanged implements Query interface
func (ref *Reference) OnChildChanged(event chan *ChildSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnChildMoved implements Query interface
func (ref *Reference) OnChildMoved(event chan *ChildSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnceValue implements Query interface
func (ref *Reference) OnceValue() (*DataSnapshot, error) {
	// TODO: find from cached first
	b, err := ref.invokeRequest(http.MethodGet, nil)
	if err != nil {
		return nil, err
	}
	return &DataSnapshot{
		ref: ref,
		raw: b,
	}, nil
}

// OnceChildAdded implements Query interface
func (ref *Reference) OnceChildAdded() *ChildSnapshot {
	panic(ErrNotImplemented)
}

// OnceChildRemove implements Query interface
func (ref *Reference) OnceChildRemove() *OldChildSnapshot {
	panic(ErrNotImplemented)
}

// OnceChildChanged implements Query interface
func (ref *Reference) OnceChildChanged() *ChildSnapshot {
	panic(ErrNotImplemented)
}

// OnceChildMoved implements Query interface
func (ref *Reference) OnceChildMoved() *ChildSnapshot {
	panic(ErrNotImplemented)
}

// String returns absolute URL for this location
func (ref *Reference) String() string {
	u, err := ref.url()
	if err != nil {
		return ""
	}
	q := u.Query()
	q.Del("access_token")
	u.RawQuery = q.Encode()
	return u.String()
}
<commit_msg>database: fix typo<commit_after>package admin

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	_path "path"
	"strconv"
)

// Reference represents a specific location in Database
type Reference struct {
	database *Database
	path     string

	// queries
	startAt      interface{}
	endAt        interface{}
	orderBy      interface{}
	equalTo      interface{}
	limitToFirst int
	limitToLast  int
}

func marshalJSON(v interface{}) (string, error) {
	b, err := json.Marshal(v)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func addQueryJSON(q url.Values, name string, value interface{}) error {
	s, err := marshalJSON(value)
	if err != nil {
		return err
	}
	q.Add(name, s)
	return nil
}

func addQueryInt(q url.Values, name string, value int) {
	s := strconv.Itoa(value)
	q.Add(name, s)
}

func (ref *Reference) buildQuery(q url.Values) error {
	var err error

	if ref.startAt != nil {
		err = addQueryJSON(q, "startAt", ref.startAt)
		if err != nil {
			return err
		}
	}

	if ref.endAt != nil {
		err = addQueryJSON(q, "endAt", ref.endAt)
		if err != nil {
			return err
		}
	}

	if ref.orderBy != nil {
		err = addQueryJSON(q, "orderBy", ref.orderBy)
		if err != nil {
			return err
		}
	}

	if ref.equalTo != nil {
		err = addQueryJSON(q, "equalTo", ref.equalTo)
		if err != nil {
			return err
		}
	}

	if ref.limitToFirst != 0 {
		addQueryInt(q, "limitToFirst", ref.limitToFirst)
	}

	if ref.limitToLast != 0 {
		addQueryInt(q, "limitToLast", ref.limitToLast)
	}

	return nil
}

func (ref *Reference) url() (*url.URL, error) {
	u, err := url.Parse(ref.database.app.databaseURL + "/" + ref.path + ".json")
	if err != nil {
		return nil, err
	}
	q := u.Query()
	err = ref.buildQuery(q)
	if err != nil {
		return nil, err
	}

	u.RawQuery = q.Encode()
	return u, nil
}

func (ref *Reference) invokeRequest(method string, body io.Reader) ([]byte, error) {
	url, err := ref.url()
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest(method, url.String(), body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	resp, err := ref.database.app.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusOK {
		var e struct {
			Error string `json:"error"`
		}
		err = json.Unmarshal(b, &e)
		if err != nil {
			e.Error = resp.Status
		}
		return nil, fmt.Errorf("firebasedatabase: %s", e.Error)
	}
	return bytes.TrimSpace(b), nil
}

// Set writes data to current location
func (ref *Reference) Set(value interface{}) error {
	buf := bytes.NewBuffer([]byte{})
	err := json.NewEncoder(buf).Encode(value)
	if err != nil {
		return err
	}
	_, err = ref.invokeRequest(http.MethodPut, buf)
	if err != nil {
		return err
	}
	return nil
}

// Push pushs data to current location
func (ref Reference) Push(value interface{}) (*Reference, error) {
	buf := bytes.NewBuffer([]byte{})
	err := json.NewEncoder(buf).Encode(value)
	if err != nil {
		return nil, err
	}
	b, err := ref.invokeRequest(http.MethodPost, buf)
	if err != nil {
		return nil, err
	}

	var r struct {
		Name string `json:"name"`
	}
	err = json.Unmarshal(b, &r)
	if err != nil {
		return nil, err
	}

	nRef := ref
	nRef.path = _path.Join(ref.path, r.Name)

	return &nRef, nil
}

// Remove removes data from current location
func (ref *Reference) Remove() error {
	_, err := ref.invokeRequest(http.MethodDelete, nil)
	if err != nil {
		return err
	}
	return nil
}

// Key returns the last path of Reference
func (ref *Reference) Key() string {
	_, p := _path.Split(ref.path)
	return p
}

// Ref returns a copy
func (ref Reference) Ref() *Reference {
	return &ref
}

// Root returns the root location of database
func (ref *Reference) Root() *Reference {
	return &Reference{
		database: ref.database,
	}
}

// Child returns a Reference for relative path
func (ref Reference) Child(path string) *Reference {
	ref.path = _path.Join(ref.path, path)
	return &ref
}

// Parent returns the parent location of Reference
func (ref Reference) Parent() *Reference {
	ref.path, _ = _path.Split(ref.path)
	return &ref
}

// EndAt implements Query interface
func (ref Reference) EndAt(value interface{}) Query {
	ref.endAt = value
	return &ref
}

// StartAt implements Query interface
func (ref Reference) StartAt(value interface{}) Query {
	ref.startAt = value
	return &ref
}

// EqualTo implements Query interface
func (ref Reference) EqualTo(value interface{}) Query {
	ref.equalTo = value
	return &ref
}

// IsEqual returns true if current and provided query is the same location,
// same query params, and same App instance
func (ref *Reference) IsEqual(other Query) bool {
	r := other.Ref()

	// check app instance
	if ref.database.app != r.database.app {
		return false
	}

	// check location
	if ref.path != r.path {
		return false
	}

	// check queries
	q1, q2 := url.Values{}, url.Values{}
	ref.buildQuery(q1)
	r.buildQuery(q2)
	if len(q1) != len(q2) || q1.Encode() != q2.Encode() {
		return false
	}

	return true
}

// LimitToFirst implements Query interface
func (ref Reference) LimitToFirst(limit int) Query {
	ref.limitToFirst = limit
	return &ref
}

// LimitToLast implements Query interface
func (ref Reference) LimitToLast(limit int) Query {
	ref.limitToLast = limit
	return &ref
}

// OrderByChild implements Query interface
func (ref Reference) OrderByChild(path interface{}) Query {
	ref.orderBy = path
	return &ref
}

// OrderByKey implements Query interface
func (ref Reference) OrderByKey() Query {
	ref.orderBy = "$key"
	return &ref
}

// OrderByPriority implements Query interface
func (ref Reference) OrderByPriority() Query {
	ref.orderBy = "$priority"
	return &ref
}

// OrderByValue implements Query interface
func (ref Reference) OrderByValue() Query {
	ref.orderBy = "$value"
	return &ref
}

// OnValue implements Query interface
func (ref *Reference) OnValue(event chan *DataSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnChildAdded implements Query interface
func (ref *Reference) OnChildAdded(event chan *ChildSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnChildRemoved implements Query interface
func (ref *Reference) OnChildRemoved(event chan *OldChildSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnChildChanged implements Query interface
func (ref *Reference) OnChildChanged(event chan *ChildSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnChildMoved implements Query interface
func (ref *Reference) OnChildMoved(event chan *ChildSnapshot) CancelFunc {
	panic(ErrNotImplemented)
}

// OnceValue implements Query interface
func (ref *Reference) OnceValue() (*DataSnapshot, error) {
	// TODO: find from cached first
	b, err := ref.invokeRequest(http.MethodGet, nil)
	if err != nil {
		return nil, err
	}
	return &DataSnapshot{
		ref: ref,
		raw: b,
	}, nil
}

// OnceChildAdded implements Query interface
func (ref *Reference) OnceChildAdded() *ChildSnapshot {
	panic(ErrNotImplemented)
}

// OnceChildRemove implements Query interface
func (ref *Reference) OnceChildRemove() *OldChildSnapshot {
	panic(ErrNotImplemented)
}

// OnceChildChanged implements Query interface
func (ref *Reference) OnceChildChanged() *ChildSnapshot {
	panic(ErrNotImplemented)
}

// OnceChildMoved implements Query interface
func (ref *Reference) OnceChildMoved() *ChildSnapshot {
	panic(ErrNotImplemented)
}

// String returns absolute URL for this location
func (ref *Reference) String() string {
	u, err := ref.url()
	if err != nil {
		return ""
	}
	q := u.Query()
	q.Del("access_token")
	u.RawQuery = q.Encode()
	return u.String()
}
<|endoftext|>


<commit_before>package nms

import (
	"fmt"
	"net"
	"time"

	"github.com/k-sone/snmpgo"

	"github.com/mehrdadrad/mylg/cli"
)

var (
	OID = map[string]string{
		"sysDescr":             "1.3.6.1.2.1.1.1.0",
		"ifDescr":              "1.3.6.1.2.1.2.2.1.2",
		"ifHCInOctets":         "1.3.6.1.2.1.31.1.1.1.6",
		"ifHCInUcastPkts":      "1.3.6.1.2.1.31.1.1.1.7",
		"ifHCOutOctets":        "1.3.6.1.2.1.31.1.1.1.10",
		"ifHCOutUcastPkts":     "1.3.6.1.2.1.31.1.1.1.11",
		"ifHCInMulticastPkts":  "1.3.6.1.2.1.31.1.1.1.8",
		"ifHCOutMulticastPkts": "1.3.6.1.2.1.31.1.1.1.12",
		"ifHCInBroadcastPkts":  "1.3.6.1.2.1.31.1.1.1.9",
		"ifHCOutBroadcastPkts": "1.3.6.1.2.1.31.1.1.1.13",
		"ifInDiscards":         "1.3.6.1.2.1.2.2.1.13",
		"ifInErrors":           "1.3.6.1.2.1.2.2.1.14",
		"ifOutDiscards":        "1.3.6.1.2.1.2.2.1.19",
		"ifOutErrors":          "1.3.6.1.2.1.2.2.1.20",
	} // OID holds essentiall OIDs that need for each interface
)

// SNMPClient represents all necessary SNMP parameters
type SNMPClient struct {
	Args     snmpgo.SNMPArguments
	Host     string
	SysDescr string
}

// NewSNMP sets and validates SNMP parameters
func NewSNMP(a string, cfg cli.Config) (*SNMPClient, error) {
	var (
		host, flag = cli.Flag(a)
		community  = cli.SetFlag(flag, "c", cfg.Snmp.Community).(string)
		timeout    = cli.SetFlag(flag, "t", cfg.Snmp.Timeout).(string)
		retries    = cli.SetFlag(flag, "r", cfg.Snmp.Retries).(int)
		port       = cli.SetFlag(flag, "p", cfg.Snmp.Port).(int)
	)

	tDuration, err := time.ParseDuration(timeout)
	if err != nil {
		return &SNMPClient{}, err
	}

	args := snmpgo.SNMPArguments{
		Version:   snmpgo.V2c,
		Timeout:   tDuration,
		Address:   net.JoinHostPort(host, fmt.Sprintf("%d", port)),
		Retries:   uint(retries),
		Community: community,
	}

	if err := chkVersion(flag, &args); err != nil {
		return &SNMPClient{}, err
	}

	if args.Version == snmpgo.V3 {
		checkAuth()
	}

	return &SNMPClient{
		Args:     args,
		Host:     host,
		SysDescr: "",
	}, nil
}

func chkVersion(flags map[string]interface{}, args *snmpgo.SNMPArguments) error {
	if v, ok := flags["v"]; ok {
		switch v.(type) {
		case int:
			if v == 1 {
				args.Version = snmpgo.V1
			} else if v == 3 {
				args.Version = snmpgo.V3
			} else {
				return fmt.Errorf("wrong snmp version")
			}
		}
	}
	return nil
}

func checkAuth() {
	//TODO
}

// BulkWalk retrieves a subtree of management values
func (c *SNMPClient) BulkWalk(oid ...string) ([]*snmpgo.VarBind, error) {
	var r []*snmpgo.VarBind
	snmp, err := snmpgo.NewSNMP(c.Args)
	if err != nil {
		return r, err
	}

	oids, err := snmpgo.NewOids(oid)
	if err != nil {
		return r, err
	}

	if err = snmp.Open(); err != nil {
		return r, err
	}
	defer snmp.Close()
	pdu, err := snmp.GetBulkWalk(oids, 0, 100)
	if err != nil {
		return r, err
	}
	r = pdu.VarBinds()
	return r, nil
}

// GetOIDs retrieves values based on the oid(s)
func (c *SNMPClient) GetOIDs(oid ...string) ([]*snmpgo.VarBind, error) {
	var r []*snmpgo.VarBind
	snmp, err := snmpgo.NewSNMP(c.Args)
	if err != nil {
		return r, err
	}

	oids, err := snmpgo.NewOids(oid)
	if err != nil {
		return r, err
	}

	if err = snmp.Open(); err != nil {
		return r, err
	}
	defer snmp.Close()

	pdu, err := snmp.GetRequest(oids)
	if err != nil {
		return r, err
	}
	r = pdu.VarBinds()

	return r, nil
}
<commit_msg>add version option<commit_after>package nms

import (
	"fmt"
	"net"
	"time"

	"github.com/k-sone/snmpgo"

	"github.com/mehrdadrad/mylg/cli"
)

var (
	OID = map[string]string{
		"sysDescr":             "1.3.6.1.2.1.1.1.0",
		"ifDescr":              "1.3.6.1.2.1.2.2.1.2",
		"ifHCInOctets":         "1.3.6.1.2.1.31.1.1.1.6",
		"ifHCInUcastPkts":      "1.3.6.1.2.1.31.1.1.1.7",
		"ifHCOutOctets":        "1.3.6.1.2.1.31.1.1.1.10",
		"ifHCOutUcastPkts":     "1.3.6.1.2.1.31.1.1.1.11",
		"ifHCInMulticastPkts":  "1.3.6.1.2.1.31.1.1.1.8",
		"ifHCOutMulticastPkts": "1.3.6.1.2.1.31.1.1.1.12",
		"ifHCInBroadcastPkts":  "1.3.6.1.2.1.31.1.1.1.9",
		"ifHCOutBroadcastPkts": "1.3.6.1.2.1.31.1.1.1.13",
		"ifInDiscards":         "1.3.6.1.2.1.2.2.1.13",
		"ifInErrors":           "1.3.6.1.2.1.2.2.1.14",
		"ifOutDiscards":        "1.3.6.1.2.1.2.2.1.19",
		"ifOutErrors":          "1.3.6.1.2.1.2.2.1.20",
	} // OID holds essentiall OIDs that need for each interface
)

// SNMPClient represents all necessary SNMP parameters
type SNMPClient struct {
	Args     snmpgo.SNMPArguments
	Host     string
	SysDescr string
}

// NewSNMP sets and validates SNMP parameters
func NewSNMP(a string, cfg cli.Config) (*SNMPClient, error) {
	var (
		host, flag = cli.Flag(a)
		community  = cli.SetFlag(flag, "c", cfg.Snmp.Community).(string)
		timeout    = cli.SetFlag(flag, "t", cfg.Snmp.Timeout).(string)
		version    = cli.SetFlag(flag, "v", cfg.Snmp.Version).(string)
		retries    = cli.SetFlag(flag, "r", cfg.Snmp.Retries).(int)
		port       = cli.SetFlag(flag, "p", cfg.Snmp.Port).(int)
	)

	tDuration, err := time.ParseDuration(timeout)
	if err != nil {
		return &SNMPClient{}, err
	}

	args := snmpgo.SNMPArguments{
		Timeout:   tDuration,
		Address:   net.JoinHostPort(host, fmt.Sprintf("%d", port)),
		Retries:   uint(retries),
		Community: community,
	}

	// set SNMP version
	switch version {
	case "1":
		args.Version = snmpgo.V1
	case "2", "2c":
		args.Version = snmpgo.V2c
	case "3":
		args.Version = snmpgo.V3
	default:
		return &SNMPClient{}, fmt.Errorf("wrong version")
	}

	if args.Version == snmpgo.V3 {
		checkAuth()
	}

	return &SNMPClient{
		Args:     args,
		Host:     host,
		SysDescr: "",
	}, nil
}

func checkAuth() {
	//TODO
}

// BulkWalk retrieves a subtree of management values
func (c *SNMPClient) BulkWalk(oid ...string) ([]*snmpgo.VarBind, error) {
	var r []*snmpgo.VarBind
	snmp, err := snmpgo.NewSNMP(c.Args)
	if err != nil {
		return r, err
	}

	oids, err := snmpgo.NewOids(oid)
	if err != nil {
		return r, err
	}

	if err = snmp.Open(); err != nil {
		return r, err
	}
	defer snmp.Close()
	pdu, err := snmp.GetBulkWalk(oids, 0, 100)
	if err != nil {
		return r, err
	}
	r = pdu.VarBinds()
	return r, nil
}

// GetOIDs retrieves values based on the oid(s)
func (c *SNMPClient) GetOIDs(oid ...string) ([]*snmpgo.VarBind, error) {
	var r []*snmpgo.VarBind
	snmp, err := snmpgo.NewSNMP(c.Args)
	if err != nil {
		return r, err
	}

	oids, err := snmpgo.NewOids(oid)
	if err != nil {
		return r, err
	}

	if err = snmp.Open(); err != nil {
		return r, err
	}
	defer snmp.Close()

	pdu, err := snmp.GetRequest(oids)
	if err != nil {
		return r, err
	}
	r = pdu.VarBinds()

	return r, nil
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/api/response"
	"github.com/grafana/metrictank/cluster"
	"github.com/grafana/metrictank/conf"
	"github.com/grafana/metrictank/idx/memory"
	"github.com/grafana/metrictank/mdata"
	"github.com/grafana/metrictank/mdata/cache"
	"gopkg.in/raintank/schema.v1"
)

func newSrv(delSeries, delArchives int, key string) (*Server, *cache.MockCache) {
	srv, _ := NewServer()
	srv.RegisterRoutes()

	mdata.SetSingleAgg(conf.Avg, conf.Min, conf.Max)
	mdata.SetSingleSchema(conf.NewRetentionMT(10, 100, 600, 10, true))

	store := mdata.NewDevnullStore()
	srv.BindBackendStore(store)

	mockCache := cache.NewMockCache()
	mockCache.DelMetricSeries = delSeries
	mockCache.DelMetricArchives = delArchives
	metrics := mdata.NewAggMetrics(store, mockCache, false, 0, 0, 0)
	srv.BindMemoryStore(metrics)
	srv.BindCache(mockCache)

	metricIndex := memory.New()
	metricIndex.AddOrUpdate(
		&schema.MetricData{
			Id:       key,
			OrgId:    1,
			Name:     "test.key",
			Metric:   "test.key",
			Interval: 10,
			Value:    1,
		},
		0,
	)
	srv.BindMetricIndex(metricIndex)
	return srv, mockCache
}

func TestMetricDelete(t *testing.T) {
	cluster.Init("default", "test", time.Now(), "http", 6060)

	delSeries := 3
	delArchives := 10
	testKey := "12345"

	srv, cache := newSrv(delSeries, delArchives, testKey)
	req, _ := json.Marshal(models.CCacheDelete{
		Patterns:  []string{"test.*"},
		OrgId:     1,
		Propagate: false,
	})

	ts := httptest.NewServer(srv.Macaron)
	defer ts.Close()

	res, err := http.Post(ts.URL+"/ccache/delete", "application/json", bytes.NewReader(req))
	if err != nil {
		t.Fatalf("There was an error in the request: %s", err)
	}

	respParsed := models.CCacheDeleteResp{}
	buf := new(bytes.Buffer)
	buf.ReadFrom(res.Body)
	json.Unmarshal(buf.Bytes(), &respParsed)

	if len(cache.DelMetricKeys) != 1 || cache.DelMetricKeys[0] != testKey {
		t.Fatalf("Expected that key %s has been deleted, but it has not", testKey)
	}

	if respParsed.DeletedSeries != delSeries || respParsed.DeletedArchives != delArchives {
		t.Fatalf("Expected %d series and %d archives to get deleted, but got %d and %d", delSeries, delArchives, respParsed.DeletedSeries, respParsed.DeletedArchives)
	}
}

func TestMetricDeleteWithErrorInPropagation(t *testing.T) {
	manager := cluster.InitMock()

	// define how many series/archives are getting deleted by peer 0
	resp := models.CCacheDeleteResp{
		Peers:           map[string]models.CCacheDeleteResp{"2": {Errors: 1}},
		DeletedSeries:   1,
		DeletedArchives: 1,
		Errors:          1,
	}

	respEncoded := response.NewJson(500, resp, "")
	buf, _ := respEncoded.Body()
	manager.Peers = append(manager.Peers, cluster.NewMockNode(false, "0", buf))

	// define how many series/archives are going to get deleted by this server
	delSeries := 3
	delArchives := 10
	testKey := "12345"

	srv, _ := newSrv(delSeries, delArchives, testKey)
	req, err := json.Marshal(models.CCacheDelete{
		Patterns:  []string{"test.*"},
		OrgId:     1,
		Propagate: true,
	})
	if err != nil {
		t.Fatalf("Unexpected error when marshaling json: %s", err)
	}

	ts := httptest.NewServer(srv.Macaron)
	defer ts.Close()

	res, err := http.Post(ts.URL+"/ccache/delete", "application/json", bytes.NewReader(req))
	if err != nil {
		t.Fatalf("There was an error in the request: %s", err)
	}

	expectedCode := 500
	if res.StatusCode != expectedCode {
		buf2 := new(bytes.Buffer)
		buf2.ReadFrom(res.Body)
		respParsed := models.CCacheDeleteResp{}
		json.Unmarshal(buf2.Bytes(), &respParsed)
		t.Fatalf("Expected status code %d, but got %d:\n%+v", expectedCode, res.StatusCode, respParsed)
	}
}

func TestMetricDeletePropagation(t *testing.T) {
	manager := cluster.InitMock()

	expectedDeletedSeries, expectedDeletedArchives := 0, 0

	// define how many series/archives are getting deleted by peer 0
	resp := models.CCacheDeleteResp{
		DeletedSeries:   2,
		DeletedArchives: 5,
	}
	expectedDeletedSeries += resp.DeletedSeries
	expectedDeletedArchives += resp.DeletedArchives
	respEncoded := response.NewJson(200, resp, "")
	buf, _ := respEncoded.Body()
	manager.Peers = append(manager.Peers, cluster.NewMockNode(false, "1", buf))

	// define how many series/archives are getting deleted by peer 1
	resp = models.CCacheDeleteResp{
		Peers:           map[string]models.CCacheDeleteResp{"2": {Errors: 1}},
		DeletedSeries:   1,
		DeletedArchives: 1,
	}

	respEncoded = response.NewJson(200, resp, "")
	buf, _ = respEncoded.Body()
	// should be ignored because peer.IsLocal() is true
	manager.Peers = append(manager.Peers, cluster.NewMockNode(true, "2", buf))

	// define how many series/archives are getting deleted by peer 2
	resp = models.CCacheDeleteResp{
		Peers:           map[string]models.CCacheDeleteResp{"3": {Errors: 1}},
		DeletedSeries:   1,
		DeletedArchives: 3,
	}
	expectedDeletedSeries += resp.DeletedSeries
	expectedDeletedArchives += resp.DeletedArchives
	respEncoded = response.NewJson(200, resp, "")
	buf, _ = respEncoded.Body()
	manager.Peers = append(manager.Peers, cluster.NewMockNode(false, "3", buf))

	// define how many series/archives are going to get deleted by this server
	delSeries := 3
	delArchives := 10
	testKey := "12345"

	// add up how many series/archives are expected to be deleted
	expectedDeletedSeries += delSeries
	expectedDeletedArchives += delArchives

	srv, cache := newSrv(delSeries, delArchives, testKey)
	req, err := json.Marshal(models.CCacheDelete{
		Patterns:  []string{"test.*"},
		OrgId:     1,
		Propagate: true,
	})
	if err != nil {
		t.Fatalf("Unexpected error when marshaling json: %s", err)
	}

	ts := httptest.NewServer(srv.Macaron)
	defer ts.Close()

	res, err := http.Post(ts.URL+"/ccache/delete", "application/json", bytes.NewReader(req))
	if err != nil {
		t.Fatalf("There was an error in the request: %s", err)
	}

	buf2 := new(bytes.Buffer)
	buf2.ReadFrom(res.Body)
	respParsed := models.CCacheDeleteResp{}
	json.Unmarshal(buf2.Bytes(), &respParsed)

	if len(cache.DelMetricKeys) != 1 || cache.DelMetricKeys[0] != testKey {
		t.Fatalf("Expected that key %s has been deleted, but it has not", testKey)
	}

	deletedArchives := respParsed.DeletedArchives
	deletedSeries := respParsed.DeletedSeries
	for _, peer := range respParsed.Peers {
		deletedArchives += peer.DeletedArchives
		deletedSeries += peer.DeletedSeries
	}

	if deletedSeries != expectedDeletedSeries || deletedArchives != expectedDeletedArchives {
		t.Fatalf(
			"Expected %d series and %d archives to get deleted, but got %d and %d",
			expectedDeletedSeries, expectedDeletedArchives, respParsed.DeletedSeries, respParsed.DeletedArchives,
		)
	}
}
<commit_msg>improve tests<commit_after>package api

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/api/response"
	"github.com/grafana/metrictank/cluster"
	"github.com/grafana/metrictank/conf"
	"github.com/grafana/metrictank/idx/memory"
	"github.com/grafana/metrictank/mdata"
	"github.com/grafana/metrictank/mdata/cache"
	"gopkg.in/raintank/schema.v1"
)

func newSrv(delSeries, delArchives int, key string) (*Server, *cache.MockCache) {
	srv, _ := NewServer()
	srv.RegisterRoutes()

	mdata.SetSingleAgg(conf.Avg, conf.Min, conf.Max)
	mdata.SetSingleSchema(conf.NewRetentionMT(10, 100, 600, 10, true))

	store := mdata.NewDevnullStore()
	srv.BindBackendStore(store)

	mockCache := cache.NewMockCache()
	mockCache.DelMetricSeries = delSeries
	mockCache.DelMetricArchives = delArchives
	metrics := mdata.NewAggMetrics(store, mockCache, false, 0, 0, 0)
	srv.BindMemoryStore(metrics)
	srv.BindCache(mockCache)

	metricIndex := memory.New()
	metricIndex.AddOrUpdate(
		&schema.MetricData{
			Id:       key,
			OrgId:    1,
			Name:     "test.key",
			Metric:   "test.key",
			Interval: 10,
			Value:    1,
		},
		0,
	)
	srv.BindMetricIndex(metricIndex)
	return srv, mockCache
}

func TestMetricDelete(t *testing.T) {
	cluster.Init("default", "test", time.Now(), "http", 6060)

	delSeries := 3
	delArchives := 10
	testKey := "12345"

	srv, cache := newSrv(delSeries, delArchives, testKey)
	req, _ := json.Marshal(models.CCacheDelete{
		Patterns:  []string{"test.*"},
		OrgId:     1,
		Propagate: false,
	})

	ts := httptest.NewServer(srv.Macaron)
	defer ts.Close()

	res, err := http.Post(ts.URL+"/ccache/delete", "application/json", bytes.NewReader(req))
	if err != nil {
		t.Fatalf("There was an error in the request: %s", err)
	}

	respParsed := models.CCacheDeleteResp{}
	buf := new(bytes.Buffer)
	buf.ReadFrom(res.Body)
	json.Unmarshal(buf.Bytes(), &respParsed)

	if len(cache.DelMetricKeys) != 1 || cache.DelMetricKeys[0] != testKey {
		t.Fatalf("Expected that key %s has been deleted, but it has not", testKey)
	}

	if respParsed.DeletedSeries != delSeries || respParsed.DeletedArchives != delArchives {
		t.Fatalf("Expected %d series and %d archives to get deleted, but got %d and %d", delSeries, delArchives, respParsed.DeletedSeries, respParsed.DeletedArchives)
	}
}

func TestMetricDeleteWithErrorInPropagation(t *testing.T) {
	manager := cluster.InitMock()

	// define how many series/archives are getting deleted by peer 0
	resp := models.CCacheDeleteResp{
		DeletedSeries:   1,
		DeletedArchives: 1,
		Errors:          1,
	}

	respEncoded := response.NewJson(500, resp, "")
	buf, _ := respEncoded.Body()
	manager.Peers = append(manager.Peers, cluster.NewMockNode(false, "0", buf))

	// define how many series/archives are going to get deleted by this server
	delSeries := 3
	delArchives := 10
	testKey := "12345"

	srv, _ := newSrv(delSeries, delArchives, testKey)
	req, err := json.Marshal(models.CCacheDelete{
		Patterns:  []string{"test.*"},
		OrgId:     1,
		Propagate: true,
	})
	if err != nil {
		t.Fatalf("Unexpected error when marshaling json: %s", err)
	}

	ts := httptest.NewServer(srv.Macaron)
	defer ts.Close()

	res, err := http.Post(ts.URL+"/ccache/delete", "application/json", bytes.NewReader(req))
	if err != nil {
		t.Fatalf("There was an error in the request: %s", err)
	}

	expectedCode := 500
	if res.StatusCode != expectedCode {
		buf2 := new(bytes.Buffer)
		buf2.ReadFrom(res.Body)
		respParsed := models.CCacheDeleteResp{}
		json.Unmarshal(buf2.Bytes(), &respParsed)
		t.Fatalf("Expected status code %d, but got %d:\n%+v", expectedCode, res.StatusCode, respParsed)
	}
}

func TestMetricDeletePropagation(t *testing.T) {
	manager := cluster.InitMock()

	expectedDeletedSeries, expectedDeletedArchives := 0, 0
	for _, peer := range []string{"Peer1", "Peer2", "Peer3"} {
		// define how many series/archives are getting deleted by this peer
		resp := models.CCacheDeleteResp{
			DeletedSeries:   2,
			DeletedArchives: 5,
		}
		expectedDeletedSeries += resp.DeletedSeries
		expectedDeletedArchives += resp.DeletedArchives
		respEncoded := response.NewJson(200, resp, "")
		buf, _ := respEncoded.Body()
		manager.Peers = append(manager.Peers, cluster.NewMockNode(false, peer, buf))
	}

	// define how many series/archives are going to get deleted by this server
	delSeries := 3
	delArchives := 10
	testKey := "12345"

	// add up how many series/archives are expected to be deleted
	expectedDeletedSeries += delSeries
	expectedDeletedArchives += delArchives

	srv, cache := newSrv(delSeries, delArchives, testKey)
	req, err := json.Marshal(models.CCacheDelete{
		Patterns:  []string{"test.*"},
		OrgId:     1,
		Propagate: true,
	})
	if err != nil {
		t.Fatalf("Unexpected error when marshaling json: %s", err)
	}

	ts := httptest.NewServer(srv.Macaron)
	defer ts.Close()

	res, err := http.Post(ts.URL+"/ccache/delete", "application/json", bytes.NewReader(req))
	if err != nil {
		t.Fatalf("There was an error in the request: %s", err)
	}

	buf2 := new(bytes.Buffer)
	buf2.ReadFrom(res.Body)
	respParsed := models.CCacheDeleteResp{}
	json.Unmarshal(buf2.Bytes(), &respParsed)

	if len(cache.DelMetricKeys) != 1 || cache.DelMetricKeys[0] != testKey {
		t.Fatalf("Expected that key %s has been deleted, but it has not", testKey)
	}

	deletedArchives := respParsed.DeletedArchives
	deletedSeries := respParsed.DeletedSeries
	for _, peer := range respParsed.Peers {
		deletedArchives += peer.DeletedArchives
		deletedSeries += peer.DeletedSeries
	}

	if deletedSeries != expectedDeletedSeries || deletedArchives != expectedDeletedArchives {
		t.Fatalf(
			"Expected %d series and %d archives to get deleted, but got %d and %d",
			expectedDeletedSeries, expectedDeletedArchives, respParsed.DeletedSeries, respParsed.DeletedArchives,
		)
	}
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/NebulousLabs/Sia/build"
)

type updateHandler struct {
	version string
}

func (uh *updateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.URL.String() {
	case "/current/MANIFEST":
		fmt.Fprintf(w, "%s\nsiad\n", uh.version)
	case "/current/siad":
		fmt.Fprint(w, "yep this is siad")
	case "/current/siad.sig":
		fmt.Fprint(w, "and this is totally a signature")
	default:
		http.NotFound(w, r)
	}
}

// TestUpdate checks that updates work properly.
func TestSignedUpdate(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	st, err := createServerTester("TestSignedUpdate")
	if err != nil {
		t.Fatal(err)
	}

	// to test the update process, we need to spoof the update server
	uh := new(updateHandler)
	http.Handle("/", uh)
	go http.ListenAndServe(":8080", nil)
	updateURL = "http://localhost:8080"

	// same version
	uh.version = build.Version
	var info UpdateInfo
	st.getAPI("/daemon/updates/check", &info)
	if info.Available {
		t.Error("new version should not be available")
	}

	// newer version
	uh.version = "100.0"
	err = st.getAPI("/daemon/updates/check", &info)
	if err != nil {
		t.Error(err)
	} else if !info.Available {
		t.Error("new version should be available")
	}

	// apply (bad signature)
	resp, err := HttpGET("http://" + st.server.listener.Addr().String() + "/daemon/updates/apply?version=current")
	if err != nil {
		t.Fatal("GET failed:", err)
	}
	if resp.StatusCode != http.StatusInternalServerError {
		t.Error("expected internal server error, got", resp.StatusCode)
	}
}

func TestVersion(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	st, err := createServerTester("TestSignedUpdate")
	if err != nil {
		t.Fatal(err)
	}
	var version string
	st.getAPI("/daemon/version", &version)
	if version != build.Version {
		t.Fatalf("/daemon/version reporting bad version: expected %v, got %v", build.Version, version)
	}
}
<commit_msg>serve test update on random open port<commit_after>package api

import (
	"fmt"
	"net"
	"net/http"
	"testing"

	"github.com/NebulousLabs/Sia/build"
)

type updateHandler struct {
	version string
}

func (uh *updateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.URL.String() {
	case "/current/MANIFEST":
		fmt.Fprintf(w, "%s\nsiad\n", uh.version)
	case "/current/siad":
		fmt.Fprint(w, "yep this is siad")
	case "/current/siad.sig":
		fmt.Fprint(w, "and this is totally a signature")
	default:
		http.NotFound(w, r)
	}
}

// TestUpdate checks that updates work properly.
func TestSignedUpdate(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	st, err := createServerTester("TestSignedUpdate")
	if err != nil {
		t.Fatal(err)
	}

	// to test the update process, we need to spoof the update server
	uh := new(updateHandler)
	http.Handle("/", uh)
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		t.Fatal(err)
	}
	go http.Serve(l, nil)
	updateURL = "http://" + l.Addr().String()

	// same version
	uh.version = build.Version
	var info UpdateInfo
	st.getAPI("/daemon/updates/check", &info)
	if info.Available {
		t.Error("new version should not be available")
	}

	// newer version
	uh.version = "100.0"
	err = st.getAPI("/daemon/updates/check", &info)
	if err != nil {
		t.Error(err)
	} else if !info.Available {
		t.Error("new version should be available")
	}

	// apply (bad signature)
	resp, err := HttpGET("http://" + st.server.listener.Addr().String() + "/daemon/updates/apply?version=current")
	if err != nil {
		t.Fatal("GET failed:", err)
	}
	if resp.StatusCode != http.StatusInternalServerError {
		t.Error("expected internal server error, got", resp.StatusCode)
	}
}

func TestVersion(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	st, err := createServerTester("TestSignedUpdate")
	if err != nil {
		t.Fatal(err)
	}
	var version string
	st.getAPI("/daemon/version", &version)
	if version != build.Version {
		t.Fatalf("/daemon/version reporting bad version: expected %v, got %v", build.Version, version)
	}
}
<|endoftext|>


<commit_before>package engine

import (
	"fmt"
	"github.com/dotcloud/docker/utils"
	"io"
	"log"
	"os"
	"runtime"
	"strings"
)

type Handler func(*Job) Status

var globalHandlers map[string]Handler

func init() {
	globalHandlers = make(map[string]Handler)
}

func Register(name string, handler Handler) error {
	_, exists := globalHandlers[name]
	if exists {
		return fmt.Errorf("Can't overwrite global handler for command %s", name)
	}
	globalHandlers[name] = handler
	return nil
}

// The Engine is the core of Docker.
// It acts as a store for *containers*, and allows manipulation of these
// containers by executing *jobs*.
type Engine struct {
	root     string
	handlers map[string]Handler
	hack     Hack // data for temporary hackery (see hack.go)
	id       string
	Stdout   io.Writer
	Stderr   io.Writer
	Stdin    io.Reader
}

func (eng *Engine) Root() string {
	return eng.root
}

func (eng *Engine) Register(name string, handler Handler) error {
	eng.Logf("Register(%s) (handlers=%v)", name, eng.handlers)
	_, exists := eng.handlers[name]
	if exists {
		return fmt.Errorf("Can't overwrite handler for command %s", name)
	}
	eng.handlers[name] = handler
	return nil
}

// New initializes a new engine managing the directory specified at `root`.
// `root` is used to store containers and any other state private to the engine.
// Changing the contents of the root without executing a job will cause unspecified
// behavior.
func New(root string) (*Engine, error) {
	// Check for unsupported architectures
	if runtime.GOARCH != "amd64" {
		return nil, fmt.Errorf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
	}
	// Check for unsupported kernel versions
	// FIXME: it would be cleaner to not test for specific versions, but rather
	// test for specific functionalities.
	// Unfortunately we can't test for the feature "does not cause a kernel panic"
	// without actually causing a kernel panic, so we need this workaround until
	// the circumstances of pre-3.8 crashes are clearer.
	// For details see http://github.com/dotcloud/docker/issues/407
	if k, err := utils.GetKernelVersion(); err != nil {
		log.Printf("WARNING: %s\n", err)
	} else {
		if utils.CompareKernelVersion(k, &utils.KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
			if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
				log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
			}
		}
	}
	if err := os.MkdirAll(root, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}
	eng := &Engine{
		root:     root,
		handlers: make(map[string]Handler),
		id:       utils.RandomString(),
		Stdout:   os.Stdout,
		Stderr:   os.Stderr,
		Stdin:    os.Stdin,
	}
	// Copy existing global handlers
	for k, v := range globalHandlers {
		eng.handlers[k] = v
	}
	return eng, nil
}

func (eng *Engine) String() string {
	return fmt.Sprintf("%s|%s", eng.Root(), eng.id[:8])
}

// Job creates a new job which can later be executed.
// This function mimics `Command` from the standard os/exec package.
func (eng *Engine) Job(name string, args ...string) *Job {
	job := &Job{
		Eng:    eng,
		Name:   name,
		Args:   args,
		Stdin:  NewInput(),
		Stdout: NewOutput(),
		Stderr: NewOutput(),
	}
	job.Stdout.Add(utils.NopWriteCloser(eng.Stdout))
	job.Stderr.Add(utils.NopWriteCloser(eng.Stderr))
	handler, exists := eng.handlers[name]
	if exists {
		job.handler = handler
	}
	return job
}

func (eng *Engine) Logf(format string, args ...interface{}) (n int, err error) {
	prefixedFormat := fmt.Sprintf("[%s] %s\n", eng, strings.TrimRight(format, "\n"))
	return fmt.Fprintf(eng.Stderr, prefixedFormat, args...)
}
<commit_msg>Engine: don't log job stdout to engine stdout (it might be non-text output, for example tar data for 'export'<commit_after>package engine

import (
	"fmt"
	"github.com/dotcloud/docker/utils"
	"io"
	"log"
	"os"
	"runtime"
	"strings"
)

type Handler func(*Job) Status

var globalHandlers map[string]Handler

func init() {
	globalHandlers = make(map[string]Handler)
}

func Register(name string, handler Handler) error {
	_, exists := globalHandlers[name]
	if exists {
		return fmt.Errorf("Can't overwrite global handler for command %s", name)
	}
	globalHandlers[name] = handler
	return nil
}

// The Engine is the core of Docker.
// It acts as a store for *containers*, and allows manipulation of these
// containers by executing *jobs*.
type Engine struct {
	root     string
	handlers map[string]Handler
	hack     Hack // data for temporary hackery (see hack.go)
	id       string
	Stdout   io.Writer
	Stderr   io.Writer
	Stdin    io.Reader
}

func (eng *Engine) Root() string {
	return eng.root
}

func (eng *Engine) Register(name string, handler Handler) error {
	eng.Logf("Register(%s) (handlers=%v)", name, eng.handlers)
	_, exists := eng.handlers[name]
	if exists {
		return fmt.Errorf("Can't overwrite handler for command %s", name)
	}
	eng.handlers[name] = handler
	return nil
}

// New initializes a new engine managing the directory specified at `root`.
// `root` is used to store containers and any other state private to the engine.
// Changing the contents of the root without executing a job will cause unspecified
// behavior.
func New(root string) (*Engine, error) {
	// Check for unsupported architectures
	if runtime.GOARCH != "amd64" {
		return nil, fmt.Errorf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
	}
	// Check for unsupported kernel versions
	// FIXME: it would be cleaner to not test for specific versions, but rather
	// test for specific functionalities.
	// Unfortunately we can't test for the feature "does not cause a kernel panic"
	// without actually causing a kernel panic, so we need this workaround until
	// the circumstances of pre-3.8 crashes are clearer.
	// For details see http://github.com/dotcloud/docker/issues/407
	if k, err := utils.GetKernelVersion(); err != nil {
		log.Printf("WARNING: %s\n", err)
	} else {
		if utils.CompareKernelVersion(k, &utils.KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
			if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
				log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
			}
		}
	}
	if err := os.MkdirAll(root, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}
	eng := &Engine{
		root:     root,
		handlers: make(map[string]Handler),
		id:       utils.RandomString(),
		Stdout:   os.Stdout,
		Stderr:   os.Stderr,
		Stdin:    os.Stdin,
	}
	// Copy existing global handlers
	for k, v := range globalHandlers {
		eng.handlers[k] = v
	}
	return eng, nil
}

func (eng *Engine) String() string {
	return fmt.Sprintf("%s|%s", eng.Root(), eng.id[:8])
}

// Job creates a new job which can later be executed.
// This function mimics `Command` from the standard os/exec package.
func (eng *Engine) Job(name string, args ...string) *Job {
	job := &Job{
		Eng:    eng,
		Name:   name,
		Args:   args,
		Stdin:  NewInput(),
		Stdout: NewOutput(),
		Stderr: NewOutput(),
	}
	job.Stderr.Add(utils.NopWriteCloser(eng.Stderr))
	handler, exists := eng.handlers[name]
	if exists {
		job.handler = handler
	}
	return job
}

func (eng *Engine) Logf(format string, args ...interface{}) (n int, err error) {
	prefixedFormat := fmt.Sprintf("[%s] %s\n", eng, strings.TrimRight(format, "\n"))
	return fmt.Fprintf(eng.Stderr, prefixedFormat, args...)
}
<|endoftext|>


<commit_before>package engine

import (
	"fmt"
	"os"
	"regexp"
	"sync"
	"syscall"
	"time"

	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	conf "github.com/funkygao/jsconf"
	log "github.com/funkygao/log4go"
)

const (
	RELOAD  = "reload"
	STOP    = "stop"
	SIGUSR1 = "user1"
	SIGUSR2 = "user2"
)

var (
	availablePlugins = make(map[string]func() Plugin) // name:factory
	pluginTypeRegex  = regexp.MustCompile("^.*(Filter|Input|Output)$")

	// Globals returns the global configurations of dbus.
	Globals func() *GlobalConfig
)

// GlobalConfig is the struct for holding global config values.
type GlobalConfig struct {
	*conf.Conf

	StartedAt      time.Time
	Stopping       bool
	Debug          bool
	ClusterEnabled bool
	Zone           string
	RouterTrack    bool

	RPCPort int
	APIPort int

	ZrootConf       string
	ZrootCluster    string
	ZrootCheckpoint string

	InputRecyclePoolSize  int
	FilterRecyclePoolSize int
	HubChanSize           int
	PluginChanSize        int

	WatchdogTick time.Duration

	// registry is used to hold the global object shared between plugins.
	registry map[string]interface{}
	regMu    sync.RWMutex

	sigChan chan os.Signal
}

func (g *GlobalConfig) Shutdown() {
	g.Kill(syscall.SIGINT)
}

func (g *GlobalConfig) Kill(sig os.Signal) {
	g.sigChan <- sig
}

func (g *GlobalConfig) GetOrRegisterZkzone(zone string) *zk.ZkZone {
	g.regMu.Lock()
	defer g.regMu.Unlock()

	key := fmt.Sprintf("zkzone.%s", zone)
	if _, present := g.registry[key]; !present {
		zkzone := zk.NewZkZone(zk.DefaultConfig(zone, ctx.ZoneZkAddrs(zone)))
		g.registry[key] = zkzone
	}

	if z, ok := g.registry[key].(*zk.ZkZone); ok {
		return z
	}

	log.Critical("unknown zone: %s", zone)
	return nil
}

func DefaultGlobals() *GlobalConfig {
	return &GlobalConfig{
		APIPort:               9876,
		RPCPort:               9877,
		Debug:                 false,
		ClusterEnabled:        true,
		InputRecyclePoolSize:  100,
		FilterRecyclePoolSize: 100,
		HubChanSize:           200,
		PluginChanSize:        150,
		RouterTrack:           true,
		WatchdogTick:          time.Minute * 10,
		StartedAt:             time.Now(),
		registry:              map[string]interface{}{},
		ZrootConf:             "/dbus/conf",
		ZrootCheckpoint:       "/dbus/checkpoint",
		ZrootCluster:          "/dbus/cluster",
	}
}
<commit_msg>add comment: global.Zone is only to locate kguard<commit_after>package engine

import (
	"fmt"
	"os"
	"regexp"
	"sync"
	"syscall"
	"time"

	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	conf "github.com/funkygao/jsconf"
	log "github.com/funkygao/log4go"
)

const (
	RELOAD  = "reload"
	STOP    = "stop"
	SIGUSR1 = "user1"
	SIGUSR2 = "user2"
)

var (
	availablePlugins = make(map[string]func() Plugin) // name:factory
	pluginTypeRegex  = regexp.MustCompile("^.*(Filter|Input|Output)$")

	// Globals returns the global configurations of dbus.
	Globals func() *GlobalConfig
)

// GlobalConfig is the struct for holding global config values.
type GlobalConfig struct {
	*conf.Conf

	StartedAt      time.Time
	Stopping       bool
	Debug          bool
	ClusterEnabled bool
	Zone           string // used to locate kguard
	RouterTrack    bool

	RPCPort int
	APIPort int

	ZrootConf       string
	ZrootCluster    string
	ZrootCheckpoint string

	InputRecyclePoolSize  int
	FilterRecyclePoolSize int
	HubChanSize           int
	PluginChanSize        int

	WatchdogTick time.Duration

	// registry is used to hold the global object shared between plugins.
	registry map[string]interface{}
	regMu    sync.RWMutex

	sigChan chan os.Signal
}

func (g *GlobalConfig) Shutdown() {
	g.Kill(syscall.SIGINT)
}

func (g *GlobalConfig) Kill(sig os.Signal) {
	g.sigChan <- sig
}

func (g *GlobalConfig) GetOrRegisterZkzone(zone string) *zk.ZkZone {
	g.regMu.Lock()
	defer g.regMu.Unlock()

	key := fmt.Sprintf("zkzone.%s", zone)
	if _, present := g.registry[key]; !present {
		zkzone := zk.NewZkZone(zk.DefaultConfig(zone, ctx.ZoneZkAddrs(zone)))
		g.registry[key] = zkzone
	}

	if z, ok := g.registry[key].(*zk.ZkZone); ok {
		return z
	}

	log.Critical("unknown zone: %s", zone)
	return nil
}

func DefaultGlobals() *GlobalConfig {
	return &GlobalConfig{
		APIPort:               9876,
		RPCPort:               9877,
		Debug:                 false,
		ClusterEnabled:        true,
		InputRecyclePoolSize:  100,
		FilterRecyclePoolSize: 100,
		HubChanSize:           200,
		PluginChanSize:        150,
		RouterTrack:           true,
		WatchdogTick:          time.Minute * 10,
		StartedAt:             time.Now(),
		registry:              map[string]interface{}{},
		ZrootConf:             "/dbus/conf",
		ZrootCheckpoint:       "/dbus/checkpoint",
		ZrootCluster:          "/dbus/cluster",
	}
}
<|endoftext|>


<commit_before>package mallory

import (
	"errors"
	"github.com/justmao945/mallory/ssh"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/user"
	"sync"
	"sync/atomic"
)

//
type EngineSSH struct {
	Env *Env
	URL *url.URL
	Cli *ssh.Client
	Cfg *ssh.ClientConfig
	Dir *EngineDirect
	// atomic Dial
	mutex   sync.RWMutex
	cntDial int64
}

// Create and initialize
func CreateEngineSSH(e *Env) (self *EngineSSH, err error) {
	self = &EngineSSH{
		Env: e,
		Cfg: &ssh.ClientConfig{},
	}
	// e.g.  ssh://user:passwd@192.168.1.1:1122
	self.URL, err = url.Parse(e.Remote)
	if err != nil {
		return
	}

	if self.URL.User != nil {
		self.Cfg.User = self.URL.User.Username()
	} else {
		u, err := user.Current()
		if err != nil {
			return self, err
		}
		// u.Name is the full name, should not be used
		self.Cfg.User = u.Username
	}

	// 1) try RSA keyring first
	for {
		id_rsa := os.ExpandEnv("$HOME/.ssh/id_rsa")
		pem, err := ioutil.ReadFile(id_rsa)
		if err != nil {
			break
		}
		signer, err := ssh.ParsePrivateKey(pem)
		if err != nil {
			break
		}
		self.Cfg.Auth = append(self.Cfg.Auth, ssh.PublicKeys(signer))
		// stop !!
		break
	}
	// 2) try password
	for {
		if self.URL.User == nil {
			break
		}
		if pass, ok := self.URL.User.Password(); ok {
			self.Cfg.Auth = append(self.Cfg.Auth, ssh.Password(pass))
		}
		// stop here!!
		break
	}

	if len(self.Cfg.Auth) == 0 {
		//TODO: keyboard intercative
		err = errors.New("Invalid auth method, please add password or generate ssh keys")
		return
	}

	self.Cli, err = ssh.Dial("tcp", self.URL.Host, self.Cfg)
	if err != nil {
		return
	}

	dial := func(network, addr string) (c net.Conn, err error) {
		for {
			// need read lock, we'll reconnect Cli if is disconnected
			// use read write lock may slow down connection ?
			self.mutex.RLock()
			c, err = self.Cli.Dial(network, addr)
			self.mutex.RUnlock()

			// We want to reconnect the network when disconnected.
			// FIXME: unexported net.errClosing
			if err != nil && err.Error() == "use of closed network connection" {
				// we may change the Cli, need write lock
				self.mutex.Lock()
				if self.cntDial < 0 {
					self.cntDial = 1
				} else {
					self.cntDial++
				}
				if self.cntDial > 1 {
					// someone already tried to reconnect, skip
					continue
				}
				self.Cli.Close()
				self.Cli, err = ssh.Dial("tcp", self.URL.Host, self.Cfg)
				if err != nil {
					return
				}
				self.mutex.Unlock()
				continue
			} else {
				atomic.AddInt64(&self.cntDial, -1)
			}

			// do not reconnect when no error or other errors
			break
		}
		return
	}

	self.Dir = &EngineDirect{
		Tr: &http.Transport{Dial: dial},
	}
	return
}

func (self *EngineSSH) Serve(s *Session) {
	self.Dir.Serve(s)
}

func (self *EngineSSH) Connect(s *Session) {
	self.Dir.Connect(s)
}
<commit_msg>minor fix on buggy seg<commit_after>package mallory

import (
	"errors"
	"github.com/justmao945/mallory/ssh"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/user"
	"sync"
	"sync/atomic"
)

//
type EngineSSH struct {
	Env *Env
	URL *url.URL
	Cli *ssh.Client
	Cfg *ssh.ClientConfig
	Dir *EngineDirect
	// atomic Dial
	mutex   sync.RWMutex
	cntDial int64
}

// Create and initialize
func CreateEngineSSH(e *Env) (self *EngineSSH, err error) {
	self = &EngineSSH{
		Env: e,
		Cfg: &ssh.ClientConfig{},
	}
	// e.g.  ssh://user:passwd@192.168.1.1:1122
	self.URL, err = url.Parse(e.Remote)
	if err != nil {
		return
	}

	if self.URL.User != nil {
		self.Cfg.User = self.URL.User.Username()
	} else {
		u, err := user.Current()
		if err != nil {
			return self, err
		}
		// u.Name is the full name, should not be used
		self.Cfg.User = u.Username
	}

	// 1) try RSA keyring first
	for {
		id_rsa := os.ExpandEnv("$HOME/.ssh/id_rsa")
		pem, err := ioutil.ReadFile(id_rsa)
		if err != nil {
			break
		}
		signer, err := ssh.ParsePrivateKey(pem)
		if err != nil {
			break
		}
		self.Cfg.Auth = append(self.Cfg.Auth, ssh.PublicKeys(signer))
		// stop !!
		break
	}
	// 2) try password
	for {
		if self.URL.User == nil {
			break
		}
		if pass, ok := self.URL.User.Password(); ok {
			self.Cfg.Auth = append(self.Cfg.Auth, ssh.Password(pass))
		}
		// stop here!!
		break
	}

	if len(self.Cfg.Auth) == 0 {
		//TODO: keyboard intercative
		err = errors.New("Invalid auth method, please add password or generate ssh keys")
		return
	}

	self.Cli, err = ssh.Dial("tcp", self.URL.Host, self.Cfg)
	if err != nil {
		return
	}

	dial := func(network, addr string) (c net.Conn, err error) {
		for i = 0; i < 3; i++ {
			// need read lock, we'll reconnect Cli if is disconnected
			// use read write lock may slow down connection ?
			self.mutex.RLock()
			c, err = self.Cli.Dial(network, addr)
			self.mutex.RUnlock()

			// We want to reconnect the network when disconnected.
			// FIXME: unexported net.errClosing
			if err != nil && err.Error() == "use of closed network connection" {
				// we may change the Cli, need write lock
				self.mutex.Lock()
				if self.cntDial < 0 {
					self.cntDial = 1
				} else {
					self.cntDial++
				}
				if self.cntDial > 1 {
					// someone already tried to reconnect, skip
					continue
				}
				self.Cli.Close()
				self.Cli, err = ssh.Dial("tcp", self.URL.Host, self.Cfg)
				if err != nil {
					self.cntDial--
					return
				}
				self.mutex.Unlock()
				continue
			} else {
				atomic.AddInt64(&self.cntDial, -1)
			}

			// do not reconnect when no error or other errors
			break
		}
		return
	}

	self.Dir = &EngineDirect{
		Tr: &http.Transport{Dial: dial},
	}
	return
}

func (self *EngineSSH) Serve(s *Session) {
	self.Dir.Serve(s)
}

func (self *EngineSSH) Connect(s *Session) {
	self.Dir.Connect(s)
}
<|endoftext|>


<commit_before>package anonymous_messaging

import "fmt"

type Mix struct {
	Id string
	PubKey int
	PrvKey int
	Server *TCPSocketServer
}

func (m Mix) StartMix() {
	m.Server.Start()
}

func (m Mix) ProcessPacket(packet string) string {
	return packet
}

func (m Mix) SendLoopMessage() {
	fmt.Println("Sending loop message")
}

func (m Mix) LogInfo(msg string) {
	fmt.Println(msg)
}<commit_msg>Fixed missing package import<commit_after>package anonymous_messaging

import (
	"fmt"
	tcp "anonymous-messaging/tcpconn"
)

type Mix struct {
	Id string
	PubKey int
	PrvKey int
	Server *tcp.TCPSocketServer
}

func (m Mix) StartMix() {
	m.Server.Start()
}

func (m Mix) ProcessPacket(packet string) string {
	return packet
}

func (m Mix) SendLoopMessage() {
	fmt.Println("Sending loop message")
}

func (m Mix) LogInfo(msg string) {
	fmt.Println(msg)
}<|endoftext|>