<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/docdb"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsDocDBSubnetGroup() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsDocDBSubnetGroupCreate,
		Read:   resourceAwsDocDBSubnetGroupRead,
		Update: resourceAwsDocDBSubnetGroupUpdate,
		Delete: resourceAwsDocDBSubnetGroupDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
				ValidateFunc:  validateDocDBSubnetGroupName,
			},
			"name_prefix": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name"},
				ValidateFunc:  validateDocDBSubnetGroupNamePrefix,
			},

			"description": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "Managed by Terraform",
			},

			"subnet_ids": {
				Type:     schema.TypeSet,
				Required: true,
				MinItems: 1,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsDocDBSubnetGroupCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).docdbconn
	tags := tagsFromMapDocDB(d.Get("tags").(map[string]interface{}))

	subnetIds := expandStringSet(d.Get("subnet_ids").(*schema.Set))

	var groupName string
	if v, ok := d.GetOk("name"); ok {
		groupName = v.(string)
	} else if v, ok := d.GetOk("name_prefix"); ok {
		groupName = resource.PrefixedUniqueId(v.(string))
	} else {
		groupName = resource.UniqueId()
	}

	createOpts := docdb.CreateDBSubnetGroupInput{
		DBSubnetGroupName:        aws.String(groupName),
		DBSubnetGroupDescription: aws.String(d.Get("description").(string)),
		SubnetIds:                subnetIds,
		Tags:                     tags,
	}

	log.Printf("[DEBUG] Create DocDB Subnet Group: %#v", createOpts)
	_, err := conn.CreateDBSubnetGroup(&createOpts)
	if err != nil {
		return fmt.Errorf("Error creating DocDB Subnet Group: %s", err)
	}

	d.SetId(groupName)

	return resourceAwsDocDBSubnetGroupRead(d, meta)
}

func resourceAwsDocDBSubnetGroupRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).docdbconn

	describeOpts := docdb.DescribeDBSubnetGroupsInput{
		DBSubnetGroupName: aws.String(d.Id()),
	}

	var subnetGroups []*docdb.DBSubnetGroup
	if err := conn.DescribeDBSubnetGroupsPages(&describeOpts, func(resp *docdb.DescribeDBSubnetGroupsOutput, lastPage bool) bool {
		subnetGroups = append(subnetGroups, resp.DBSubnetGroups...)
		return !lastPage
	}); err != nil {
		if isAWSErr(err, docdb.ErrCodeDBSubnetGroupNotFoundFault, "") {
			log.Printf("[WARN] DocDB Subnet Group (%s) not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return fmt.Errorf("error reading DocDB Subnet Group (%s) parameters: %s", d.Id(), err)
	}

	if len(subnetGroups) != 1 ||
		*subnetGroups[0].DBSubnetGroupName != d.Id() {
		return fmt.Errorf("Unable to find DocDB Subnet Group: %s, removing from state", d.Id())
	}

	subnetGroup := subnetGroups[0]
	d.Set("name", subnetGroup.DBSubnetGroupName)
	d.Set("description", subnetGroup.DBSubnetGroupDescription)
	d.Set("arn", subnetGroup.DBSubnetGroupArn)

	subnets := make([]string, 0, len(subnetGroup.Subnets))
	for _, s := range subnetGroup.Subnets {
		subnets = append(subnets, aws.StringValue(s.SubnetIdentifier))
	}
	if err := d.Set("subnet_ids", subnets); err != nil {
		return fmt.Errorf("error setting subnet_ids: %s", err)
	}

	resp, err := conn.ListTagsForResource(&docdb.ListTagsForResourceInput{
		ResourceName: subnetGroup.DBSubnetGroupArn,
	})

	if err != nil {
		log.Printf("[DEBUG] Error retrieving tags for ARN: %s", aws.StringValue(subnetGroup.DBSubnetGroupArn))
	}

	if err := d.Set("tags", tagsToMapDocDB(resp.TagList)); err != nil {
		return fmt.Errorf("Error setting DocDB Subnet Group tags: %s", err)
	}
	return nil
}

func resourceAwsDocDBSubnetGroupUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).docdbconn

	if d.HasChange("subnet_ids") || d.HasChange("description") {
		_, n := d.GetChange("subnet_ids")
		if n == nil {
			n = new(schema.Set)
		}
		sIds := expandStringSet(n.(*schema.Set))

		_, err := conn.ModifyDBSubnetGroup(&docdb.ModifyDBSubnetGroupInput{
			DBSubnetGroupName:        aws.String(d.Id()),
			DBSubnetGroupDescription: aws.String(d.Get("description").(string)),
			SubnetIds:                sIds,
		})

		if err != nil {
			return fmt.Errorf("error modify DocDB Subnet Group (%s) parameters: %s", d.Id(), err)
		}
	}

	if err := setTagsDocDB(conn, d); err != nil {
		return fmt.Errorf("error setting DocDB Subnet Group (%s) tags: %s", d.Id(), err)
	}
	d.SetPartial("tags")

	return resourceAwsDocDBSubnetGroupRead(d, meta)
}

func resourceAwsDocDBSubnetGroupDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).docdbconn

	delOpts := docdb.DeleteDBSubnetGroupInput{
		DBSubnetGroupName: aws.String(d.Id()),
	}

	log.Printf("[DEBUG] Deleting DocDB Subnet Group: %s", d.Id())

	_, err := conn.DeleteDBSubnetGroup(&delOpts)
	if err != nil {
		if isAWSErr(err, docdb.ErrCodeDBSubnetGroupNotFoundFault, "") {
			return nil
		}
		return fmt.Errorf("error deleting DocDB Subnet Group (%s): %s", d.Id(), err)
	}

	return waitForDocDBSubnetGroupDeletion(conn, d.Id())
}

func waitForDocDBSubnetGroupDeletion(conn *docdb.DocDB, name string) error {
	params := &docdb.DescribeDBSubnetGroupsInput{
		DBSubnetGroupName: aws.String(name),
	}

	return resource.Retry(10*time.Minute, func() *resource.RetryError {
		_, err := conn.DescribeDBSubnetGroups(params)

		if isAWSErr(err, docdb.ErrCodeDBSubnetGroupNotFoundFault, "") {
			return nil
		}

		if err != nil {
			return resource.NonRetryableError(err)
		}

		return resource.RetryableError(fmt.Errorf("DocDB Subnet Group (%s) still exists", name))
	})
}
<commit_msg>fix return err object<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/docdb"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsDocDBSubnetGroup() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsDocDBSubnetGroupCreate,
		Read:   resourceAwsDocDBSubnetGroupRead,
		Update: resourceAwsDocDBSubnetGroupUpdate,
		Delete: resourceAwsDocDBSubnetGroupDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
				ValidateFunc:  validateDocDBSubnetGroupName,
			},
			"name_prefix": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name"},
				ValidateFunc:  validateDocDBSubnetGroupNamePrefix,
			},

			"description": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "Managed by Terraform",
			},

			"subnet_ids": {
				Type:     schema.TypeSet,
				Required: true,
				MinItems: 1,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsDocDBSubnetGroupCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).docdbconn
	tags := tagsFromMapDocDB(d.Get("tags").(map[string]interface{}))

	subnetIds := expandStringSet(d.Get("subnet_ids").(*schema.Set))

	var groupName string
	if v, ok := d.GetOk("name"); ok {
		groupName = v.(string)
	} else if v, ok := d.GetOk("name_prefix"); ok {
		groupName = resource.PrefixedUniqueId(v.(string))
	} else {
		groupName = resource.UniqueId()
	}

	createOpts := docdb.CreateDBSubnetGroupInput{
		DBSubnetGroupName:        aws.String(groupName),
		DBSubnetGroupDescription: aws.String(d.Get("description").(string)),
		SubnetIds:                subnetIds,
		Tags:                     tags,
	}

	log.Printf("[DEBUG] Create DocDB Subnet Group: %#v", createOpts)
	_, err := conn.CreateDBSubnetGroup(&createOpts)
	if err != nil {
		return fmt.Errorf("error creating DocDB Subnet Group: %s", err)
	}

	d.SetId(groupName)

	return resourceAwsDocDBSubnetGroupRead(d, meta)
}

func resourceAwsDocDBSubnetGroupRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).docdbconn

	describeOpts := docdb.DescribeDBSubnetGroupsInput{
		DBSubnetGroupName: aws.String(d.Id()),
	}

	var subnetGroups []*docdb.DBSubnetGroup
	if err := conn.DescribeDBSubnetGroupsPages(&describeOpts, func(resp *docdb.DescribeDBSubnetGroupsOutput, lastPage bool) bool {
		subnetGroups = append(subnetGroups, resp.DBSubnetGroups...)
		return !lastPage
	}); err != nil {
		if isAWSErr(err, docdb.ErrCodeDBSubnetGroupNotFoundFault, "") {
			log.Printf("[WARN] DocDB Subnet Group (%s) not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return fmt.Errorf("error reading DocDB Subnet Group (%s) parameters: %s", d.Id(), err)
	}

	if len(subnetGroups) != 1 ||
		*subnetGroups[0].DBSubnetGroupName != d.Id() {
		return fmt.Errorf("unable to find DocDB Subnet Group: %s, removing from state", d.Id())
	}

	subnetGroup := subnetGroups[0]
	d.Set("name", subnetGroup.DBSubnetGroupName)
	d.Set("description", subnetGroup.DBSubnetGroupDescription)
	d.Set("arn", subnetGroup.DBSubnetGroupArn)

	subnets := make([]string, 0, len(subnetGroup.Subnets))
	for _, s := range subnetGroup.Subnets {
		subnets = append(subnets, aws.StringValue(s.SubnetIdentifier))
	}
	if err := d.Set("subnet_ids", subnets); err != nil {
		return fmt.Errorf("error setting subnet_ids: %s", err)
	}

	resp, err := conn.ListTagsForResource(&docdb.ListTagsForResourceInput{
		ResourceName: subnetGroup.DBSubnetGroupArn,
	})

	if err != nil {
		return fmt.Errorf("error retrieving tags for ARN: %s", aws.StringValue(subnetGroup.DBSubnetGroupArn))
	}

	if err := d.Set("tags", tagsToMapDocDB(resp.TagList)); err != nil {
		return fmt.Errorf("error setting DocDB Subnet Group tags: %s", err)
	}
	return nil
}

func resourceAwsDocDBSubnetGroupUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).docdbconn

	if d.HasChange("subnet_ids") || d.HasChange("description") {
		_, n := d.GetChange("subnet_ids")
		if n == nil {
			n = new(schema.Set)
		}
		sIds := expandStringSet(n.(*schema.Set))

		_, err := conn.ModifyDBSubnetGroup(&docdb.ModifyDBSubnetGroupInput{
			DBSubnetGroupName:        aws.String(d.Id()),
			DBSubnetGroupDescription: aws.String(d.Get("description").(string)),
			SubnetIds:                sIds,
		})

		if err != nil {
			return fmt.Errorf("error modify DocDB Subnet Group (%s) parameters: %s", d.Id(), err)
		}
	}

	if err := setTagsDocDB(conn, d); err != nil {
		return fmt.Errorf("error setting DocDB Subnet Group (%s) tags: %s", d.Id(), err)
	}
	d.SetPartial("tags")

	return resourceAwsDocDBSubnetGroupRead(d, meta)
}

func resourceAwsDocDBSubnetGroupDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).docdbconn

	delOpts := docdb.DeleteDBSubnetGroupInput{
		DBSubnetGroupName: aws.String(d.Id()),
	}

	log.Printf("[DEBUG] Deleting DocDB Subnet Group: %s", d.Id())

	_, err := conn.DeleteDBSubnetGroup(&delOpts)
	if err != nil {
		if isAWSErr(err, docdb.ErrCodeDBSubnetGroupNotFoundFault, "") {
			return nil
		}
		return fmt.Errorf("error deleting DocDB Subnet Group (%s): %s", d.Id(), err)
	}

	return waitForDocDBSubnetGroupDeletion(conn, d.Id())
}

func waitForDocDBSubnetGroupDeletion(conn *docdb.DocDB, name string) error {
	params := &docdb.DescribeDBSubnetGroupsInput{
		DBSubnetGroupName: aws.String(name),
	}

	return resource.Retry(10*time.Minute, func() *resource.RetryError {
		_, err := conn.DescribeDBSubnetGroups(params)

		if isAWSErr(err, docdb.ErrCodeDBSubnetGroupNotFoundFault, "") {
			return nil
		}

		if err != nil {
			return resource.NonRetryableError(err)
		}

		return resource.RetryableError(fmt.Errorf("DocDB Subnet Group (%s) still exists", name))
	})
}
<|endoftext|>


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

// +build !android

package font

import "io/ioutil"

func buildDefault() ([]byte, error) {
	return ioutil.ReadFile("/usr/share/fonts/truetype/droid/DroidSans.ttf")
}

func buildMonospace() ([]byte, error) {
	return ioutil.ReadFile("/usr/share/fonts/truetype/droid/DroidSansMono.ttf")
}
<commit_msg>exp/font: droid->noto fallback in tests<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !android

package font

import "io/ioutil"

func buildDefault() ([]byte, error) {
	// Try Noto first, but fall back to Droid as the latter was deprecated
	noto, nerr := ioutil.ReadFile("/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf")
	if nerr != nil {
		if droid, err := ioutil.ReadFile("/usr/share/fonts/truetype/droid/DroidSans.ttf"); err == nil {
			return droid, nil
		}
	}
	return noto, nerr
}

func buildMonospace() ([]byte, error) {
	// Try Noto first, but fall back to Droid as the latter was deprecated
	noto, nerr := ioutil.ReadFile("/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf")
	if nerr != nil {
		if droid, err := ioutil.ReadFile("/usr/share/fonts/truetype/droid/DroidSansMono.ttf"); err == nil {
			return droid, nil
		}
	}
	return noto, nerr
}
<|endoftext|>


<commit_before>package daemon

import (
	"fmt"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"

	"github.com/subgraph/oz"
	"github.com/subgraph/oz/ipc"
	"github.com/subgraph/oz/network"

	"github.com/op/go-logging"
)

type daemonState struct {
	log         *logging.Logger
	config      *oz.Config
	profiles    oz.Profiles
	sandboxes   []*Sandbox
	nextSboxId  int
	nextDisplay int
	memBackend  *logging.ChannelMemoryBackend
	backends    []logging.Backend
	network     *network.HostNetwork
}

func Main() {
	d := initialize()

	err := runServer(
		d.log,
		d.handlePing,
		d.handleListProfiles,
		d.handleLaunch,
		d.handleListSandboxes,
		d.handleKillSandbox,
		d.handleLogs,
	)
	if err != nil {
		d.log.Error("Error running server: %v", err)
	}
}

func initialize() *daemonState {
	sigs := make(chan os.Signal)
	signal.Notify(sigs, syscall.SIGHUP, syscall.SIGUSR1)

	d := &daemonState{}
	d.initializeLogging()
	config, err := d.loadConfig()
	if err != nil {
		d.log.Error("Could not load configuration: %s", oz.DefaultConfigPath, err)
		os.Exit(1)
	}
	d.config = config
	ps, err := d.loadProfiles(d.config.ProfileDir)
	if err != nil {
		d.log.Fatalf("Failed to load profiles: %v", err)
		os.Exit(1)
	}
	d.profiles = ps
	oz.ReapChildProcs(d.log, d.handleChildExit)
	d.nextSboxId = 1
	d.nextDisplay = 100

	for _, pp := range d.profiles {
		if pp.Networking.Nettype == network.TYPE_BRIDGE {
			d.log.Info("Initializing bridge networking")
			htn, err := network.BridgeInit(d.config.BridgeMACAddr, d.config.NMIgnoreFile, d.log)
			if err != nil {
				d.log.Fatalf("Failed to initialize bridge networking: %+v", err)
				return nil
			}

			d.network = htn

			network.NetPrint(d.log)

			break
		}
	}

	sockets := path.Join(config.SandboxPath, "sockets")
	if err := os.MkdirAll(sockets, 0755); err != nil {
		d.log.Fatalf("Failed to create sockets directory: %v", err)
	}

	go d.processSignals(sigs)

	return d
}

func (d *daemonState) loadConfig() (*oz.Config, error) {
	config, err := oz.LoadConfig(oz.DefaultConfigPath)
	if err != nil {
		if os.IsNotExist(err) {
			d.log.Info("Configuration file (%s) is missing, using defaults.", oz.DefaultConfigPath)
			config = oz.NewDefaultConfig()
		} else {
			return nil, err
		}
	}
	d.log.Info("Oz Global Config: %+v", config)

	return config, nil
}

func (d *daemonState) loadProfiles(profileDir string) (oz.Profiles, error) {
	ps, err := oz.LoadProfiles(profileDir)
	if err != nil {
		return nil, err
	}
	d.Debug("%d profiles loaded", len(ps))
	return ps, nil
}

func (d *daemonState) processSignals(c <-chan os.Signal) {
	for {
		sig := <-c
		switch sig {
		case syscall.SIGHUP:
			d.log.Notice("Received HUP signal, reloading profiles.")

			ps, err := d.loadProfiles(d.config.ProfileDir)
			if err != nil {
				d.log.Error("Failed to reload profiles: %v", err)
				return
			}
			d.profiles = ps
		case syscall.SIGUSR1:
			d.handleNetworkReconfigure()
		}
	}
}

func (d *daemonState) handleChildExit(pid int, wstatus syscall.WaitStatus) {
	d.Debug("Child process pid=%d exited with status %d", pid, wstatus.ExitStatus())

	for _, sbox := range d.sandboxes {
		if sbox.init.Process.Pid == pid {
			sbox.remove(d.log)
			return
		}
	}
	d.Notice("No sandbox found with oz-init pid = %d", pid)
}

func runServer(log *logging.Logger, args ...interface{}) error {
	s, err := ipc.NewServer(SocketName, messageFactory, log, args...)
	if err != nil {
		return err
	}

	return s.Run()
}

func (d *daemonState) handlePing(msg *PingMsg, m *ipc.Message) error {
	d.Debug("received ping with data [%s]", msg.Data)
	return m.Respond(&PingMsg{msg.Data})
}

func (d *daemonState) handleListProfiles(msg *ListProfilesMsg, m *ipc.Message) error {
	r := new(ListProfilesResp)
	index := 1
	for _, p := range d.profiles {
		r.Profiles = append(r.Profiles, Profile{Index: index, Name: p.Name, Path: p.Path})
		index += 1
	}
	return m.Respond(r)
}

func (d *daemonState) handleLaunch(msg *LaunchMsg, m *ipc.Message) error {
	d.Debug("Launch message received. Path: %s Name: %s Pwd: %s Args: %+v", msg.Path, msg.Name, msg.Pwd, msg.Args)
	p, err := d.getProfileFromLaunchMsg(msg)
	if err != nil {
		return m.Respond(&ErrorMsg{err.Error()})
	}

	if sbox := d.getRunningSandboxByName(p.Name); sbox != nil {
		if msg.Noexec {
			errmsg := "Asked to launch program but sandbox is running and noexec is set!"
			d.Notice(errmsg)
			return m.Respond(&ErrorMsg{errmsg})
		} else {
			d.Info("Found running sandbox for `%s`, running program there", p.Name)
			sbox.launchProgram(d.config.PrefixPath, msg.Path, msg.Pwd, msg.Args, d.log)
		}
	} else {
		d.Debug("Would launch %s", p.Name)
		msg.Env = d.sanitizeEnvironment(p, msg.Env)
		_, err = d.launch(p, msg, m.Ucred.Uid, m.Ucred.Gid, d.log)
		if err != nil {
			d.Warning("Launch of %s failed: %v", p.Name, err)
			return m.Respond(&ErrorMsg{err.Error()})
		}
	}
	return m.Respond(&OkMsg{})
}

func (d *daemonState) sanitizeEnvironment(p *oz.Profile, oldEnv []string) []string {
	newEnv := []string{}

	for _, EnvItem := range d.config.EnvironmentVars {
		for _, OldItem := range oldEnv {
			if strings.HasPrefix(OldItem, EnvItem+"=") {
				newEnv = append(newEnv, EnvItem+"="+strings.Replace(OldItem, EnvItem+"=", "", 1))

				break
			}
		}
	}

	for _, EnvItem := range p.Environment {
		if EnvItem.Value != "" {
			d.log.Info("Setting environment variable: %s=%s\n", EnvItem.Name, EnvItem.Value)

			newEnv = append(newEnv, EnvItem.Name+"="+EnvItem.Value)
		} else {
			for _, OldItem := range oldEnv {
				if strings.HasPrefix(OldItem, EnvItem.Name+"=") {
					NewValue := strings.Replace(OldItem, EnvItem.Name+"=", "", 1)
					newEnv = append(newEnv, EnvItem.Name+"="+NewValue)

					d.log.Info("Cloning environment variable: %s=%s\n", EnvItem.Name, NewValue)

					break
				}
			}
		}
	}

	return newEnv
}

func (d *daemonState) handleKillSandbox(msg *KillSandboxMsg, m *ipc.Message) error {
	if msg.Id == -1 {
		for _, sb := range d.sandboxes {
			if err := sb.init.Process.Signal(os.Interrupt); err != nil {
				return m.Respond(&ErrorMsg{fmt.Sprintf("failed to send interrupt signal: %v", err)})
			}
		}
	} else {
		sbox := d.sandboxById(msg.Id)
		if sbox == nil {
			return m.Respond(&ErrorMsg{fmt.Sprintf("no sandbox found with id = %d", msg.Id)})
		}
		if err := sbox.init.Process.Signal(os.Interrupt); err != nil {
			return m.Respond(&ErrorMsg{fmt.Sprintf("failed to send interrupt signal: %v", err)})
		}
	}
	return m.Respond(&OkMsg{})
}

func (d *daemonState) sandboxById(id int) *Sandbox {
	for _, sb := range d.sandboxes {
		if sb.id == id {
			return sb
		}
	}
	return nil
}

func (d *daemonState) getProfileFromLaunchMsg(msg *LaunchMsg) (*oz.Profile, error) {
	if msg.Index == 0 && msg.Name == "" {
		return d.getProfileByPath(msg.Path)
	}
	return d.getProfileByIdxOrName(msg.Index, msg.Name)
}

func (d *daemonState) getProfileByPath(cpath string) (*oz.Profile, error) {
	for _, p := range d.profiles {
		if p.Path == cpath {
			return p, nil
		}
		for _, pp := range p.Paths {
			if pp == cpath {
				return p, nil
			}
		}
	}

	return nil, fmt.Errorf("could not find profile path '%s'", cpath)
}

func (d *daemonState) getProfileByIdxOrName(index int, name string) (*oz.Profile, error) {
	if len(name) == 0 {
		if index < 1 || index > len(d.profiles) {
			return nil, fmt.Errorf("not a valid profile index (%d)", index)
		}
		return d.profiles[index-1], nil
	}

	for _, p := range d.profiles {
		if p.Name == name {
			return p, nil
		}
	}
	return nil, fmt.Errorf("could not find profile name '%s'", name)
}

func (d *daemonState) getRunningSandboxByName(name string) *Sandbox {
	for _, sb := range d.sandboxes {
		if sb.profile.Name == name {
			return sb
		}
	}

	return nil
}

func (d *daemonState) handleListSandboxes(list *ListSandboxesMsg, msg *ipc.Message) error {
	r := new(ListSandboxesResp)
	for _, sb := range d.sandboxes {
		r.Sandboxes = append(r.Sandboxes, SandboxInfo{Id: sb.id, Address: sb.addr, Profile: sb.profile.Name})
	}
	return msg.Respond(r)
}

func (d *daemonState) handleLogs(logs *LogsMsg, msg *ipc.Message) error {
	for n := d.memBackend.Head(); n != nil; n = n.Next() {
		s := n.Record.Formatted(0)
		msg.Respond(&LogData{Lines: []string{s}})
	}
	if logs.Follow {
		d.followLogs(msg)
		return nil
	}
	msg.Respond(&OkMsg{})
	return nil
}

func (d *daemonState) handleNetworkReconfigure() {
	brIP, brNet, err := network.FindEmptyRange()
	if err != nil {
		return
	}
	if brIP.Equal(d.network.Gateway) {
		d.log.Notice("Range is still available, not reconfiguring.")
		return
	}
	d.log.Notice("Network has changed, reconfiguring with %s %s", brIP.String(), brNet.String())

	if err := d.network.BridgeReconfigure(d.log); err != nil {
		d.log.Error("Unable to reconfigure bridge network: %v", err)
		return
	}
	/*
		for _, sbox := range d.sandboxes {
			if sbox.profile.Networking.Nettype == network.TYPE_BRIDGE {
				sbox.network, err := network.PrepareSandboxNetwork(d.network, d.log)
				if err != nil {
					d.log.Error("Unable to prepare reconfigure of sandbox `%s` networking: %v", sbox.profile.Name, err)
					continue
				}
				if err := d.network.NetReconfigure(d.network, sbox.network, sbox.Pid, d.log); err != nil {
					d.log.Error("Unable to reconfigure sandbox `%s` networking: %v", sbox.profile.Name, err)
					continue
				}
				// TODO: Reconfigure default gateway inside sandbox
			}
		}
	*/
	return
}
<commit_msg>Ignore empty env declarations<commit_after>package daemon

import (
	"fmt"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"

	"github.com/subgraph/oz"
	"github.com/subgraph/oz/ipc"
	"github.com/subgraph/oz/network"

	"github.com/op/go-logging"
)

type daemonState struct {
	log         *logging.Logger
	config      *oz.Config
	profiles    oz.Profiles
	sandboxes   []*Sandbox
	nextSboxId  int
	nextDisplay int
	memBackend  *logging.ChannelMemoryBackend
	backends    []logging.Backend
	network     *network.HostNetwork
}

func Main() {
	d := initialize()

	err := runServer(
		d.log,
		d.handlePing,
		d.handleListProfiles,
		d.handleLaunch,
		d.handleListSandboxes,
		d.handleKillSandbox,
		d.handleLogs,
	)
	if err != nil {
		d.log.Error("Error running server: %v", err)
	}
}

func initialize() *daemonState {
	sigs := make(chan os.Signal)
	signal.Notify(sigs, syscall.SIGHUP, syscall.SIGUSR1)

	d := &daemonState{}
	d.initializeLogging()
	config, err := d.loadConfig()
	if err != nil {
		d.log.Error("Could not load configuration: %s", oz.DefaultConfigPath, err)
		os.Exit(1)
	}
	d.config = config
	ps, err := d.loadProfiles(d.config.ProfileDir)
	if err != nil {
		d.log.Fatalf("Failed to load profiles: %v", err)
		os.Exit(1)
	}
	d.profiles = ps
	oz.ReapChildProcs(d.log, d.handleChildExit)
	d.nextSboxId = 1
	d.nextDisplay = 100

	for _, pp := range d.profiles {
		if pp.Networking.Nettype == network.TYPE_BRIDGE {
			d.log.Info("Initializing bridge networking")
			htn, err := network.BridgeInit(d.config.BridgeMACAddr, d.config.NMIgnoreFile, d.log)
			if err != nil {
				d.log.Fatalf("Failed to initialize bridge networking: %+v", err)
				return nil
			}

			d.network = htn

			network.NetPrint(d.log)

			break
		}
	}

	sockets := path.Join(config.SandboxPath, "sockets")
	if err := os.MkdirAll(sockets, 0755); err != nil {
		d.log.Fatalf("Failed to create sockets directory: %v", err)
	}

	go d.processSignals(sigs)

	return d
}

func (d *daemonState) loadConfig() (*oz.Config, error) {
	config, err := oz.LoadConfig(oz.DefaultConfigPath)
	if err != nil {
		if os.IsNotExist(err) {
			d.log.Info("Configuration file (%s) is missing, using defaults.", oz.DefaultConfigPath)
			config = oz.NewDefaultConfig()
		} else {
			return nil, err
		}
	}
	d.log.Info("Oz Global Config: %+v", config)

	return config, nil
}

func (d *daemonState) loadProfiles(profileDir string) (oz.Profiles, error) {
	ps, err := oz.LoadProfiles(profileDir)
	if err != nil {
		return nil, err
	}
	d.Debug("%d profiles loaded", len(ps))
	return ps, nil
}

func (d *daemonState) processSignals(c <-chan os.Signal) {
	for {
		sig := <-c
		switch sig {
		case syscall.SIGHUP:
			d.log.Notice("Received HUP signal, reloading profiles.")

			ps, err := d.loadProfiles(d.config.ProfileDir)
			if err != nil {
				d.log.Error("Failed to reload profiles: %v", err)
				return
			}
			d.profiles = ps
		case syscall.SIGUSR1:
			d.handleNetworkReconfigure()
		}
	}
}

func (d *daemonState) handleChildExit(pid int, wstatus syscall.WaitStatus) {
	d.Debug("Child process pid=%d exited with status %d", pid, wstatus.ExitStatus())

	for _, sbox := range d.sandboxes {
		if sbox.init.Process.Pid == pid {
			sbox.remove(d.log)
			return
		}
	}
	d.Notice("No sandbox found with oz-init pid = %d", pid)
}

func runServer(log *logging.Logger, args ...interface{}) error {
	s, err := ipc.NewServer(SocketName, messageFactory, log, args...)
	if err != nil {
		return err
	}

	return s.Run()
}

func (d *daemonState) handlePing(msg *PingMsg, m *ipc.Message) error {
	d.Debug("received ping with data [%s]", msg.Data)
	return m.Respond(&PingMsg{msg.Data})
}

func (d *daemonState) handleListProfiles(msg *ListProfilesMsg, m *ipc.Message) error {
	r := new(ListProfilesResp)
	index := 1
	for _, p := range d.profiles {
		r.Profiles = append(r.Profiles, Profile{Index: index, Name: p.Name, Path: p.Path})
		index += 1
	}
	return m.Respond(r)
}

func (d *daemonState) handleLaunch(msg *LaunchMsg, m *ipc.Message) error {
	d.Debug("Launch message received. Path: %s Name: %s Pwd: %s Args: %+v", msg.Path, msg.Name, msg.Pwd, msg.Args)
	p, err := d.getProfileFromLaunchMsg(msg)
	if err != nil {
		return m.Respond(&ErrorMsg{err.Error()})
	}

	if sbox := d.getRunningSandboxByName(p.Name); sbox != nil {
		if msg.Noexec {
			errmsg := "Asked to launch program but sandbox is running and noexec is set!"
			d.Notice(errmsg)
			return m.Respond(&ErrorMsg{errmsg})
		} else {
			d.Info("Found running sandbox for `%s`, running program there", p.Name)
			sbox.launchProgram(d.config.PrefixPath, msg.Path, msg.Pwd, msg.Args, d.log)
		}
	} else {
		d.Debug("Would launch %s", p.Name)
		msg.Env = d.sanitizeEnvironment(p, msg.Env)
		_, err = d.launch(p, msg, m.Ucred.Uid, m.Ucred.Gid, d.log)
		if err != nil {
			d.Warning("Launch of %s failed: %v", p.Name, err)
			return m.Respond(&ErrorMsg{err.Error()})
		}
	}
	return m.Respond(&OkMsg{})
}

func (d *daemonState) sanitizeEnvironment(p *oz.Profile, oldEnv []string) []string {
	newEnv := []string{}

	for _, EnvItem := range d.config.EnvironmentVars {
		for _, OldItem := range oldEnv {
			if strings.HasPrefix(OldItem, EnvItem+"=") {
				newEnv = append(newEnv, EnvItem+"="+strings.Replace(OldItem, EnvItem+"=", "", 1))

				break
			}
		}
	}

	for _, EnvItem := range p.Environment {
		if EnvItem.Name == "" {
			continue
		}
		if EnvItem.Value != "" {
			d.log.Info("Setting environment variable: %s=%s\n", EnvItem.Name, EnvItem.Value)

			newEnv = append(newEnv, EnvItem.Name+"="+EnvItem.Value)
		} else {
			for _, OldItem := range oldEnv {
				if strings.HasPrefix(OldItem, EnvItem.Name+"=") {
					NewValue := strings.Replace(OldItem, EnvItem.Name+"=", "", 1)
					newEnv = append(newEnv, EnvItem.Name+"="+NewValue)

					d.log.Info("Cloning environment variable: %s=%s\n", EnvItem.Name, NewValue)

					break
				}
			}
		}
	}

	return newEnv
}

func (d *daemonState) handleKillSandbox(msg *KillSandboxMsg, m *ipc.Message) error {
	if msg.Id == -1 {
		for _, sb := range d.sandboxes {
			if err := sb.init.Process.Signal(os.Interrupt); err != nil {
				return m.Respond(&ErrorMsg{fmt.Sprintf("failed to send interrupt signal: %v", err)})
			}
		}
	} else {
		sbox := d.sandboxById(msg.Id)
		if sbox == nil {
			return m.Respond(&ErrorMsg{fmt.Sprintf("no sandbox found with id = %d", msg.Id)})
		}
		if err := sbox.init.Process.Signal(os.Interrupt); err != nil {
			return m.Respond(&ErrorMsg{fmt.Sprintf("failed to send interrupt signal: %v", err)})
		}
	}
	return m.Respond(&OkMsg{})
}

func (d *daemonState) sandboxById(id int) *Sandbox {
	for _, sb := range d.sandboxes {
		if sb.id == id {
			return sb
		}
	}
	return nil
}

func (d *daemonState) getProfileFromLaunchMsg(msg *LaunchMsg) (*oz.Profile, error) {
	if msg.Index == 0 && msg.Name == "" {
		return d.getProfileByPath(msg.Path)
	}
	return d.getProfileByIdxOrName(msg.Index, msg.Name)
}

func (d *daemonState) getProfileByPath(cpath string) (*oz.Profile, error) {
	for _, p := range d.profiles {
		if p.Path == cpath {
			return p, nil
		}
		for _, pp := range p.Paths {
			if pp == cpath {
				return p, nil
			}
		}
	}

	return nil, fmt.Errorf("could not find profile path '%s'", cpath)
}

func (d *daemonState) getProfileByIdxOrName(index int, name string) (*oz.Profile, error) {
	if len(name) == 0 {
		if index < 1 || index > len(d.profiles) {
			return nil, fmt.Errorf("not a valid profile index (%d)", index)
		}
		return d.profiles[index-1], nil
	}

	for _, p := range d.profiles {
		if p.Name == name {
			return p, nil
		}
	}
	return nil, fmt.Errorf("could not find profile name '%s'", name)
}

func (d *daemonState) getRunningSandboxByName(name string) *Sandbox {
	for _, sb := range d.sandboxes {
		if sb.profile.Name == name {
			return sb
		}
	}

	return nil
}

func (d *daemonState) handleListSandboxes(list *ListSandboxesMsg, msg *ipc.Message) error {
	r := new(ListSandboxesResp)
	for _, sb := range d.sandboxes {
		r.Sandboxes = append(r.Sandboxes, SandboxInfo{Id: sb.id, Address: sb.addr, Profile: sb.profile.Name})
	}
	return msg.Respond(r)
}

func (d *daemonState) handleLogs(logs *LogsMsg, msg *ipc.Message) error {
	for n := d.memBackend.Head(); n != nil; n = n.Next() {
		s := n.Record.Formatted(0)
		msg.Respond(&LogData{Lines: []string{s}})
	}
	if logs.Follow {
		d.followLogs(msg)
		return nil
	}
	msg.Respond(&OkMsg{})
	return nil
}

func (d *daemonState) handleNetworkReconfigure() {
	brIP, brNet, err := network.FindEmptyRange()
	if err != nil {
		return
	}
	if brIP.Equal(d.network.Gateway) {
		d.log.Notice("Range is still available, not reconfiguring.")
		return
	}
	d.log.Notice("Network has changed, reconfiguring with %s %s", brIP.String(), brNet.String())

	if err := d.network.BridgeReconfigure(d.log); err != nil {
		d.log.Error("Unable to reconfigure bridge network: %v", err)
		return
	}
	/*
		for _, sbox := range d.sandboxes {
			if sbox.profile.Networking.Nettype == network.TYPE_BRIDGE {
				sbox.network, err := network.PrepareSandboxNetwork(d.network, d.log)
				if err != nil {
					d.log.Error("Unable to prepare reconfigure of sandbox `%s` networking: %v", sbox.profile.Name, err)
					continue
				}
				if err := d.network.NetReconfigure(d.network, sbox.network, sbox.Pid, d.log); err != nil {
					d.log.Error("Unable to reconfigure sandbox `%s` networking: %v", sbox.profile.Name, err)
					continue
				}
				// TODO: Reconfigure default gateway inside sandbox
			}
		}
	*/
	return
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package node

import (
	"encoding/json"
	"fmt"
	"net"
	"os"
	"strings"
	"time"

	"k8s.io/klog"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	"k8s.io/apimachinery/pkg/util/wait"
	clientset "k8s.io/client-go/kubernetes"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
)

const (
	// NodeUnreachablePodReason is the reason on a pod when its state cannot be confirmed as kubelet is unresponsive
	// on the node it is (was) running.
	NodeUnreachablePodReason = "NodeLost"
	// NodeUnreachablePodMessage is the message on a pod when its state cannot be confirmed as kubelet is unresponsive
	// on the node it is (was) running.
	NodeUnreachablePodMessage = "Node %v which was running pod %v is unresponsive"
)

// GetHostname returns OS's hostname if 'hostnameOverride' is empty; otherwise, return 'hostnameOverride'.
func GetHostname(hostnameOverride string) (string, error) {
	hostName := hostnameOverride
	if len(hostName) == 0 {
		nodeName, err := os.Hostname()
		if err != nil {
			return "", fmt.Errorf("couldn't determine hostname: %v", err)
		}
		hostName = nodeName
	}

	// Trim whitespaces first to avoid getting an empty hostname
	// For linux, the hostname is read from file /proc/sys/kernel/hostname directly
	hostName = strings.TrimSpace(hostName)
	if len(hostName) == 0 {
		return "", fmt.Errorf("empty hostname is invalid")
	}
	return strings.ToLower(hostName), nil
}

// NoMatchError is a typed implementation of the error interface. It indicates a failure to get a matching Node.
type NoMatchError struct {
	addresses []v1.NodeAddress
}

// Error is the implementation of the conventional interface for
// representing an error condition, with the nil value representing no error.
func (e *NoMatchError) Error() string {
	return fmt.Sprintf("no preferred addresses found; known addresses: %v", e.addresses)
}

// GetPreferredNodeAddress returns the address of the provided node, using the provided preference order.
// If none of the preferred address types are found, an error is returned.
func GetPreferredNodeAddress(node *v1.Node, preferredAddressTypes []v1.NodeAddressType) (string, error) {
	for _, addressType := range preferredAddressTypes {
		for _, address := range node.Status.Addresses {
			if address.Type == addressType {
				return address.Address, nil
			}
		}
	}
	return "", &NoMatchError{addresses: node.Status.Addresses}
}

// GetNodeHostIP returns the provided node's IP, based on the priority:
// 1. NodeInternalIP
// 2. NodeExternalIP
func GetNodeHostIP(node *v1.Node) (net.IP, error) {
	addresses := node.Status.Addresses
	addressMap := make(map[v1.NodeAddressType][]v1.NodeAddress)
	for i := range addresses {
		addressMap[addresses[i].Type] = append(addressMap[addresses[i].Type], addresses[i])
	}
	if addresses, ok := addressMap[v1.NodeInternalIP]; ok {
		return net.ParseIP(addresses[0].Address), nil
	}
	if addresses, ok := addressMap[v1.NodeExternalIP]; ok {
		return net.ParseIP(addresses[0].Address), nil
	}
	return nil, fmt.Errorf("host IP unknown; known addresses: %v", addresses)
}

// GetNodeIP returns the ip of node with the provided hostname
// If required, wait for the node to be defined.
func GetNodeIP(client clientset.Interface, hostname string) net.IP {
	var nodeIP net.IP
	backoff := wait.Backoff {
		Steps:    5,
		Duration: 1 * time.Second,
		Factor:   2.0,
		Jitter:   0.2,
	}

	err := wait.ExponentialBackoff(backoff, func() (bool, error) {
		node, err := client.CoreV1().Nodes().Get(hostname, metav1.GetOptions{})
		if err != nil {
			klog.Errorf("Failed to retrieve node info: %v", err)
			return false, nil
		}
		nodeIP, err = GetNodeHostIP(node)
		if err != nil {
			klog.Errorf("Failed to retrieve node IP: %v", err)
			return false, err
		}
		return true, nil
	})
	if err == nil {
		klog.Infof("Successfully retrieved node IP: %v", nodeIP)
	}
	return nodeIP
}

// GetZoneKey is a helper function that builds a string identifier that is unique per failure-zone;
// it returns empty-string for no zone.
func GetZoneKey(node *v1.Node) string {
	labels := node.Labels
	if labels == nil {
		return ""
	}

	region, _ := labels[v1.LabelZoneRegion]
	failureDomain, _ := labels[v1.LabelZoneFailureDomain]

	if region == "" && failureDomain == "" {
		return ""
	}

	// We include the null character just in case region or failureDomain has a colon
	// (We do assume there's no null characters in a region or failureDomain)
	// As a nice side-benefit, the null character is not printed by fmt.Print or glog
	return region + ":\x00:" + failureDomain
}

// SetNodeCondition updates specific node condition with patch operation.
func SetNodeCondition(c clientset.Interface, node types.NodeName, condition v1.NodeCondition) error {
	generatePatch := func(condition v1.NodeCondition) ([]byte, error) {
		raw, err := json.Marshal(&[]v1.NodeCondition{condition})
		if err != nil {
			return nil, err
		}
		return []byte(fmt.Sprintf(`{"status":{"conditions":%s}}`, raw)), nil
	}
	condition.LastHeartbeatTime = metav1.NewTime(time.Now())
	patch, err := generatePatch(condition)
	if err != nil {
		return nil
	}
	_, err = c.CoreV1().Nodes().PatchStatus(string(node), patch)
	return err
}

// PatchNodeCIDR patches the specified node's CIDR to the given value.
func PatchNodeCIDR(c clientset.Interface, node types.NodeName, cidr string) error {
	raw, err := json.Marshal(cidr)
	if err != nil {
		return fmt.Errorf("failed to json.Marshal CIDR: %v", err)
	}

	patchBytes := []byte(fmt.Sprintf(`{"spec":{"podCIDR":%s}}`, raw))

	if _, err := c.CoreV1().Nodes().Patch(string(node), types.StrategicMergePatchType, patchBytes); err != nil {
		return fmt.Errorf("failed to patch node CIDR: %v", err)
	}
	return nil
}

// PatchNodeStatus patches node status.
func PatchNodeStatus(c v1core.CoreV1Interface, nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) (*v1.Node, []byte, error) {
	patchBytes, err := preparePatchBytesforNodeStatus(nodeName, oldNode, newNode)
	if err != nil {
		return nil, nil, err
	}

	updatedNode, err := c.Nodes().Patch(string(nodeName), types.StrategicMergePatchType, patchBytes, "status")
	if err != nil {
		return nil, nil, fmt.Errorf("failed to patch status %q for node %q: %v", patchBytes, nodeName, err)
	}
	return updatedNode, patchBytes, nil
}

func preparePatchBytesforNodeStatus(nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) ([]byte, error) {
	oldData, err := json.Marshal(oldNode)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal oldData for node %q: %v", nodeName, err)
	}

	// Reset spec to make sure only patch for Status or ObjectMeta is generated.
	// Note that we don't reset ObjectMeta here, because:
	// 1. This aligns with Nodes().UpdateStatus().
	// 2. Some component does use this to update node annotations.
	newNode.Spec = oldNode.Spec
	newData, err := json.Marshal(newNode)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal newData for node %q: %v", nodeName, err)
	}

	patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
	if err != nil {
		return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for node %q: %v", nodeName, err)
	}
	return patchBytes, nil
}
<commit_msg>Updated node.go using update-gofmt.sh<commit_after>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package node

import (
	"encoding/json"
	"fmt"
	"net"
	"os"
	"strings"
	"time"

	"k8s.io/klog"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	"k8s.io/apimachinery/pkg/util/wait"
	clientset "k8s.io/client-go/kubernetes"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
)

const (
	// NodeUnreachablePodReason is the reason on a pod when its state cannot be confirmed as kubelet is unresponsive
	// on the node it is (was) running.
	NodeUnreachablePodReason = "NodeLost"
	// NodeUnreachablePodMessage is the message on a pod when its state cannot be confirmed as kubelet is unresponsive
	// on the node it is (was) running.
	NodeUnreachablePodMessage = "Node %v which was running pod %v is unresponsive"
)

// GetHostname returns OS's hostname if 'hostnameOverride' is empty; otherwise, return 'hostnameOverride'.
func GetHostname(hostnameOverride string) (string, error) {
	hostName := hostnameOverride
	if len(hostName) == 0 {
		nodeName, err := os.Hostname()
		if err != nil {
			return "", fmt.Errorf("couldn't determine hostname: %v", err)
		}
		hostName = nodeName
	}

	// Trim whitespaces first to avoid getting an empty hostname
	// For linux, the hostname is read from file /proc/sys/kernel/hostname directly
	hostName = strings.TrimSpace(hostName)
	if len(hostName) == 0 {
		return "", fmt.Errorf("empty hostname is invalid")
	}
	return strings.ToLower(hostName), nil
}

// NoMatchError is a typed implementation of the error interface. It indicates a failure to get a matching Node.
type NoMatchError struct {
	addresses []v1.NodeAddress
}

// Error is the implementation of the conventional interface for
// representing an error condition, with the nil value representing no error.
func (e *NoMatchError) Error() string {
	return fmt.Sprintf("no preferred addresses found; known addresses: %v", e.addresses)
}

// GetPreferredNodeAddress returns the address of the provided node, using the provided preference order.
// If none of the preferred address types are found, an error is returned.
func GetPreferredNodeAddress(node *v1.Node, preferredAddressTypes []v1.NodeAddressType) (string, error) {
	for _, addressType := range preferredAddressTypes {
		for _, address := range node.Status.Addresses {
			if address.Type == addressType {
				return address.Address, nil
			}
		}
	}
	return "", &NoMatchError{addresses: node.Status.Addresses}
}

// GetNodeHostIP returns the provided node's IP, based on the priority:
// 1. NodeInternalIP
// 2. NodeExternalIP
func GetNodeHostIP(node *v1.Node) (net.IP, error) {
	addresses := node.Status.Addresses
	addressMap := make(map[v1.NodeAddressType][]v1.NodeAddress)
	for i := range addresses {
		addressMap[addresses[i].Type] = append(addressMap[addresses[i].Type], addresses[i])
	}
	if addresses, ok := addressMap[v1.NodeInternalIP]; ok {
		return net.ParseIP(addresses[0].Address), nil
	}
	if addresses, ok := addressMap[v1.NodeExternalIP]; ok {
		return net.ParseIP(addresses[0].Address), nil
	}
	return nil, fmt.Errorf("host IP unknown; known addresses: %v", addresses)
}

// GetNodeIP returns the ip of node with the provided hostname
// If required, wait for the node to be defined.
func GetNodeIP(client clientset.Interface, hostname string) net.IP {
	var nodeIP net.IP
	backoff := wait.Backoff{
		Steps:    5,
		Duration: 1 * time.Second,
		Factor:   2.0,
		Jitter:   0.2,
	}

	err := wait.ExponentialBackoff(backoff, func() (bool, error) {
		node, err := client.CoreV1().Nodes().Get(hostname, metav1.GetOptions{})
		if err != nil {
			klog.Errorf("Failed to retrieve node info: %v", err)
			return false, nil
		}
		nodeIP, err = GetNodeHostIP(node)
		if err != nil {
			klog.Errorf("Failed to retrieve node IP: %v", err)
			return false, err
		}
		return true, nil
	})
	if err == nil {
		klog.Infof("Successfully retrieved node IP: %v", nodeIP)
	}
	return nodeIP
}

// GetZoneKey is a helper function that builds a string identifier that is unique per failure-zone;
// it returns empty-string for no zone.
func GetZoneKey(node *v1.Node) string {
	labels := node.Labels
	if labels == nil {
		return ""
	}

	region, _ := labels[v1.LabelZoneRegion]
	failureDomain, _ := labels[v1.LabelZoneFailureDomain]

	if region == "" && failureDomain == "" {
		return ""
	}

	// We include the null character just in case region or failureDomain has a colon
	// (We do assume there's no null characters in a region or failureDomain)
	// As a nice side-benefit, the null character is not printed by fmt.Print or glog
	return region + ":\x00:" + failureDomain
}

// SetNodeCondition updates specific node condition with patch operation.
func SetNodeCondition(c clientset.Interface, node types.NodeName, condition v1.NodeCondition) error {
	generatePatch := func(condition v1.NodeCondition) ([]byte, error) {
		raw, err := json.Marshal(&[]v1.NodeCondition{condition})
		if err != nil {
			return nil, err
		}
		return []byte(fmt.Sprintf(`{"status":{"conditions":%s}}`, raw)), nil
	}
	condition.LastHeartbeatTime = metav1.NewTime(time.Now())
	patch, err := generatePatch(condition)
	if err != nil {
		return nil
	}
	_, err = c.CoreV1().Nodes().PatchStatus(string(node), patch)
	return err
}

// PatchNodeCIDR patches the specified node's CIDR to the given value.
func PatchNodeCIDR(c clientset.Interface, node types.NodeName, cidr string) error {
	raw, err := json.Marshal(cidr)
	if err != nil {
		return fmt.Errorf("failed to json.Marshal CIDR: %v", err)
	}

	patchBytes := []byte(fmt.Sprintf(`{"spec":{"podCIDR":%s}}`, raw))

	if _, err := c.CoreV1().Nodes().Patch(string(node), types.StrategicMergePatchType, patchBytes); err != nil {
		return fmt.Errorf("failed to patch node CIDR: %v", err)
	}
	return nil
}

// PatchNodeStatus patches node status.
func PatchNodeStatus(c v1core.CoreV1Interface, nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) (*v1.Node, []byte, error) {
	patchBytes, err := preparePatchBytesforNodeStatus(nodeName, oldNode, newNode)
	if err != nil {
		return nil, nil, err
	}

	updatedNode, err := c.Nodes().Patch(string(nodeName), types.StrategicMergePatchType, patchBytes, "status")
	if err != nil {
		return nil, nil, fmt.Errorf("failed to patch status %q for node %q: %v", patchBytes, nodeName, err)
	}
	return updatedNode, patchBytes, nil
}

func preparePatchBytesforNodeStatus(nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) ([]byte, error) {
	oldData, err := json.Marshal(oldNode)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal oldData for node %q: %v", nodeName, err)
	}

	// Reset spec to make sure only patch for Status or ObjectMeta is generated.
	// Note that we don't reset ObjectMeta here, because:
	// 1. This aligns with Nodes().UpdateStatus().
	// 2. Some component does use this to update node annotations.
	newNode.Spec = oldNode.Spec
	newData, err := json.Marshal(newNode)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal newData for node %q: %v", nodeName, err)
	}

	patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
	if err != nil {
		return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for node %q: %v", nodeName, err)
	}
	return patchBytes, nil
}
<|endoftext|>


<commit_before>package handlers

import (
	"os"
	"os/exec"
	"testing"

	"github.com/anonx/sunplate/command"
)

func TestStart(t *testing.T) {
	Start(command.Data{
		"--input":   "./testdata/controllers",
		"--output":  "./testdata/assets/handlers",
		"--package": "handlers",
	})

	cmd := exec.Command("go", "build", "./testdata/assets/handlers")
	cmd.Stderr = os.Stderr // Show the output of the program we run.
	if err := cmd.Run(); err != nil {
		t.Errorf(`There are problems with generated handlers, error: "%s".`, err)
	}

	// Remove the directory we have created.
	os.RemoveAll("./testdata/assets")
}
<commit_msg>Download dependencies when testing generated handlers<commit_after>package handlers

import (
	"os"
	"os/exec"
	"testing"

	"github.com/anonx/sunplate/command"
)

func TestStart(t *testing.T) {
	Start(command.Data{
		"--input":   "./testdata/controllers",
		"--output":  "./testdata/assets/handlers",
		"--package": "handlers",
	})

	cmd := exec.Command("go", "get", "-t", "./testdata/assets/handlers/...")
	cmd.Stderr = os.Stderr // Show the output of the program we run.
	if err := cmd.Run(); err != nil {
		t.Errorf(`There are problems with generated handlers, error: "%s".`, err)
	}

	// Remove the directory we have created.
	os.RemoveAll("./testdata/assets")
}
<|endoftext|>


<commit_before>package citrixadc

import (
	"github.com/chiradeep/go-nitro/config/basic"

	"github.com/chiradeep/go-nitro/netscaler"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"fmt"
	"log"
)

func resourceCitrixAdcServer() *schema.Resource {
	return &schema.Resource{
		SchemaVersion: 1,
		Create:        createServerFunc,
		Read:          readServerFunc,
		Update:        updateServerFunc,
		Delete:        deleteServerFunc,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},
		Schema: map[string]*schema.Schema{
			"comment": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"delay": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},
			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"domainresolvenow": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},
			"domainresolveretry": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},
			"graceful": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"internal": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},
			"ipaddress": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"ipv6address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"newname": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"querytype": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"state": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"td": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"translationip": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"translationmask": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
		},
	}
}

func createServerFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  netscaler-provider: In createServerFunc")
	client := meta.(*NetScalerNitroClient).client
	var serverName string
	if v, ok := d.GetOk("name"); ok {
		serverName = v.(string)
	} else {
		serverName = resource.PrefixedUniqueId("tf-server-")
		d.Set("name", serverName)
	}
	server := basic.Server{
		Comment:            d.Get("comment").(string),
		Domain:             d.Get("domain").(string),
		Domainresolvenow:   d.Get("domainresolvenow").(bool),
		Domainresolveretry: d.Get("domainresolveretry").(int),
		Internal:           d.Get("internal").(bool),
		Ipaddress:          d.Get("ipaddress").(string),
		Ipv6address:        d.Get("ipv6address").(string),
		Name:               d.Get("name").(string),
		Newname:            d.Get("newname").(string),
		Querytype:          d.Get("querytype").(string),
		State:              d.Get("state").(string),
		Td:                 d.Get("td").(int),
		Translationip:      d.Get("translationip").(string),
		Translationmask:    d.Get("translationmask").(string),
	}

	_, err := client.AddResource(netscaler.Server.Type(), serverName, &server)
	if err != nil {
		return err
	}

	d.SetId(serverName)

	err = readServerFunc(d, meta)
	if err != nil {
		log.Printf("[ERROR] netscaler-provider: ?? we just created this server but we can't read it ?? %s", serverName)
		return nil
	}
	return nil
}

func readServerFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] netscaler-provider:  In readServerFunc")
	client := meta.(*NetScalerNitroClient).client
	serverName := d.Id()
	log.Printf("[DEBUG] netscaler-provider: Reading server state %s", serverName)
	data, err := client.FindResource(netscaler.Server.Type(), serverName)
	if err != nil {
		log.Printf("[WARN] netscaler-provider: Clearing server state %s", serverName)
		d.SetId("")
		return nil
	}
	d.Set("name", data["name"])
	d.Set("comment", data["comment"])
	d.Set("domain", data["domain"])
	d.Set("domainresolvenow", data["domainresolvenow"])
	d.Set("domainresolveretry", data["domainresolveretry"])
	d.Set("internal", data["internal"])
	d.Set("ipaddress", data["ipaddress"])
	d.Set("ipv6address", data["ipv6address"])
	d.Set("name", data["name"])
	d.Set("newname", data["newname"])
	d.Set("querytype", data["querytype"])
	d.Set("state", data["state"])
	d.Set("td", data["td"])
	d.Set("translationip", data["translationip"])
	d.Set("translationmask", data["translationmask"])

	return nil

}

func updateServerFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  netscaler-provider: In updateServerFunc")
	client := meta.(*NetScalerNitroClient).client
	serverName := d.Get("name").(string)

	server := basic.Server{
		Name: d.Get("name").(string),
	}

	stateChange := false

	hasChange := false

	if d.HasChange("comment") {
		log.Printf("[DEBUG]  netscaler-provider: Comment has changed for server %s, starting update", serverName)
		server.Comment = d.Get("comment").(string)
		hasChange = true
	}
	if d.HasChange("domain") {
		log.Printf("[DEBUG]  netscaler-provider: Domain has changed for server %s, starting update", serverName)
		server.Domain = d.Get("domain").(string)
		hasChange = true
	}
	if d.HasChange("domainresolvenow") {
		log.Printf("[DEBUG]  netscaler-provider: Domainresolvenow has changed for server %s, starting update", serverName)
		server.Domainresolvenow = d.Get("domainresolvenow").(bool)
		hasChange = true
	}
	if d.HasChange("domainresolveretry") {
		log.Printf("[DEBUG]  netscaler-provider: Domainresolveretry has changed for server %s, starting update", serverName)
		server.Domainresolveretry = d.Get("domainresolveretry").(int)
		hasChange = true
	}
	if d.HasChange("internal") {
		log.Printf("[DEBUG]  netscaler-provider: Internal has changed for server %s, starting update", serverName)
		server.Internal = d.Get("internal").(bool)
		hasChange = true
	}
	if d.HasChange("ipaddress") {
		log.Printf("[DEBUG]  netscaler-provider: Ipaddress has changed for server %s, starting update", serverName)
		server.Ipaddress = d.Get("ipaddress").(string)
		hasChange = true
	}
	if d.HasChange("ipv6address") {
		log.Printf("[DEBUG]  netscaler-provider: Ipv6address has changed for server %s, starting update", serverName)
		server.Ipv6address = d.Get("ipv6address").(string)
		hasChange = true
	}
	if d.HasChange("name") {
		log.Printf("[DEBUG]  netscaler-provider: Name has changed for server %s, starting update", serverName)
		server.Name = d.Get("name").(string)
		hasChange = true
	}
	if d.HasChange("newname") {
		log.Printf("[DEBUG]  netscaler-provider: Newname has changed for server %s, starting update", serverName)
		server.Newname = d.Get("newname").(string)
		hasChange = true
	}
	if d.HasChange("querytype") {
		log.Printf("[DEBUG]  netscaler-provider: Querytype has changed for server %s, starting update", serverName)
		server.Querytype = d.Get("querytype").(string)
		hasChange = true
	}
	if d.HasChange("state") {
		log.Printf("[DEBUG]  netscaler-provider: State has changed for server %s, starting update", serverName)
		stateChange = true
	}
	if d.HasChange("td") {
		log.Printf("[DEBUG]  netscaler-provider: Td has changed for server %s, starting update", serverName)
		server.Td = d.Get("td").(int)
		hasChange = true
	}
	if d.HasChange("translationip") {
		log.Printf("[DEBUG]  netscaler-provider: Translationip has changed for server %s, starting update", serverName)
		server.Translationip = d.Get("translationip").(string)
		hasChange = true
	}
	if d.HasChange("translationmask") {
		log.Printf("[DEBUG]  netscaler-provider: Translationmask has changed for server %s, starting update", serverName)
		server.Translationmask = d.Get("translationmask").(string)
		hasChange = true
	}

	if hasChange {
		_, err := client.UpdateResource(netscaler.Server.Type(), serverName, &server)
		if err != nil {
			return fmt.Errorf("Error updating server %s", serverName)
		}
	}
	if stateChange {
		err := doServerStateChange(d, client)
		if err != nil {
			return fmt.Errorf("Error enabling/disabling server %s", serverName)
		}
	}
	return readServerFunc(d, meta)
}

func deleteServerFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  netscaler-provider: In deleteServerFunc")
	client := meta.(*NetScalerNitroClient).client
	serverName := d.Id()
	err := client.DeleteResource(netscaler.Server.Type(), serverName)
	if err != nil {
		return err
	}

	d.SetId("")

	return nil
}

func doServerStateChange(d *schema.ResourceData, client *netscaler.NitroClient) error {
	log.Printf("[DEBUG]  netscaler-provider: In doServerStateChange")

	// We need a new instance of the struct since
	// ActOnResource will fail if we put in superfluous attributes
	server := basic.Server{
		Name: d.Get("name").(string),
	}

	newstate := d.Get("state")

	// Enable action
	if newstate == "ENABLED" {
		err := client.ActOnResource(netscaler.Server.Type(), server, "enable")
		if err != nil {
			return err
		}
	} else if newstate == "DISABLED" {
		// Add attributes relevant to the disable operation
		server.Delay = d.Get("delay").(int)
		server.Graceful = d.Get("graceful").(string)
		err := client.ActOnResource(netscaler.Server.Type(), server, "disable")
		if err != nil {
			return err
		}
	} else {
		return fmt.Errorf("\"%s\" is not a valid state. Use (\"ENABLED\", \"DISABLED\").", newstate)
	}

	return nil
}
<commit_msg>Remove newname from server resource<commit_after>package citrixadc

import (
	"github.com/chiradeep/go-nitro/config/basic"

	"github.com/chiradeep/go-nitro/netscaler"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"fmt"
	"log"
)

func resourceCitrixAdcServer() *schema.Resource {
	return &schema.Resource{
		SchemaVersion: 1,
		Create:        createServerFunc,
		Read:          readServerFunc,
		Update:        updateServerFunc,
		Delete:        deleteServerFunc,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},
		Schema: map[string]*schema.Schema{
			"comment": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"delay": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},
			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"domainresolvenow": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},
			"domainresolveretry": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},
			"graceful": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"internal": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},
			"ipaddress": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"ipv6address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"querytype": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"state": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"td": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"translationip": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"translationmask": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
		},
	}
}

func createServerFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  netscaler-provider: In createServerFunc")
	client := meta.(*NetScalerNitroClient).client
	var serverName string
	if v, ok := d.GetOk("name"); ok {
		serverName = v.(string)
	} else {
		serverName = resource.PrefixedUniqueId("tf-server-")
		d.Set("name", serverName)
	}
	server := basic.Server{
		Comment:            d.Get("comment").(string),
		Domain:             d.Get("domain").(string),
		Domainresolvenow:   d.Get("domainresolvenow").(bool),
		Domainresolveretry: d.Get("domainresolveretry").(int),
		Internal:           d.Get("internal").(bool),
		Ipaddress:          d.Get("ipaddress").(string),
		Ipv6address:        d.Get("ipv6address").(string),
		Name:               d.Get("name").(string),
		Querytype:          d.Get("querytype").(string),
		State:              d.Get("state").(string),
		Td:                 d.Get("td").(int),
		Translationip:      d.Get("translationip").(string),
		Translationmask:    d.Get("translationmask").(string),
	}

	_, err := client.AddResource(netscaler.Server.Type(), serverName, &server)
	if err != nil {
		return err
	}

	d.SetId(serverName)

	err = readServerFunc(d, meta)
	if err != nil {
		log.Printf("[ERROR] netscaler-provider: ?? we just created this server but we can't read it ?? %s", serverName)
		return nil
	}
	return nil
}

func readServerFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] netscaler-provider:  In readServerFunc")
	client := meta.(*NetScalerNitroClient).client
	serverName := d.Id()
	log.Printf("[DEBUG] netscaler-provider: Reading server state %s", serverName)
	data, err := client.FindResource(netscaler.Server.Type(), serverName)
	if err != nil {
		log.Printf("[WARN] netscaler-provider: Clearing server state %s", serverName)
		d.SetId("")
		return nil
	}
	d.Set("name", data["name"])
	d.Set("comment", data["comment"])
	d.Set("domain", data["domain"])
	d.Set("domainresolvenow", data["domainresolvenow"])
	d.Set("domainresolveretry", data["domainresolveretry"])
	d.Set("internal", data["internal"])
	d.Set("ipaddress", data["ipaddress"])
	d.Set("ipv6address", data["ipv6address"])
	d.Set("name", data["name"])
	d.Set("querytype", data["querytype"])
	d.Set("state", data["state"])
	d.Set("td", data["td"])
	d.Set("translationip", data["translationip"])
	d.Set("translationmask", data["translationmask"])

	return nil

}

func updateServerFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  netscaler-provider: In updateServerFunc")
	client := meta.(*NetScalerNitroClient).client
	serverName := d.Get("name").(string)

	server := basic.Server{
		Name: d.Get("name").(string),
	}

	stateChange := false

	hasChange := false

	if d.HasChange("comment") {
		log.Printf("[DEBUG]  netscaler-provider: Comment has changed for server %s, starting update", serverName)
		server.Comment = d.Get("comment").(string)
		hasChange = true
	}
	if d.HasChange("domain") {
		log.Printf("[DEBUG]  netscaler-provider: Domain has changed for server %s, starting update", serverName)
		server.Domain = d.Get("domain").(string)
		hasChange = true
	}
	if d.HasChange("domainresolvenow") {
		log.Printf("[DEBUG]  netscaler-provider: Domainresolvenow has changed for server %s, starting update", serverName)
		server.Domainresolvenow = d.Get("domainresolvenow").(bool)
		hasChange = true
	}
	if d.HasChange("domainresolveretry") {
		log.Printf("[DEBUG]  netscaler-provider: Domainresolveretry has changed for server %s, starting update", serverName)
		server.Domainresolveretry = d.Get("domainresolveretry").(int)
		hasChange = true
	}
	if d.HasChange("internal") {
		log.Printf("[DEBUG]  netscaler-provider: Internal has changed for server %s, starting update", serverName)
		server.Internal = d.Get("internal").(bool)
		hasChange = true
	}
	if d.HasChange("ipaddress") {
		log.Printf("[DEBUG]  netscaler-provider: Ipaddress has changed for server %s, starting update", serverName)
		server.Ipaddress = d.Get("ipaddress").(string)
		hasChange = true
	}
	if d.HasChange("ipv6address") {
		log.Printf("[DEBUG]  netscaler-provider: Ipv6address has changed for server %s, starting update", serverName)
		server.Ipv6address = d.Get("ipv6address").(string)
		hasChange = true
	}
	if d.HasChange("name") {
		log.Printf("[DEBUG]  netscaler-provider: Name has changed for server %s, starting update", serverName)
		server.Name = d.Get("name").(string)
		hasChange = true
	}
	if d.HasChange("querytype") {
		log.Printf("[DEBUG]  netscaler-provider: Querytype has changed for server %s, starting update", serverName)
		server.Querytype = d.Get("querytype").(string)
		hasChange = true
	}
	if d.HasChange("state") {
		log.Printf("[DEBUG]  netscaler-provider: State has changed for server %s, starting update", serverName)
		stateChange = true
	}
	if d.HasChange("td") {
		log.Printf("[DEBUG]  netscaler-provider: Td has changed for server %s, starting update", serverName)
		server.Td = d.Get("td").(int)
		hasChange = true
	}
	if d.HasChange("translationip") {
		log.Printf("[DEBUG]  netscaler-provider: Translationip has changed for server %s, starting update", serverName)
		server.Translationip = d.Get("translationip").(string)
		hasChange = true
	}
	if d.HasChange("translationmask") {
		log.Printf("[DEBUG]  netscaler-provider: Translationmask has changed for server %s, starting update", serverName)
		server.Translationmask = d.Get("translationmask").(string)
		hasChange = true
	}

	if hasChange {
		_, err := client.UpdateResource(netscaler.Server.Type(), serverName, &server)
		if err != nil {
			return fmt.Errorf("Error updating server %s", serverName)
		}
	}
	if stateChange {
		err := doServerStateChange(d, client)
		if err != nil {
			return fmt.Errorf("Error enabling/disabling server %s", serverName)
		}
	}
	return readServerFunc(d, meta)
}

func deleteServerFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  netscaler-provider: In deleteServerFunc")
	client := meta.(*NetScalerNitroClient).client
	serverName := d.Id()
	err := client.DeleteResource(netscaler.Server.Type(), serverName)
	if err != nil {
		return err
	}

	d.SetId("")

	return nil
}

func doServerStateChange(d *schema.ResourceData, client *netscaler.NitroClient) error {
	log.Printf("[DEBUG]  netscaler-provider: In doServerStateChange")

	// We need a new instance of the struct since
	// ActOnResource will fail if we put in superfluous attributes
	server := basic.Server{
		Name: d.Get("name").(string),
	}

	newstate := d.Get("state")

	// Enable action
	if newstate == "ENABLED" {
		err := client.ActOnResource(netscaler.Server.Type(), server, "enable")
		if err != nil {
			return err
		}
	} else if newstate == "DISABLED" {
		// Add attributes relevant to the disable operation
		server.Delay = d.Get("delay").(int)
		server.Graceful = d.Get("graceful").(string)
		err := client.ActOnResource(netscaler.Server.Type(), server, "disable")
		if err != nil {
			return err
		}
	} else {
		return fmt.Errorf("\"%s\" is not a valid state. Use (\"ENABLED\", \"DISABLED\").", newstate)
	}

	return nil
}
<|endoftext|>


<commit_before>package http_response

import (
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

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

// HTTPResponse struct
type HTTPResponse struct {
	Address             string
	Body                string
	Method              string
	ResponseTimeout     internal.Duration
	Headers             map[string]string
	FollowRedirects     bool
	ResponseStringMatch string

	// Path to CA file
	SSLCA string `toml:"ssl_ca"`
	// Path to host cert file
	SSLCert string `toml:"ssl_cert"`
	// Path to cert key file
	SSLKey string `toml:"ssl_key"`
	// Use SSL but skip chain & host verification
	InsecureSkipVerify bool

	compiledStringMatch *regexp.Regexp
	client              *http.Client
}

// Description returns the plugin Description
func (h *HTTPResponse) Description() string {
	return "HTTP/HTTPS request given an address a method and a timeout"
}

var sampleConfig = `
  ## Server address (default http://localhost)
  # address = "http://localhost"

  ## Set response_timeout (default 5 seconds)
  # response_timeout = "5s"

  ## HTTP Request Method
  # method = "GET"

  ## Whether to follow redirects from the server (defaults to false)
  # follow_redirects = false

  ## Optional HTTP Request Body
  # body = '''
  # {'fake':'data'}
  # '''

  ## Optional substring or regex match in body of the response
  # response_string_match = "\"service_status\": \"up\""
  # response_string_match = "ok"
  # response_string_match = "\".*_status\".?:.?\"up\""

  ## Optional SSL Config
  # ssl_ca = "/etc/telegraf/ca.pem"
  # ssl_cert = "/etc/telegraf/cert.pem"
  # ssl_key = "/etc/telegraf/key.pem"
  ## Use SSL but skip chain & host verification
  # insecure_skip_verify = false

  ## HTTP Request Headers (all values must be strings)
  # [inputs.http_response.headers]
  #   Host = "github.com"
`

// SampleConfig returns the plugin SampleConfig
func (h *HTTPResponse) SampleConfig() string {
	return sampleConfig
}

// ErrRedirectAttempted indicates that a redirect occurred
var ErrRedirectAttempted = errors.New("redirect")

// CreateHttpClient creates an http client which will timeout at the specified
// timeout period and can follow redirects if specified
func (h *HTTPResponse) createHttpClient() (*http.Client, error) {
	tlsCfg, err := internal.GetTLSConfig(
		h.SSLCert, h.SSLKey, h.SSLCA, h.InsecureSkipVerify)
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Transport: &http.Transport{
			Proxy:             http.ProxyFromEnvironment,
			DisableKeepAlives: true,
			TLSClientConfig:   tlsCfg,
		},
		Timeout: h.ResponseTimeout.Duration,
	}

	if h.FollowRedirects == false {
		client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
			return ErrRedirectAttempted
		}
	}
	return client, nil
}

// HTTPGather gathers all fields and returns any errors it encounters
func (h *HTTPResponse) httpGather() (map[string]interface{}, error) {
	// Prepare fields
	fields := make(map[string]interface{})

	var body io.Reader
	if h.Body != "" {
		body = strings.NewReader(h.Body)
	}
	request, err := http.NewRequest(h.Method, h.Address, body)
	if err != nil {
		return nil, err
	}

	for key, val := range h.Headers {
		request.Header.Add(key, val)
		if key == "Host" {
			request.Host = val
		}
	}

	// Start Timer
	start := time.Now()
	resp, err := h.client.Do(request)

	if err != nil {
		if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
			fields["result_type"] = "timeout"
			return fields, nil
		}
		fields["result_type"] = "connection_failed"
		if h.FollowRedirects {
			return fields, nil
		}
		if urlError, ok := err.(*url.Error); ok &&
			urlError.Err == ErrRedirectAttempted {
			err = nil
		} else {
			return fields, nil
		}
	}
	defer func() {
		io.Copy(ioutil.Discard, resp.Body)
		resp.Body.Close()
	}()

	fields["response_time"] = time.Since(start).Seconds()
	fields["http_response_code"] = resp.StatusCode

	// Check the response for a regex match.
	if h.ResponseStringMatch != "" {

		// Compile once and reuse
		if h.compiledStringMatch == nil {
			h.compiledStringMatch = regexp.MustCompile(h.ResponseStringMatch)
			if err != nil {
				log.Printf("E! Failed to compile regular expression %s : %s", h.ResponseStringMatch, err)
				fields["result_type"] = "response_string_mismatch"
				return fields, nil
			}
		}

		bodyBytes, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Printf("E! Failed to read body of HTTP Response : %s", err)
			fields["result_type"] = "response_string_mismatch"
			fields["response_string_match"] = 0
			return fields, nil
		}

		if h.compiledStringMatch.Match(bodyBytes) {
			fields["result_type"] = "success"
			fields["response_string_match"] = 1
		} else {
			fields["result_type"] = "response_string_mismatch"
			fields["response_string_match"] = 0
		}
	} else {
		fields["result_type"] = "success"
	}

	return fields, nil
}

// Gather gets all metric fields and tags and returns any errors it encounters
func (h *HTTPResponse) Gather(acc telegraf.Accumulator) error {
	// Set default values
	if h.ResponseTimeout.Duration < time.Second {
		h.ResponseTimeout.Duration = time.Second * 5
	}
	// Check send and expected string
	if h.Method == "" {
		h.Method = "GET"
	}
	if h.Address == "" {
		h.Address = "http://localhost"
	}
	addr, err := url.Parse(h.Address)
	if err != nil {
		return err
	}
	if addr.Scheme != "http" && addr.Scheme != "https" {
		return errors.New("Only http and https are supported")
	}
	// Prepare data
	tags := map[string]string{"server": h.Address, "method": h.Method}
	var fields map[string]interface{}

	if h.client == nil {
		client, err := h.createHttpClient()
		if err != nil {
			return err
		}
		h.client = client
	}

	// Gather data
	fields, err = h.httpGather()
	if err != nil {
		return err
	}
	// Add metrics
	acc.AddFields("http_response", fields, tags)
	return nil
}

func init() {
	inputs.Add("http_response", func() telegraf.Input {
		return &HTTPResponse{}
	})
}
<commit_msg>Add ability to override proxy from environment in http response (#3626)<commit_after>package http_response

import (
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

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

// HTTPResponse struct
type HTTPResponse struct {
	Address             string
	Proxy               string
	Body                string
	Method              string
	ResponseTimeout     internal.Duration
	Headers             map[string]string
	FollowRedirects     bool
	ResponseStringMatch string

	// Path to CA file
	SSLCA string `toml:"ssl_ca"`
	// Path to host cert file
	SSLCert string `toml:"ssl_cert"`
	// Path to cert key file
	SSLKey string `toml:"ssl_key"`
	// Use SSL but skip chain & host verification
	InsecureSkipVerify bool

	compiledStringMatch *regexp.Regexp
	client              *http.Client
}

// Description returns the plugin Description
func (h *HTTPResponse) Description() string {
	return "HTTP/HTTPS request given an address a method and a timeout"
}

var sampleConfig = `
  ## Server address (default http://localhost)
  # address = "http://localhost"

  ## Set http_proxy (telegraf uses the system wide proxy settings if it's is not set)
  # http_proxy = "http://localhost:8888"

  ## Set response_timeout (default 5 seconds)
  # response_timeout = "5s"

  ## HTTP Request Method
  # method = "GET"

  ## Whether to follow redirects from the server (defaults to false)
  # follow_redirects = false

  ## Optional HTTP Request Body
  # body = '''
  # {'fake':'data'}
  # '''

  ## Optional substring or regex match in body of the response
  # response_string_match = "\"service_status\": \"up\""
  # response_string_match = "ok"
  # response_string_match = "\".*_status\".?:.?\"up\""

  ## Optional SSL Config
  # ssl_ca = "/etc/telegraf/ca.pem"
  # ssl_cert = "/etc/telegraf/cert.pem"
  # ssl_key = "/etc/telegraf/key.pem"
  ## Use SSL but skip chain & host verification
  # insecure_skip_verify = false

  ## HTTP Request Headers (all values must be strings)
  # [inputs.http_response.headers]
  #   Host = "github.com"
`

// SampleConfig returns the plugin SampleConfig
func (h *HTTPResponse) SampleConfig() string {
	return sampleConfig
}

// ErrRedirectAttempted indicates that a redirect occurred
var ErrRedirectAttempted = errors.New("redirect")

// Set the proxy. A configured proxy overwrites the system wide proxy.
func getProxyFunc(http_proxy string) func(*http.Request) (*url.URL, error) {
	if http_proxy == "" {
		return http.ProxyFromEnvironment
	}
	proxyURL, err := url.Parse(http_proxy)
	if err != nil {
		return func(_ *http.Request) (*url.URL, error) {
			return nil, errors.New("bad proxy: " + err.Error())
		}
	}
	return func(r *http.Request) (*url.URL, error) {
		return proxyURL, nil
	}
}

// CreateHttpClient creates an http client which will timeout at the specified
// timeout period and can follow redirects if specified
func (h *HTTPResponse) createHttpClient() (*http.Client, error) {
	tlsCfg, err := internal.GetTLSConfig(
		h.SSLCert, h.SSLKey, h.SSLCA, h.InsecureSkipVerify)
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Transport: &http.Transport{
			Proxy:             getProxyFunc(h.Proxy),
			DisableKeepAlives: true,
			TLSClientConfig:   tlsCfg,
		},
		Timeout: h.ResponseTimeout.Duration,
	}

	if h.FollowRedirects == false {
		client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
			return ErrRedirectAttempted
		}
	}
	return client, nil
}

// HTTPGather gathers all fields and returns any errors it encounters
func (h *HTTPResponse) httpGather() (map[string]interface{}, error) {
	// Prepare fields
	fields := make(map[string]interface{})

	var body io.Reader
	if h.Body != "" {
		body = strings.NewReader(h.Body)
	}
	request, err := http.NewRequest(h.Method, h.Address, body)
	if err != nil {
		return nil, err
	}

	for key, val := range h.Headers {
		request.Header.Add(key, val)
		if key == "Host" {
			request.Host = val
		}
	}

	// Start Timer
	start := time.Now()
	resp, err := h.client.Do(request)

	if err != nil {
		if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
			fields["result_type"] = "timeout"
			return fields, nil
		}
		fields["result_type"] = "connection_failed"
		if h.FollowRedirects {
			return fields, nil
		}
		if urlError, ok := err.(*url.Error); ok &&
			urlError.Err == ErrRedirectAttempted {
			err = nil
		} else {
			return fields, nil
		}
	}
	defer func() {
		io.Copy(ioutil.Discard, resp.Body)
		resp.Body.Close()
	}()

	fields["response_time"] = time.Since(start).Seconds()
	fields["http_response_code"] = resp.StatusCode

	// Check the response for a regex match.
	if h.ResponseStringMatch != "" {

		// Compile once and reuse
		if h.compiledStringMatch == nil {
			h.compiledStringMatch = regexp.MustCompile(h.ResponseStringMatch)
			if err != nil {
				log.Printf("E! Failed to compile regular expression %s : %s", h.ResponseStringMatch, err)
				fields["result_type"] = "response_string_mismatch"
				return fields, nil
			}
		}

		bodyBytes, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Printf("E! Failed to read body of HTTP Response : %s", err)
			fields["result_type"] = "response_string_mismatch"
			fields["response_string_match"] = 0
			return fields, nil
		}

		if h.compiledStringMatch.Match(bodyBytes) {
			fields["result_type"] = "success"
			fields["response_string_match"] = 1
		} else {
			fields["result_type"] = "response_string_mismatch"
			fields["response_string_match"] = 0
		}
	} else {
		fields["result_type"] = "success"
	}

	return fields, nil
}

// Gather gets all metric fields and tags and returns any errors it encounters
func (h *HTTPResponse) Gather(acc telegraf.Accumulator) error {
	// Set default values
	if h.ResponseTimeout.Duration < time.Second {
		h.ResponseTimeout.Duration = time.Second * 5
	}
	// Check send and expected string
	if h.Method == "" {
		h.Method = "GET"
	}
	if h.Address == "" {
		h.Address = "http://localhost"
	}
	addr, err := url.Parse(h.Address)
	if err != nil {
		return err
	}
	if addr.Scheme != "http" && addr.Scheme != "https" {
		return errors.New("Only http and https are supported")
	}
	// Prepare data
	tags := map[string]string{"server": h.Address, "method": h.Method}
	var fields map[string]interface{}

	if h.client == nil {
		client, err := h.createHttpClient()
		if err != nil {
			return err
		}
		h.client = client
	}

	// Gather data
	fields, err = h.httpGather()
	if err != nil {
		return err
	}
	// Add metrics
	acc.AddFields("http_response", fields, tags)
	return nil
}

func init() {
	inputs.Add("http_response", func() telegraf.Input {
		return &HTTPResponse{}
	})
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"strings"

	"google.golang.org/api/cloudbilling/v1"
	"google.golang.org/api/cloudresourcemanager/v1"
)

func GetProjectCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	// NOTE: asset.name should use the project number, but we use project_id b/c
	// the number is computed server-side.
	name, err := assetName(d, config, "//cloudresourcemanager.googleapis.com/projects/{{project_id_or_project}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetProjectApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "cloudresourcemanager.googleapis.com/Project",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
				DiscoveryName:        "Project",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetProjectApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	pid := d.Get("project_id").(string)

	project := &cloudresourcemanager.Project{
		ProjectId: pid,
		Name:      d.Get("name").(string),
	}

	if err := getParentResourceId(d, project); err != nil {
		return nil, err
	}

	if _, ok := d.GetOk("labels"); ok {
		project.Labels = expandLabels(d)
	}

	return jsonMap(project)
}

func getParentResourceId(d TerraformResourceData, p *cloudresourcemanager.Project) error {
	orgId := d.Get("org_id").(string)
	folderId := d.Get("folder_id").(string)

	if orgId != "" && folderId != "" {
		return fmt.Errorf("'org_id' and 'folder_id' cannot be both set.")
	}

	if orgId != "" {
		p.Parent = &cloudresourcemanager.ResourceId{
			Id:   orgId,
			Type: "organization",
		}
	}

	if folderId != "" {
		p.Parent = &cloudresourcemanager.ResourceId{
			Id:   strings.TrimPrefix(folderId, "folders/"),
			Type: "folder",
		}
	}

	return nil
}

func GetProjectBillingInfoCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	name, err := assetName(d, config, "//cloudbilling.googleapis.com/projects/{{project_id_or_project}}/billingInfo")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetProjectBillingInfoApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "cloudbilling.googleapis.com/ProjectBillingInfo",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/cloudbilling/v1/rest",
				DiscoveryName:        "ProjectBillingInfo",
				Data:                 obj,
			}},
		}, nil
	} else {
		return []Asset{}, err
	}
}

func GetProjectBillingInfoApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	if _, ok := d.GetOk("billing_account"); !ok {
		// TODO: If the project already exists, we could ask the API about it's
		// billing info here.
		return nil, ErrNoConversion
	}

	ba := &cloudbilling.ProjectBillingInfo{
		BillingAccountName: fmt.Sprintf("billingAccounts/%s", d.Get("billing_account")),
		Name:               fmt.Sprintf("projects/%s/billingInfo", d.Get("project_id")),
		ProjectId:          d.Get("project_id").(string),
	}

	return jsonMap(ba)
}
<commit_msg>Made project CAI conversion prefer project number if available (#4605)<commit_after>package google

import (
	"fmt"
	"strings"

	"google.golang.org/api/cloudbilling/v1"
	"google.golang.org/api/cloudresourcemanager/v1"
)

func GetProjectCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	// use project number if it's available; otherwise, fill in project id so that we
	// keep the CAI assets apart for different uncreated projects.
	var linkTmpl string
	if _, ok := d.GetOk("number"); ok {
		linkTmpl = "//cloudresourcemanager.googleapis.com/projects/{{number}}"
	} else {
		linkTmpl = "//cloudresourcemanager.googleapis.com/projects/{{project_id_or_project}}"
	}
	name, err := assetName(d, config, linkTmpl)
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetProjectApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "cloudresourcemanager.googleapis.com/Project",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
				DiscoveryName:        "Project",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetProjectApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	pid := d.Get("project_id").(string)

	project := &cloudresourcemanager.Project{
		ProjectId: pid,
		Name:      d.Get("name").(string),
	}

	if err := getParentResourceId(d, project); err != nil {
		return nil, err
	}

	if _, ok := d.GetOk("labels"); ok {
		project.Labels = expandLabels(d)
	}

	return jsonMap(project)
}

func getParentResourceId(d TerraformResourceData, p *cloudresourcemanager.Project) error {
	orgId := d.Get("org_id").(string)
	folderId := d.Get("folder_id").(string)

	if orgId != "" && folderId != "" {
		return fmt.Errorf("'org_id' and 'folder_id' cannot be both set.")
	}

	if orgId != "" {
		p.Parent = &cloudresourcemanager.ResourceId{
			Id:   orgId,
			Type: "organization",
		}
	}

	if folderId != "" {
		p.Parent = &cloudresourcemanager.ResourceId{
			Id:   strings.TrimPrefix(folderId, "folders/"),
			Type: "folder",
		}
	}

	return nil
}

func GetProjectBillingInfoCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	// use project number if it's available; otherwise, fill in project id so that we
	// keep the CAI assets apart for different uncreated projects.
	var linkTmpl string
	if _, ok := d.GetOk("number"); ok {
		linkTmpl = "//cloudbilling.googleapis.com/projects/{{number}}/billingInfo"
	} else {
		linkTmpl = "//cloudbilling.googleapis.com/projects/{{project_id_or_project}}/billingInfo"
	}
	name, err := assetName(d, config, linkTmpl)
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetProjectBillingInfoApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "cloudbilling.googleapis.com/ProjectBillingInfo",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/cloudbilling/v1/rest",
				DiscoveryName:        "ProjectBillingInfo",
				Data:                 obj,
			}},
		}, nil
	} else {
		return []Asset{}, err
	}
}

func GetProjectBillingInfoApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	if _, ok := d.GetOk("billing_account"); !ok {
		// TODO: If the project already exists, we could ask the API about it's
		// billing info here.
		return nil, ErrNoConversion
	}

	var name string
	if number, ok := d.GetOk("number"); ok {
		name = fmt.Sprintf("projects/%s/billingInfo", number)
	} else {
		name = fmt.Sprintf("projects/%s/billingInfo", d.Get("project_id"))
	}

	ba := &cloudbilling.ProjectBillingInfo{
		BillingAccountName: fmt.Sprintf("billingAccounts/%s", d.Get("billing_account")),
		Name:               name,
		ProjectId:          d.Get("project_id").(string),
	}

	return jsonMap(ba)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/georgemac/whittle/cmd/whittle/options"
	"github.com/georgemac/whittle/cmd/whittle/table"
	"github.com/pkg/errors"
)

func printUsage() {
	fmt.Println(`whittle [cmd] <flags>`)
	fmt.Println(`commands:`)
	fmt.Println("\toptions - generate functional options for a type")
}

func help() {
	printUsage()
	os.Exit(1)
}

// Parser is an interface for types which parse arguments and
// returns Command types to be ran
type Parser interface {
	Parse(args []string) (Command, error)
}

// ParserFunc is a function which matches the Parser interface Parse function signature
type ParserFunc func([]string) (Command, error)

// Parse delegates the call to the receiver
func (p ParserFunc) Parse(args []string) (Command, error) { return p(args) }

// Command is something which can be Ran or a Usage string be produced upon
type Command interface {
	Run() error
	Usage() string
}

var (
	optionsCommand ParserFunc = func(args []string) (Command, error) { return options.Parse(args) }
	tableCommand   ParserFunc = func(args []string) (Command, error) { return table.Parse(args) }
	commands                  = map[string]Parser{
		"options": optionsCommand,
		"table":   tableCommand,
	}
)

func main() {
	if len(os.Args) < 2 {
		help()
	}

	var (
		command = os.Args[1]
		args    = os.Args[2:]
	)

	if cmd, ok := commands[command]; ok {
		command, err := cmd.Parse(args)
		if err != nil {
			if cause := errors.Cause(err); cause == options.ErrUsage || cause == table.ErrUsage || cause == flag.ErrHelp {
				fmt.Print("whittle ", command.Usage())
			} else {
				fmt.Println(err)
			}

			os.Exit(1)
		}

		if err := command.Run(); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		return
	}

	help()
}
<commit_msg>Refactor whittle command error causes<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/georgemac/whittle/cmd/whittle/options"
	"github.com/georgemac/whittle/cmd/whittle/table"
	"github.com/pkg/errors"
)

var (
	commands = map[string]Parser{
		"options": ParserFunc(func(args []string) (Command, error) { return options.Parse(args) }),
		"table":   ParserFunc(func(args []string) (Command, error) { return table.Parse(args) }),
	}

	usageErrors = ErrorCauses{flag.ErrHelp, options.ErrUsage, table.ErrUsage}
)

// Parser is an interface for types which parse arguments and
// returns Command types to be ran
type Parser interface {
	Parse(args []string) (Command, error)
}

// ParserFunc is a function which matches the Parser interface Parse function signature
type ParserFunc func([]string) (Command, error)

// Parse delegates the call to the receiver
func (p ParserFunc) Parse(args []string) (Command, error) { return p(args) }

// Command is something which can be Ran or a Usage string be produced upon
type Command interface {
	Run() error
	Usage() string
}

// ErrorCauses is a slice of errors
type ErrorCauses []error

// ContainsCause returns true if the cause of err is in the
// ErrorCauses slice
func (e ErrorCauses) ContainsCause(err error) bool {
	for _, cause := range e {
		if errors.Cause(err) == cause {
			return true
		}
	}

	return false
}

func printUsage() {
	fmt.Println(`whittle [cmd] <flags>`)
	fmt.Println(`commands:`)
	fmt.Println("\toptions - generate functional options for a type")
	fmt.Println("\ttable - generate table driven tests for a type")
}

func help() {
	printUsage()
	os.Exit(1)
}

func main() {
	if len(os.Args) < 2 {
		help()
	}

	var (
		command = os.Args[1]
		args    = os.Args[2:]
	)

	if cmd, ok := commands[command]; ok {
		command, err := cmd.Parse(args)
		if err != nil {
			if usageErrors.ContainsCause(err) {
				fmt.Print("whittle ", command.Usage())
			} else {
				fmt.Println(err)
			}

			os.Exit(1)
		}

		if err := command.Run(); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		return
	}

	help()
}
<|endoftext|>