<commit_before>package agent

import (
	"encoding/json"
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/go-fsnotify/fsnotify"
	resourced_config "github.com/resourced/resourced/config"
	"github.com/resourced/resourced/libprocess"
	"github.com/resourced/resourced/libstring"
	"github.com/resourced/resourced/libtime"
	resourced_readers "github.com/resourced/resourced/readers"
	resourced_writers "github.com/resourced/resourced/writers"
	"os"
	"strings"
	"time"
)

// NewAgent is the constructor fot Agent struct.
func NewAgent() (*Agent, error) {
	agent := &Agent{}

	agent.setTags()

	err := agent.setConfigStorage()
	if err != nil {
		return nil, err
	}

	err = agent.setDb()
	if err != nil {
		return nil, err
	}

	return agent, err
}

// Agent struct carries most of the functionality of ResourceD.
// It collects information through readers and serve them up as HTTP+JSON.
type Agent struct {
	ConfigStorage *resourced_config.ConfigStorage
	DbPath        string
	Db            *bolt.DB
	Tags          []string
}

func (a *Agent) setTags() {
	a.Tags = make([]string, 0)

	tags := os.Getenv("RESOURCED_TAGS")
	if tags != "" {
		tagsSlice := strings.Split(tags, ",")
		a.Tags = make([]string, len(tagsSlice))

		for i, tag := range tagsSlice {
			a.Tags[i] = strings.TrimSpace(tag)
		}
	}
}

// setConfigStorage reads config paths and setup configStorage.
func (a *Agent) setConfigStorage() error {
	readerDir := os.Getenv("RESOURCED_CONFIG_READER_DIR")
	writerDir := os.Getenv("RESOURCED_CONFIG_WRITER_DIR")

	configStorage, err := resourced_config.NewConfigStorage(readerDir, writerDir)
	if err == nil {
		a.ConfigStorage = configStorage
	}

	go a.watchConfigDirectories(readerDir, writerDir)

	return err
}

// watchConfigDirectories uses inotify to watch changes on config directories.
func (a *Agent) watchConfigDirectories(readerDir, writerDir string) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	defer watcher.Close()

	err = watcher.Add(readerDir)
	if err != nil {
		return err
	}

	err = watcher.Add(writerDir)
	if err != nil {
		return err
	}

	for {
		select {
		case event := <-watcher.Events:
			if (event.Op&fsnotify.Create == fsnotify.Create) || (event.Op&fsnotify.Remove == fsnotify.Remove) || (event.Op&fsnotify.Write == fsnotify.Write) || (event.Op&fsnotify.Rename == fsnotify.Rename) {
				fmt.Println("Config files changed. Rebuilding ConfigStorage...")

				configStorage, err := resourced_config.NewConfigStorage(readerDir, writerDir)
				if err == nil {
					a.ConfigStorage = configStorage
				}
			}
		case err := <-watcher.Errors:
			if err != nil {
				fmt.Printf("Error while watching config files: %v\n", err)
			}
		}
	}
	return nil
}

// setDb configures the local storage.
func (a *Agent) setDb() error {
	var err error

	dbPath := os.Getenv("RESOURCED_DB")
	if dbPath == "" {
		dbPath = "~/resourced/db"

		err = os.MkdirAll(libstring.ExpandTilde("~/resourced"), 0755)
		if err != nil {
			return err
		}
	}

	a.DbPath = libstring.ExpandTilde(dbPath)

	a.Db, err = bolt.Open(a.DbPath, 0644, nil)
	if err != nil {
		return err
	}

	// Create "resources" bucket
	a.Db.Update(func(tx *bolt.Tx) error {
		tx.CreateBucket([]byte("resources"))
		return nil
	})

	return err
}

// dbBucket returns the boltdb bucket.
func (a *Agent) dbBucket(tx *bolt.Tx) *bolt.Bucket {
	return tx.Bucket([]byte("resources"))
}

// pathWithPrefix prepends the short version of config.Kind to path.
func (a *Agent) pathWithPrefix(config resourced_config.Config) string {
	if config.Kind == "reader" {
		return "/r" + config.Path
	} else if config.Kind == "writer" {
		return "/w" + config.Path
	}
	return config.Path
}

// Run executes a reader/writer config.
// Run will save reader data as JSON in local db.
func (a *Agent) Run(config resourced_config.Config) (output []byte, err error) {
	if config.Command != "" {
		output, err = a.runCommand(config)
	} else if config.GoStruct != "" && config.Kind == "reader" {
		output, err = a.runGoStructReader(config)
	} else if config.GoStruct != "" && config.Kind == "writer" {
		err = a.runGoStructWriter(config)
	}
	if err != nil {
		return output, err
	}

	err = a.saveRun(config, output)

	return output, err
}

// runCommand shells out external program and returns the output.
func (a *Agent) runCommand(config resourced_config.Config) ([]byte, error) {
	cmd := libprocess.NewCmd(config.Command)
	return cmd.Output()
}

// runGoStructReader executes IReader and returns the output.
func (a *Agent) runGoStructReader(config resourced_config.Config) ([]byte, error) {
	reader, err := resourced_readers.NewGoStruct(config.GoStruct)
	if err != nil {
		return nil, err
	}

	err = reader.Run()
	if err != nil {
		return nil, err
	}

	return reader.ToJson()
}

// runGoStructWriter executes IWriter and returns error if exists.
func (a *Agent) runGoStructWriter(config resourced_config.Config) error {
	writer, err := resourced_writers.NewGoStruct(config.GoStruct)
	if err != nil {
		return err
	}

	jsonBytes, err := a.GetRun(config)
	if err != nil {
		return err
	}

	err = writer.SetData(jsonBytes)
	if err != nil {
		return err
	}

	err = writer.Run()
	return err
}

// saveRun gathers default basic information and saves output into local storage.
func (a *Agent) saveRun(config resourced_config.Config, output []byte) error {
	// Do not perform save if config.Path is empty.
	if config.Path == "" {
		return nil
	}

	record := make(map[string]interface{})
	record["UnixNano"] = time.Now().UnixNano()
	record["Path"] = config.Path
	record["Interval"] = config.Interval
	record["Tags"] = a.Tags

	if config.Command != "" {
		record["Command"] = config.Command
	}

	if config.GoStruct != "" {
		record["GoStruct"] = config.GoStruct
	}

	hostname, err := os.Hostname()
	if err != nil {
		return err
	}
	record["Hostname"] = hostname

	runData := make(map[string]interface{})
	err = json.Unmarshal(output, &runData)
	if err != nil {
		return err
	}

	record["Data"] = runData

	recordInJson, err := json.Marshal(record)
	if err != nil {
		return err
	}

	err = a.Db.Update(func(tx *bolt.Tx) error {
		return a.dbBucket(tx).Put([]byte(a.pathWithPrefix(config)), recordInJson)
	})

	return err
}

// GetRun returns the JSON data stored in local storage given Config struct.
func (a *Agent) GetRun(config resourced_config.Config) ([]byte, error) {
	return a.GetRunByPath(a.pathWithPrefix(config))
}

// GetRunByPath returns JSON data stored in local storage given path string.
func (a *Agent) GetRunByPath(path string) ([]byte, error) {
	var data []byte

	a.Db.View(func(tx *bolt.Tx) error {
		data = a.dbBucket(tx).Get([]byte(path))
		return nil
	})

	return data, nil
}

// RunForever executes Run() in an infinite loop with a sleep of config.Interval.
func (a *Agent) RunForever(config resourced_config.Config) {
	go func(a *Agent, config resourced_config.Config) {
		for {
			a.Run(config)
			libtime.SleepString(config.Interval)
		}
	}(a, config)
}

// RunAllForever executes all readers & writers in an infinite loop.
func (a *Agent) RunAllForever() {
	for _, config := range a.ConfigStorage.Readers {
		a.RunForever(config)
	}
	for _, config := range a.ConfigStorage.Writers {
		a.RunForever(config)
	}
}
<commit_msg>StructWriter also have output that needs to be saved.<commit_after>package agent

import (
	"encoding/json"
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/go-fsnotify/fsnotify"
	resourced_config "github.com/resourced/resourced/config"
	"github.com/resourced/resourced/libprocess"
	"github.com/resourced/resourced/libstring"
	"github.com/resourced/resourced/libtime"
	resourced_readers "github.com/resourced/resourced/readers"
	resourced_writers "github.com/resourced/resourced/writers"
	"os"
	"strings"
	"time"
)

// NewAgent is the constructor fot Agent struct.
func NewAgent() (*Agent, error) {
	agent := &Agent{}

	agent.setTags()

	err := agent.setConfigStorage()
	if err != nil {
		return nil, err
	}

	err = agent.setDb()
	if err != nil {
		return nil, err
	}

	return agent, err
}

// Agent struct carries most of the functionality of ResourceD.
// It collects information through readers and serve them up as HTTP+JSON.
type Agent struct {
	ConfigStorage *resourced_config.ConfigStorage
	DbPath        string
	Db            *bolt.DB
	Tags          []string
}

func (a *Agent) setTags() {
	a.Tags = make([]string, 0)

	tags := os.Getenv("RESOURCED_TAGS")
	if tags != "" {
		tagsSlice := strings.Split(tags, ",")
		a.Tags = make([]string, len(tagsSlice))

		for i, tag := range tagsSlice {
			a.Tags[i] = strings.TrimSpace(tag)
		}
	}
}

// setConfigStorage reads config paths and setup configStorage.
func (a *Agent) setConfigStorage() error {
	readerDir := os.Getenv("RESOURCED_CONFIG_READER_DIR")
	writerDir := os.Getenv("RESOURCED_CONFIG_WRITER_DIR")

	configStorage, err := resourced_config.NewConfigStorage(readerDir, writerDir)
	if err == nil {
		a.ConfigStorage = configStorage
	}

	go a.watchConfigDirectories(readerDir, writerDir)

	return err
}

// watchConfigDirectories uses inotify to watch changes on config directories.
func (a *Agent) watchConfigDirectories(readerDir, writerDir string) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	defer watcher.Close()

	err = watcher.Add(readerDir)
	if err != nil {
		return err
	}

	err = watcher.Add(writerDir)
	if err != nil {
		return err
	}

	for {
		select {
		case event := <-watcher.Events:
			if (event.Op&fsnotify.Create == fsnotify.Create) || (event.Op&fsnotify.Remove == fsnotify.Remove) || (event.Op&fsnotify.Write == fsnotify.Write) || (event.Op&fsnotify.Rename == fsnotify.Rename) {
				fmt.Println("Config files changed. Rebuilding ConfigStorage...")

				configStorage, err := resourced_config.NewConfigStorage(readerDir, writerDir)
				if err == nil {
					a.ConfigStorage = configStorage
				}
			}
		case err := <-watcher.Errors:
			if err != nil {
				fmt.Printf("Error while watching config files: %v\n", err)
			}
		}
	}
	return nil
}

// setDb configures the local storage.
func (a *Agent) setDb() error {
	var err error

	dbPath := os.Getenv("RESOURCED_DB")
	if dbPath == "" {
		dbPath = "~/resourced/db"

		err = os.MkdirAll(libstring.ExpandTilde("~/resourced"), 0755)
		if err != nil {
			return err
		}
	}

	a.DbPath = libstring.ExpandTilde(dbPath)

	a.Db, err = bolt.Open(a.DbPath, 0644, nil)
	if err != nil {
		return err
	}

	// Create "resources" bucket
	a.Db.Update(func(tx *bolt.Tx) error {
		tx.CreateBucket([]byte("resources"))
		return nil
	})

	return err
}

// dbBucket returns the boltdb bucket.
func (a *Agent) dbBucket(tx *bolt.Tx) *bolt.Bucket {
	return tx.Bucket([]byte("resources"))
}

// pathWithPrefix prepends the short version of config.Kind to path.
func (a *Agent) pathWithPrefix(config resourced_config.Config) string {
	if config.Kind == "reader" {
		return "/r" + config.Path
	} else if config.Kind == "writer" {
		return "/w" + config.Path
	}
	return config.Path
}

// Run executes a reader/writer config.
// Run will save reader data as JSON in local db.
func (a *Agent) Run(config resourced_config.Config) (output []byte, err error) {
	if config.Command != "" {
		output, err = a.runCommand(config)
	} else if config.GoStruct != "" && config.Kind == "reader" {
		output, err = a.runGoStructReader(config)
	} else if config.GoStruct != "" && config.Kind == "writer" {
		output, err = a.runGoStructWriter(config)
	}
	if err != nil {
		return output, err
	}

	err = a.saveRun(config, output)

	return output, err
}

// runCommand shells out external program and returns the output.
func (a *Agent) runCommand(config resourced_config.Config) ([]byte, error) {
	cmd := libprocess.NewCmd(config.Command)
	return cmd.Output()
}

// runGoStructReader executes IReader and returns the output.
func (a *Agent) runGoStructReader(config resourced_config.Config) ([]byte, error) {
	reader, err := resourced_readers.NewGoStruct(config.GoStruct)
	if err != nil {
		return nil, err
	}

	err = reader.Run()
	if err != nil {
		return nil, err
	}

	return reader.ToJson()
}

// runGoStructWriter executes IWriter and returns error if exists.
func (a *Agent) runGoStructWriter(config resourced_config.Config) ([]byte, error) {
	writer, err := resourced_writers.NewGoStruct(config.GoStruct)
	if err != nil {
		return nil, err
	}

	// Get reader's run data.
	jsonBytes, err := a.GetRunByPath("/r" + config.Path)
	if err != nil {
		return nil, err
	}

	err = writer.SetData(jsonBytes)
	if err != nil {
		return nil, err
	}

	err = writer.Run()
	if err != nil {
		return nil, err
	}

	return writer.ToJson()
}

// saveRun gathers default basic information and saves output into local storage.
func (a *Agent) saveRun(config resourced_config.Config, output []byte) error {
	// Do not perform save if config.Path is empty.
	if config.Path == "" {
		return nil
	}

	record := make(map[string]interface{})
	record["UnixNano"] = time.Now().UnixNano()
	record["Path"] = config.Path
	record["Interval"] = config.Interval
	record["Tags"] = a.Tags

	if config.Command != "" {
		record["Command"] = config.Command
	}

	if config.GoStruct != "" {
		record["GoStruct"] = config.GoStruct
	}

	hostname, err := os.Hostname()
	if err != nil {
		return err
	}
	record["Hostname"] = hostname

	runData := make(map[string]interface{})
	err = json.Unmarshal(output, &runData)
	if err != nil {
		return err
	}

	record["Data"] = runData

	recordInJson, err := json.Marshal(record)
	if err != nil {
		return err
	}

	err = a.Db.Update(func(tx *bolt.Tx) error {
		return a.dbBucket(tx).Put([]byte(a.pathWithPrefix(config)), recordInJson)
	})

	return err
}

// GetRun returns the JSON data stored in local storage given Config struct.
func (a *Agent) GetRun(config resourced_config.Config) ([]byte, error) {
	return a.GetRunByPath(a.pathWithPrefix(config))
}

// GetRunByPath returns JSON data stored in local storage given path string.
func (a *Agent) GetRunByPath(path string) ([]byte, error) {
	var data []byte

	a.Db.View(func(tx *bolt.Tx) error {
		data = a.dbBucket(tx).Get([]byte(path))
		return nil
	})

	return data, nil
}

// RunForever executes Run() in an infinite loop with a sleep of config.Interval.
func (a *Agent) RunForever(config resourced_config.Config) {
	go func(a *Agent, config resourced_config.Config) {
		for {
			a.Run(config)
			libtime.SleepString(config.Interval)
		}
	}(a, config)
}

// RunAllForever executes all readers & writers in an infinite loop.
func (a *Agent) RunAllForever() {
	for _, config := range a.ConfigStorage.Readers {
		a.RunForever(config)
	}
	for _, config := range a.ConfigStorage.Writers {
		a.RunForever(config)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package main

import (
	"flag"
	mathrand "math/rand"
	"os"
	"time"

	acshandler "github.com/aws/amazon-ecs-agent/agent/acs/handler"
	"github.com/aws/amazon-ecs-agent/agent/api"
	"github.com/aws/amazon-ecs-agent/agent/auth"
	"github.com/aws/amazon-ecs-agent/agent/config"
	"github.com/aws/amazon-ecs-agent/agent/ec2"
	"github.com/aws/amazon-ecs-agent/agent/engine"
	"github.com/aws/amazon-ecs-agent/agent/eventhandler"
	"github.com/aws/amazon-ecs-agent/agent/handlers"
	"github.com/aws/amazon-ecs-agent/agent/logger"
	"github.com/aws/amazon-ecs-agent/agent/sighandlers"
	"github.com/aws/amazon-ecs-agent/agent/sighandlers/exitcodes"
	"github.com/aws/amazon-ecs-agent/agent/statemanager"
	"github.com/aws/amazon-ecs-agent/agent/utils"
	utilatomic "github.com/aws/amazon-ecs-agent/agent/utils/atomic"
	"github.com/aws/amazon-ecs-agent/agent/version"
	log "github.com/cihub/seelog"
)

func init() {
	mathrand.Seed(time.Now().UnixNano())
}

func main() {
	// Use a returning main instead of os.Exiting main to allow defers to run
	// before exit
	os.Exit(_main())
}
func _main() int {
	defer log.Flush()
	versionFlag := flag.Bool("version", false, "Print the agent version information and exit")
	acceptInsecureCert := flag.Bool("k", false, "Do not verify ssl certs")
	logLevel := flag.String("loglevel", "", "Loglevel: [<crit>|<error>|<warn>|<info>|<debug>]")
	flag.Parse()

	logger.SetLevel(*logLevel)

	log.Infof("Starting Agent: %v", version.String())

	log.Info("Loading configuration")
	cfg, err := config.NewConfig()
	if err != nil {
		log.Errorf("Error loading config: %v", err)
		return exitcodes.ExitTerminal
	}

	if *versionFlag {
		versionableEngine := engine.NewTaskEngine(cfg)
		version.PrintVersion(versionableEngine)
		return exitcodes.ExitSuccess
	}

	var currentEc2InstanceID, containerInstanceArn string
	var taskEngine engine.TaskEngine

	if cfg.Checkpoint {
		log.Info("Checkpointing is enabled. Attempting to load state")
		var previousCluster, previousEc2InstanceID, previousContainerInstanceArn string
		previousTaskEngine := engine.NewTaskEngine(cfg)
		// previousState is used to verify that our current runtime configuration is
		// compatible with our past configuration as reflected by our state-file
		previousState, err := initializeStateManager(cfg, previousTaskEngine, &previousCluster, &previousContainerInstanceArn, &previousEc2InstanceID, acshandler.SequenceNumber)
		if err != nil {
			log.Criticalf("Error creating state manager: %v", err)
			return exitcodes.ExitTerminal
		}

		err = previousState.Load()
		if err != nil {
			log.Criticalf("Error loading previously saved state: %v", err)
			return exitcodes.ExitTerminal
		}

		if previousCluster != "" {
			// TODO Handle default cluster in a sane and unified way across the codebase
			configuredCluster := cfg.Cluster
			if configuredCluster == "" {
				log.Debug("Setting cluster to default; none configured")
				configuredCluster = config.DEFAULT_CLUSTER_NAME
			}
			if previousCluster != configuredCluster {
				log.Criticalf("Data mismatch; saved cluster '%v' does not match configured cluster '%v'. Perhaps you want to delete the configured checkpoint file?", previousCluster, configuredCluster)
				return exitcodes.ExitTerminal
			}
			cfg.Cluster = previousCluster
			log.Infof("Restored cluster '%v'", cfg.Cluster)
		}

		if instanceIdentityDoc, err := ec2.GetInstanceIdentityDocument(); err == nil {
			currentEc2InstanceID = instanceIdentityDoc.InstanceId
		} else {
			log.Criticalf("Unable to access EC2 Metadata service to determine EC2 ID: %v", err)
		}

		if previousEc2InstanceID != "" && previousEc2InstanceID != currentEc2InstanceID {
			log.Warnf("Data mismatch; saved InstanceID '%v' does not match current InstanceID '%v'. Overwriting old datafile", previousEc2InstanceID, currentEc2InstanceID)

			// Reset taskEngine; all the other values are still default
			taskEngine = engine.NewTaskEngine(cfg)
		} else {
			// Use the values we loaded if there's no issue
			containerInstanceArn = previousContainerInstanceArn
			taskEngine = previousTaskEngine
		}
	} else {
		log.Info("Checkpointing not enabled; a new container instance will be created each time the agent is run")
		taskEngine = engine.NewTaskEngine(cfg)
	}

	stateManager, err := initializeStateManager(cfg, taskEngine, &cfg.Cluster, &containerInstanceArn, &currentEc2InstanceID, acshandler.SequenceNumber)
	if err != nil {
		log.Criticalf("Error creating state manager: %v", err)
		return exitcodes.ExitTerminal
	}

	credentialProvider := auth.NewBasicAWSCredentialProvider()
	awsCreds := auth.ToSDK(credentialProvider)
	client := api.NewECSClient(awsCreds, cfg, *acceptInsecureCert)

	if containerInstanceArn == "" {
		log.Info("Registering Instance with ECS")
		containerInstanceArn, err = client.RegisterContainerInstance()
		if err != nil {
			log.Errorf("Error registering: %v", err)
			if retriable, ok := err.(utils.Retriable); ok && !retriable.Retry() {
				return exitcodes.ExitTerminal
			}
			return exitcodes.ExitError
		}
		log.Infof("Registration completed successfully. I am running as '%v' in cluster '%v'", containerInstanceArn, cfg.Cluster)
		// Save our shiny new containerInstanceArn
		stateManager.Save()
	} else {
		log.Infof("Restored from checkpoint file. I am running as '%v' in cluster '%v'", containerInstanceArn, cfg.Cluster)
	}

	// Begin listening to the docker daemon and saving changes
	taskEngine.SetSaver(stateManager)
	taskEngine.MustInit()

	go sighandlers.StartTerminationHandler(stateManager, taskEngine)

	// Agent introspection api
	go handlers.ServeHttp(&containerInstanceArn, taskEngine, cfg)

	// Start sending events to the backend
	go eventhandler.HandleEngineEvents(taskEngine, client, stateManager)

	log.Info("Beginning Polling for updates")
	err = acshandler.StartSession(containerInstanceArn, credentialProvider, cfg, taskEngine, client, stateManager, *acceptInsecureCert)
	if err != nil {
		log.Criticalf("Unretriable error starting communicating with ACS: %v", err)
		return exitcodes.ExitTerminal
	}
	log.Critical("ACS Session handler should never exit")
	return exitcodes.ExitError
}

func initializeStateManager(cfg *config.Config, taskEngine engine.TaskEngine, cluster, containerInstanceArn, savedInstanceID *string, sequenceNumber *utilatomic.IncreasingInt64) (statemanager.StateManager, error) {
	if !cfg.Checkpoint {
		return statemanager.NewNoopStateManager(), nil
	}
	stateManager, err := statemanager.NewStateManager(cfg,
		statemanager.AddSaveable("TaskEngine", taskEngine),
		statemanager.AddSaveable("ContainerInstanceArn", containerInstanceArn),
		statemanager.AddSaveable("Cluster", cluster),
		statemanager.AddSaveable("EC2InstanceID", savedInstanceID),
		statemanager.AddSaveable("ACSSeqNum", sequenceNumber),
	)
	if err != nil {
		return nil, err
	}
	return stateManager, nil
}
<commit_msg>Add preflight credential get to allow better log output<commit_after>// Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package main

import (
	"flag"
	mathrand "math/rand"
	"os"
	"time"

	acshandler "github.com/aws/amazon-ecs-agent/agent/acs/handler"
	"github.com/aws/amazon-ecs-agent/agent/api"
	"github.com/aws/amazon-ecs-agent/agent/auth"
	"github.com/aws/amazon-ecs-agent/agent/config"
	"github.com/aws/amazon-ecs-agent/agent/ec2"
	"github.com/aws/amazon-ecs-agent/agent/engine"
	"github.com/aws/amazon-ecs-agent/agent/eventhandler"
	"github.com/aws/amazon-ecs-agent/agent/handlers"
	"github.com/aws/amazon-ecs-agent/agent/logger"
	"github.com/aws/amazon-ecs-agent/agent/sighandlers"
	"github.com/aws/amazon-ecs-agent/agent/sighandlers/exitcodes"
	"github.com/aws/amazon-ecs-agent/agent/statemanager"
	"github.com/aws/amazon-ecs-agent/agent/utils"
	utilatomic "github.com/aws/amazon-ecs-agent/agent/utils/atomic"
	"github.com/aws/amazon-ecs-agent/agent/version"
	log "github.com/cihub/seelog"
)

func init() {
	mathrand.Seed(time.Now().UnixNano())
}

func main() {
	// Use a returning main instead of os.Exiting main to allow defers to run
	// before exit
	os.Exit(_main())
}
func _main() int {
	defer log.Flush()
	versionFlag := flag.Bool("version", false, "Print the agent version information and exit")
	acceptInsecureCert := flag.Bool("k", false, "Do not verify ssl certs")
	logLevel := flag.String("loglevel", "", "Loglevel: [<crit>|<error>|<warn>|<info>|<debug>]")
	flag.Parse()

	logger.SetLevel(*logLevel)

	log.Infof("Starting Agent: %v", version.String())

	log.Info("Loading configuration")
	cfg, err := config.NewConfig()
	if err != nil {
		log.Errorf("Error loading config: %v", err)
		return exitcodes.ExitTerminal
	}

	if *versionFlag {
		versionableEngine := engine.NewTaskEngine(cfg)
		version.PrintVersion(versionableEngine)
		return exitcodes.ExitSuccess
	}

	var currentEc2InstanceID, containerInstanceArn string
	var taskEngine engine.TaskEngine

	if cfg.Checkpoint {
		log.Info("Checkpointing is enabled. Attempting to load state")
		var previousCluster, previousEc2InstanceID, previousContainerInstanceArn string
		previousTaskEngine := engine.NewTaskEngine(cfg)
		// previousState is used to verify that our current runtime configuration is
		// compatible with our past configuration as reflected by our state-file
		previousState, err := initializeStateManager(cfg, previousTaskEngine, &previousCluster, &previousContainerInstanceArn, &previousEc2InstanceID, acshandler.SequenceNumber)
		if err != nil {
			log.Criticalf("Error creating state manager: %v", err)
			return exitcodes.ExitTerminal
		}

		err = previousState.Load()
		if err != nil {
			log.Criticalf("Error loading previously saved state: %v", err)
			return exitcodes.ExitTerminal
		}

		if previousCluster != "" {
			// TODO Handle default cluster in a sane and unified way across the codebase
			configuredCluster := cfg.Cluster
			if configuredCluster == "" {
				log.Debug("Setting cluster to default; none configured")
				configuredCluster = config.DEFAULT_CLUSTER_NAME
			}
			if previousCluster != configuredCluster {
				log.Criticalf("Data mismatch; saved cluster '%v' does not match configured cluster '%v'. Perhaps you want to delete the configured checkpoint file?", previousCluster, configuredCluster)
				return exitcodes.ExitTerminal
			}
			cfg.Cluster = previousCluster
			log.Infof("Restored cluster '%v'", cfg.Cluster)
		}

		if instanceIdentityDoc, err := ec2.GetInstanceIdentityDocument(); err == nil {
			currentEc2InstanceID = instanceIdentityDoc.InstanceId
		} else {
			log.Criticalf("Unable to access EC2 Metadata service to determine EC2 ID: %v", err)
		}

		if previousEc2InstanceID != "" && previousEc2InstanceID != currentEc2InstanceID {
			log.Warnf("Data mismatch; saved InstanceID '%v' does not match current InstanceID '%v'. Overwriting old datafile", previousEc2InstanceID, currentEc2InstanceID)

			// Reset taskEngine; all the other values are still default
			taskEngine = engine.NewTaskEngine(cfg)
		} else {
			// Use the values we loaded if there's no issue
			containerInstanceArn = previousContainerInstanceArn
			taskEngine = previousTaskEngine
		}
	} else {
		log.Info("Checkpointing not enabled; a new container instance will be created each time the agent is run")
		taskEngine = engine.NewTaskEngine(cfg)
	}

	stateManager, err := initializeStateManager(cfg, taskEngine, &cfg.Cluster, &containerInstanceArn, &currentEc2InstanceID, acshandler.SequenceNumber)
	if err != nil {
		log.Criticalf("Error creating state manager: %v", err)
		return exitcodes.ExitTerminal
	}

	credentialProvider := auth.NewBasicAWSCredentialProvider()
	awsCreds := auth.ToSDK(credentialProvider)
	// Preflight request to make sure they're good
	if preflightCreds, err := awsCreds.Credentials(); err != nil || preflightCreds.AccessKeyID == "" {
		log.Warnf("Error getting valid credentials (AKID %v): %v", preflightCreds.AccessKeyID, err)
	}
	client := api.NewECSClient(awsCreds, cfg, *acceptInsecureCert)

	if containerInstanceArn == "" {
		log.Info("Registering Instance with ECS")
		containerInstanceArn, err = client.RegisterContainerInstance()
		if err != nil {
			log.Errorf("Error registering: %v", err)
			if retriable, ok := err.(utils.Retriable); ok && !retriable.Retry() {
				return exitcodes.ExitTerminal
			}
			return exitcodes.ExitError
		}
		log.Infof("Registration completed successfully. I am running as '%v' in cluster '%v'", containerInstanceArn, cfg.Cluster)
		// Save our shiny new containerInstanceArn
		stateManager.Save()
	} else {
		log.Infof("Restored from checkpoint file. I am running as '%v' in cluster '%v'", containerInstanceArn, cfg.Cluster)
	}

	// Begin listening to the docker daemon and saving changes
	taskEngine.SetSaver(stateManager)
	taskEngine.MustInit()

	go sighandlers.StartTerminationHandler(stateManager, taskEngine)

	// Agent introspection api
	go handlers.ServeHttp(&containerInstanceArn, taskEngine, cfg)

	// Start sending events to the backend
	go eventhandler.HandleEngineEvents(taskEngine, client, stateManager)

	log.Info("Beginning Polling for updates")
	err = acshandler.StartSession(containerInstanceArn, credentialProvider, cfg, taskEngine, client, stateManager, *acceptInsecureCert)
	if err != nil {
		log.Criticalf("Unretriable error starting communicating with ACS: %v", err)
		return exitcodes.ExitTerminal
	}
	log.Critical("ACS Session handler should never exit")
	return exitcodes.ExitError
}

func initializeStateManager(cfg *config.Config, taskEngine engine.TaskEngine, cluster, containerInstanceArn, savedInstanceID *string, sequenceNumber *utilatomic.IncreasingInt64) (statemanager.StateManager, error) {
	if !cfg.Checkpoint {
		return statemanager.NewNoopStateManager(), nil
	}
	stateManager, err := statemanager.NewStateManager(cfg,
		statemanager.AddSaveable("TaskEngine", taskEngine),
		statemanager.AddSaveable("ContainerInstanceArn", containerInstanceArn),
		statemanager.AddSaveable("Cluster", cluster),
		statemanager.AddSaveable("EC2InstanceID", savedInstanceID),
		statemanager.AddSaveable("ACSSeqNum", sequenceNumber),
	)
	if err != nil {
		return nil, err
	}
	return stateManager, nil
}
<|endoftext|>


<commit_before>package agent

import (
	"encoding/json"
	"github.com/boltdb/bolt"
	resourced_config "github.com/resourced/resourced/config"
	"github.com/resourced/resourced/libprocess"
	"github.com/resourced/resourced/libstring"
	"github.com/resourced/resourced/libtime"
	resourced_readers "github.com/resourced/resourced/readers"
	"os"
	"strings"
	"time"
)

// NewAgent is the constructor fot Agent struct.
func NewAgent() (*Agent, error) {
	agent := &Agent{}

	agent.setTags()

	err := agent.setConfigStorage()
	if err != nil {
		return nil, err
	}

	err = agent.setDb()
	if err != nil {
		return nil, err
	}

	return agent, err
}

// Agent struct carries most of the functionality of ResourceD.
// It collects information through readers and serve them up as HTTP+JSON.
type Agent struct {
	ConfigStorage *resourced_config.ConfigStorage
	DbPath        string
	Db            *bolt.DB
	Tags          []string
}

func (a *Agent) setTags() {
	tags := os.Getenv("RESOURCED_TAGS")
	if tags != "" {
		tagsSlice := strings.Split(tags, ",")
		a.Tags = make([]string, len(tagsSlice))

		for i, tag := range tagsSlice {
			a.Tags[i] = strings.TrimSpace(tag)
		}
	}
}

// setConfigStorage reads config paths and setup configStorage.
func (a *Agent) setConfigStorage() error {
	readerDir := os.Getenv("RESOURCED_CONFIG_READER_DIR")
	writerDir := os.Getenv("RESOURCED_CONFIG_WRITER_DIR")

	configStorage, err := resourced_config.NewConfigStorage(readerDir, writerDir)
	if err == nil {
		a.ConfigStorage = configStorage
	}
	return err
}

// setDb configures the local storage.
func (a *Agent) setDb() error {
	var err error

	dbPath := os.Getenv("RESOURCED_DB")
	if dbPath == "" {
		dbPath = "~/resourced/db"

		err = os.MkdirAll(libstring.ExpandTilde("~/resourced"), 0755)
		if err != nil {
			return err
		}
	}

	a.DbPath = libstring.ExpandTilde(dbPath)

	a.Db, err = bolt.Open(a.DbPath, 0644, nil)
	if err != nil {
		return err
	}

	// Create "resources" bucket
	a.Db.Update(func(tx *bolt.Tx) error {
		tx.CreateBucket([]byte("resources"))
		return nil
	})

	return err
}

// DbBucket returns the boltdb bucket.
func (a *Agent) DbBucket(tx *bolt.Tx) *bolt.Bucket {
	return tx.Bucket([]byte("resources"))
}

// Run executes a particular reader/writer config and saves the result on local storage.
func (a *Agent) Run(config resourced_config.Config) (output []byte, err error) {
	if config.Command != "" {
		output, err = a.RunCommand(config)
	} else if config.GoStruct != "" {
		output, err = a.RunGoStruct(config)
	}

	if err != nil {
		return nil, err
	}

	err = a.SaveRun(config, output)
	return output, err
}

// RunCommand shells out external program and returns the output.
func (a *Agent) RunCommand(config resourced_config.Config) ([]byte, error) {
	cmd := libprocess.NewCmd(config.Command)
	return cmd.Output()
}

// RunCommand executes IReaderWriter and returns the output.
func (a *Agent) RunGoStruct(config resourced_config.Config) ([]byte, error) {
	var reader resourced_readers.IReaderWriter

	reader, err := resourced_readers.NewGoStruct(config.GoStruct)
	if err != nil {
		return nil, err
	}

	err = reader.Run()
	if err != nil {
		return nil, err
	}

	return reader.ToJson()
}

// SaveRun gathers default basic information and saves output into local storage.
func (a *Agent) SaveRun(config resourced_config.Config, output []byte) error {
	record := make(map[string]interface{})
	record["UnixNano"] = time.Now().UnixNano()
	record["Path"] = config.Path
	record["Interval"] = config.Interval

	if config.Command != "" {
		record["Command"] = config.Command
	}

	if config.GoStruct != "" {
		record["GoStruct"] = config.GoStruct
	}

	hostname, err := os.Hostname()
	if err != nil {
		return err
	}
	record["Hostname"] = hostname

	runData := make(map[string]interface{})
	err = json.Unmarshal(output, &runData)
	if err != nil {
		return err
	}

	record["Data"] = runData

	recordInJson, err := json.Marshal(record)
	if err != nil {
		return err
	}

	err = a.Db.Update(func(tx *bolt.Tx) error {
		return a.DbBucket(tx).Put([]byte(config.Path), recordInJson)
	})

	return err
}

// GetRun returns JSON data stored in local storage given Config struct.
func (a *Agent) GetRun(config resourced_config.Config) ([]byte, error) {
	return a.GetRunByPath(config.Path)
}

// GetRunByPath returns JSON data stored in local storage given path string.
func (a *Agent) GetRunByPath(path string) ([]byte, error) {
	var data []byte

	a.Db.View(func(tx *bolt.Tx) error {
		data = a.DbBucket(tx).Get([]byte(path))
		return nil
	})

	return data, nil
}

// RunForever executes Run() in a loop with a sleep of config.Interval.
func (a *Agent) RunForever(config resourced_config.Config) {
	go func(a *Agent, config resourced_config.Config) {
		for {
			a.Run(config)
			libtime.SleepString(config.Interval)
		}
	}(a, config)
}

// RunAllForever executes all readers & writers in a loop.
func (a *Agent) RunAllForever() {
	for _, config := range a.ConfigStorage.Readers {
		a.RunForever(config)
	}
	for _, config := range a.ConfigStorage.Writers {
		a.RunForever(config)
	}
}
<commit_msg>Able to watch changes on config directories.<commit_after>package agent

import (
	"encoding/json"
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/go-fsnotify/fsnotify"
	resourced_config "github.com/resourced/resourced/config"
	"github.com/resourced/resourced/libprocess"
	"github.com/resourced/resourced/libstring"
	"github.com/resourced/resourced/libtime"
	resourced_readers "github.com/resourced/resourced/readers"
	"os"
	"strings"
	"time"
)

// NewAgent is the constructor fot Agent struct.
func NewAgent() (*Agent, error) {
	agent := &Agent{}

	agent.setTags()

	err := agent.setConfigStorage()
	if err != nil {
		return nil, err
	}

	err = agent.setDb()
	if err != nil {
		return nil, err
	}

	return agent, err
}

// Agent struct carries most of the functionality of ResourceD.
// It collects information through readers and serve them up as HTTP+JSON.
type Agent struct {
	ConfigStorage *resourced_config.ConfigStorage
	DbPath        string
	Db            *bolt.DB
	Tags          []string
}

func (a *Agent) setTags() {
	tags := os.Getenv("RESOURCED_TAGS")
	if tags != "" {
		tagsSlice := strings.Split(tags, ",")
		a.Tags = make([]string, len(tagsSlice))

		for i, tag := range tagsSlice {
			a.Tags[i] = strings.TrimSpace(tag)
		}
	}
}

// setConfigStorage reads config paths and setup configStorage.
func (a *Agent) setConfigStorage() error {
	readerDir := os.Getenv("RESOURCED_CONFIG_READER_DIR")
	writerDir := os.Getenv("RESOURCED_CONFIG_WRITER_DIR")

	configStorage, err := resourced_config.NewConfigStorage(readerDir, writerDir)
	if err == nil {
		a.ConfigStorage = configStorage
	}

	go a.watchConfigDirectories(readerDir, writerDir)

	return err
}

// watchConfigDirectories uses inotify to watch changes on config directories.
func (a *Agent) watchConfigDirectories(readerDir, writerDir string) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	defer watcher.Close()

	err = watcher.Add(readerDir)
	if err != nil {
		return err
	}

	err = watcher.Add(writerDir)
	if err != nil {
		return err
	}

	for {
		select {
		case event := <-watcher.Events:
			if (event.Op&fsnotify.Create == fsnotify.Create) || (event.Op&fsnotify.Remove == fsnotify.Remove) || (event.Op&fsnotify.Write == fsnotify.Write) || (event.Op&fsnotify.Rename == fsnotify.Rename) {
				fmt.Println("Config files changed. Rebuilding ConfigStorage...")

				configStorage, err := resourced_config.NewConfigStorage(readerDir, writerDir)
				if err == nil {
					a.ConfigStorage = configStorage
				}
			}
		case err := <-watcher.Errors:
			if err != nil {
				fmt.Printf("Error while watching config files: %v\n", err)
			}
		}
	}
	return nil
}

// setDb configures the local storage.
func (a *Agent) setDb() error {
	var err error

	dbPath := os.Getenv("RESOURCED_DB")
	if dbPath == "" {
		dbPath = "~/resourced/db"

		err = os.MkdirAll(libstring.ExpandTilde("~/resourced"), 0755)
		if err != nil {
			return err
		}
	}

	a.DbPath = libstring.ExpandTilde(dbPath)

	a.Db, err = bolt.Open(a.DbPath, 0644, nil)
	if err != nil {
		return err
	}

	// Create "resources" bucket
	a.Db.Update(func(tx *bolt.Tx) error {
		tx.CreateBucket([]byte("resources"))
		return nil
	})

	return err
}

// DbBucket returns the boltdb bucket.
func (a *Agent) DbBucket(tx *bolt.Tx) *bolt.Bucket {
	return tx.Bucket([]byte("resources"))
}

// Run executes a particular reader/writer config and saves the result on local storage.
func (a *Agent) Run(config resourced_config.Config) (output []byte, err error) {
	if config.Command != "" {
		output, err = a.RunCommand(config)
	} else if config.GoStruct != "" {
		output, err = a.RunGoStruct(config)
	}

	if err != nil {
		return nil, err
	}

	err = a.SaveRun(config, output)
	return output, err
}

// RunCommand shells out external program and returns the output.
func (a *Agent) RunCommand(config resourced_config.Config) ([]byte, error) {
	cmd := libprocess.NewCmd(config.Command)
	return cmd.Output()
}

// RunCommand executes IReaderWriter and returns the output.
func (a *Agent) RunGoStruct(config resourced_config.Config) ([]byte, error) {
	var reader resourced_readers.IReaderWriter

	reader, err := resourced_readers.NewGoStruct(config.GoStruct)
	if err != nil {
		return nil, err
	}

	err = reader.Run()
	if err != nil {
		return nil, err
	}

	return reader.ToJson()
}

// SaveRun gathers default basic information and saves output into local storage.
func (a *Agent) SaveRun(config resourced_config.Config, output []byte) error {
	record := make(map[string]interface{})
	record["UnixNano"] = time.Now().UnixNano()
	record["Path"] = config.Path
	record["Interval"] = config.Interval

	if config.Command != "" {
		record["Command"] = config.Command
	}

	if config.GoStruct != "" {
		record["GoStruct"] = config.GoStruct
	}

	hostname, err := os.Hostname()
	if err != nil {
		return err
	}
	record["Hostname"] = hostname

	runData := make(map[string]interface{})
	err = json.Unmarshal(output, &runData)
	if err != nil {
		return err
	}

	record["Data"] = runData

	recordInJson, err := json.Marshal(record)
	if err != nil {
		return err
	}

	err = a.Db.Update(func(tx *bolt.Tx) error {
		return a.DbBucket(tx).Put([]byte(config.Path), recordInJson)
	})

	return err
}

// GetRun returns JSON data stored in local storage given Config struct.
func (a *Agent) GetRun(config resourced_config.Config) ([]byte, error) {
	return a.GetRunByPath(config.Path)
}

// GetRunByPath returns JSON data stored in local storage given path string.
func (a *Agent) GetRunByPath(path string) ([]byte, error) {
	var data []byte

	a.Db.View(func(tx *bolt.Tx) error {
		data = a.DbBucket(tx).Get([]byte(path))
		return nil
	})

	return data, nil
}

// RunForever executes Run() in a loop with a sleep of config.Interval.
func (a *Agent) RunForever(config resourced_config.Config) {
	go func(a *Agent, config resourced_config.Config) {
		for {
			a.Run(config)
			libtime.SleepString(config.Interval)
		}
	}(a, config)
}

// RunAllForever executes all readers & writers in a loop.
func (a *Agent) RunAllForever() {
	for _, config := range a.ConfigStorage.Readers {
		a.RunForever(config)
	}
	for _, config := range a.ConfigStorage.Writers {
		a.RunForever(config)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

// Package agent provides hooks programs can register to retrieve
// diagnostics data by using gops.
package agent

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	gosignal "os/signal"
	"runtime"
	"runtime/pprof"
	"strconv"
	"time"

	"github.com/google/gops/internal"
	"github.com/google/gops/signal"
)

// Start stars the gops agent on a host process. Once agent started,
// users can use the advanced gops features.
//
// Note: The agent exposes an endpoint via a TCP connection that can be used by
// any program on the system. Review your security requirements before
// starting the agent.
func Start() error {
	gopsdir, err := internal.ConfigDir()
	if err != nil {
		return err
	}
	err = os.MkdirAll(gopsdir, os.ModePerm)
	if err != nil {
		return err
	}

	// TODO(jbd): Expose these endpoints on HTTP. Then, we can enable
	// the agent on Windows systems.
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return err
	}
	port := l.Addr().(*net.TCPAddr).Port
	portfile := fmt.Sprintf("%s/%d", gopsdir, os.Getpid())
	err = ioutil.WriteFile(portfile, []byte(strconv.Itoa(port)), os.ModePerm)
	if err != nil {
		return err
	}

	c := make(chan os.Signal, 1)
	gosignal.Notify(c, os.Interrupt)
	go func() {
		// cleanup the socket on shutdown.
		<-c
		os.Remove(portfile)
		os.Exit(1)
	}()

	go func() {
		buf := make([]byte, 1)
		for {
			fd, err := l.Accept()
			if err != nil {
				fmt.Fprintf(os.Stderr, "gops: %v", err)
				continue
			}
			if _, err := fd.Read(buf); err != nil {
				fmt.Fprintf(os.Stderr, "gops: %v", err)
				continue
			}
			if err := handle(fd, buf); err != nil {
				fmt.Fprintf(os.Stderr, "gops: %v", err)
				continue
			}
			fd.Close()
		}
	}()
	return err
}

func handle(conn net.Conn, msg []byte) error {
	switch msg[0] {
	case signal.StackTrace:
		buf := make([]byte, 1<<16)
		n := runtime.Stack(buf, true)
		_, err := conn.Write(buf[:n])
		return err
	case signal.GC:
		runtime.GC()
		_, err := conn.Write([]byte("ok"))
		return err
	case signal.MemStats:
		var s runtime.MemStats
		runtime.ReadMemStats(&s)
		fmt.Fprintf(conn, "alloc: %v bytes\n", s.Alloc)
		fmt.Fprintf(conn, "total-alloc: %v bytes\n", s.TotalAlloc)
		fmt.Fprintf(conn, "sys: %v bytes\n", s.Sys)
		fmt.Fprintf(conn, "lookups: %v\n", s.Lookups)
		fmt.Fprintf(conn, "mallocs: %v\n", s.Mallocs)
		fmt.Fprintf(conn, "frees: %v\n", s.Frees)
		fmt.Fprintf(conn, "heap-alloc: %v bytes\n", s.HeapAlloc)
		fmt.Fprintf(conn, "heap-sys: %v bytes\n", s.HeapSys)
		fmt.Fprintf(conn, "heap-idle: %v bytes\n", s.HeapIdle)
		fmt.Fprintf(conn, "heap-in-use: %v bytes\n", s.HeapInuse)
		fmt.Fprintf(conn, "heap-released: %v bytes\n", s.HeapReleased)
		fmt.Fprintf(conn, "heap-objects: %v\n", s.HeapObjects)
		fmt.Fprintf(conn, "stack-in-use: %v bytes\n", s.StackInuse)
		fmt.Fprintf(conn, "stack-sys: %v bytes\n", s.StackSys)
		fmt.Fprintf(conn, "next-gc: when heap-alloc >= %v bytes\n", s.NextGC)
		fmt.Fprintf(conn, "last-gc: %v ns\n", s.LastGC)
		fmt.Fprintf(conn, "gc-pause: %v ns\n", s.PauseTotalNs)
		fmt.Fprintf(conn, "num-gc: %v\n", s.NumGC)
		fmt.Fprintf(conn, "enable-gc: %v\n", s.EnableGC)
		fmt.Fprintf(conn, "debug-gc: %v\n", s.DebugGC)
	case signal.Version:
		fmt.Fprintf(conn, "%v\n", runtime.Version())
	case signal.HeapProfile:
		pprof.Lookup("heap").WriteTo(conn, 0)
	case signal.CPUProfile:
		if err := pprof.StartCPUProfile(conn); err != nil {
			return nil
		}
		time.Sleep(30 * time.Second)
		pprof.StopCPUProfile()
	case signal.Vitals:
		fmt.Fprintf(conn, "goroutines: %v\n", runtime.NumGoroutine())
		fmt.Fprintf(conn, "OS threads: %v\n", pprof.Lookup("threadcreate").Count())
		fmt.Fprintf(conn, "GOMAXPROCS: %v\n", runtime.GOMAXPROCS(0))
		fmt.Fprintf(conn, "num CPU: %v\n", runtime.NumCPU())
	}
	return nil
}
<commit_msg>agent: corrected spelling error on godoc<commit_after>// Copyright 2016 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.

// Package agent provides hooks programs can register to retrieve
// diagnostics data by using gops.
package agent

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	gosignal "os/signal"
	"runtime"
	"runtime/pprof"
	"strconv"
	"time"

	"github.com/google/gops/internal"
	"github.com/google/gops/signal"
)

// Start starts the gops agent on a host process. Once agent started,
// users can use the advanced gops features.
//
// Note: The agent exposes an endpoint via a TCP connection that can be used by
// any program on the system. Review your security requirements before
// starting the agent.
func Start() error {
	gopsdir, err := internal.ConfigDir()
	if err != nil {
		return err
	}
	err = os.MkdirAll(gopsdir, os.ModePerm)
	if err != nil {
		return err
	}

	// TODO(jbd): Expose these endpoints on HTTP. Then, we can enable
	// the agent on Windows systems.
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return err
	}
	port := l.Addr().(*net.TCPAddr).Port
	portfile := fmt.Sprintf("%s/%d", gopsdir, os.Getpid())
	err = ioutil.WriteFile(portfile, []byte(strconv.Itoa(port)), os.ModePerm)
	if err != nil {
		return err
	}

	c := make(chan os.Signal, 1)
	gosignal.Notify(c, os.Interrupt)
	go func() {
		// cleanup the socket on shutdown.
		<-c
		os.Remove(portfile)
		os.Exit(1)
	}()

	go func() {
		buf := make([]byte, 1)
		for {
			fd, err := l.Accept()
			if err != nil {
				fmt.Fprintf(os.Stderr, "gops: %v", err)
				continue
			}
			if _, err := fd.Read(buf); err != nil {
				fmt.Fprintf(os.Stderr, "gops: %v", err)
				continue
			}
			if err := handle(fd, buf); err != nil {
				fmt.Fprintf(os.Stderr, "gops: %v", err)
				continue
			}
			fd.Close()
		}
	}()
	return err
}

func handle(conn net.Conn, msg []byte) error {
	switch msg[0] {
	case signal.StackTrace:
		buf := make([]byte, 1<<16)
		n := runtime.Stack(buf, true)
		_, err := conn.Write(buf[:n])
		return err
	case signal.GC:
		runtime.GC()
		_, err := conn.Write([]byte("ok"))
		return err
	case signal.MemStats:
		var s runtime.MemStats
		runtime.ReadMemStats(&s)
		fmt.Fprintf(conn, "alloc: %v bytes\n", s.Alloc)
		fmt.Fprintf(conn, "total-alloc: %v bytes\n", s.TotalAlloc)
		fmt.Fprintf(conn, "sys: %v bytes\n", s.Sys)
		fmt.Fprintf(conn, "lookups: %v\n", s.Lookups)
		fmt.Fprintf(conn, "mallocs: %v\n", s.Mallocs)
		fmt.Fprintf(conn, "frees: %v\n", s.Frees)
		fmt.Fprintf(conn, "heap-alloc: %v bytes\n", s.HeapAlloc)
		fmt.Fprintf(conn, "heap-sys: %v bytes\n", s.HeapSys)
		fmt.Fprintf(conn, "heap-idle: %v bytes\n", s.HeapIdle)
		fmt.Fprintf(conn, "heap-in-use: %v bytes\n", s.HeapInuse)
		fmt.Fprintf(conn, "heap-released: %v bytes\n", s.HeapReleased)
		fmt.Fprintf(conn, "heap-objects: %v\n", s.HeapObjects)
		fmt.Fprintf(conn, "stack-in-use: %v bytes\n", s.StackInuse)
		fmt.Fprintf(conn, "stack-sys: %v bytes\n", s.StackSys)
		fmt.Fprintf(conn, "next-gc: when heap-alloc >= %v bytes\n", s.NextGC)
		fmt.Fprintf(conn, "last-gc: %v ns\n", s.LastGC)
		fmt.Fprintf(conn, "gc-pause: %v ns\n", s.PauseTotalNs)
		fmt.Fprintf(conn, "num-gc: %v\n", s.NumGC)
		fmt.Fprintf(conn, "enable-gc: %v\n", s.EnableGC)
		fmt.Fprintf(conn, "debug-gc: %v\n", s.DebugGC)
	case signal.Version:
		fmt.Fprintf(conn, "%v\n", runtime.Version())
	case signal.HeapProfile:
		pprof.Lookup("heap").WriteTo(conn, 0)
	case signal.CPUProfile:
		if err := pprof.StartCPUProfile(conn); err != nil {
			return nil
		}
		time.Sleep(30 * time.Second)
		pprof.StopCPUProfile()
	case signal.Vitals:
		fmt.Fprintf(conn, "goroutines: %v\n", runtime.NumGoroutine())
		fmt.Fprintf(conn, "OS threads: %v\n", pprof.Lookup("threadcreate").Count())
		fmt.Fprintf(conn, "GOMAXPROCS: %v\n", runtime.GOMAXPROCS(0))
		fmt.Fprintf(conn, "num CPU: %v\n", runtime.NumCPU())
	}
	return nil
}
<|endoftext|>


<commit_before>package agent

import (
	"log"
	"time"

	"github.com/coreos/coreinit/machine"
	"github.com/coreos/coreinit/registry"
	"github.com/coreos/coreinit/unit"
)

const (
	DefaultServiceTTL = "2s"
	DefaultMachineTTL = "10s"
	refreshInterval   = 2 // Refresh TTLs at 1/2 the TTL length
)

// The Agent owns all of the coordination between the Registry, the local
// Machine, and the local SystemdManager.
type Agent struct {
	Registry   *registry.Registry
	Manager    *unit.SystemdManager
	Machine    *machine.Machine
	ServiceTTL string
}

func (a *Agent) DoHeartbeat() {
	go a.doServiceHeartbeat()
	a.doMachineHeartbeat()
	return
}

// Keep the local statistics in the Registry up to date
func (a *Agent) doMachineHeartbeat() {
	interval := intervalFromTTL(DefaultMachineTTL)

	c := time.Tick(interval)
	for _ = range c {
		log.Println("tick machine heartbeat")
		a.UpdateMachine()
	}
}

func (a *Agent) UpdateMachine() {
	addrs := a.Machine.GetAddresses()
	ttl := parseDuration(DefaultMachineTTL)
	log.Println("Updating machine", a.Machine, "with addrs", addrs)
	a.Registry.SetMachineAddrs(a.Machine, addrs, ttl)
}

// Keep the state of local units in the Registry up to date
func (a *Agent) doServiceHeartbeat() {
	interval := intervalFromTTL(a.ServiceTTL)

	c := time.Tick(interval)
	for _ = range c {
		log.Println("tick service heartbeat")
		a.UpdateJobs()
	}
}

func (a *Agent) UpdateJobs() {
	registeredJobs := a.Registry.GetMachineJobs(a.Machine)
	localJobs := a.Manager.GetJobs()

	for _, job := range registeredJobs {
		_, ok := localJobs[job.Name]
		if !ok {
			a.Manager.StartJob(&job)
		} else if state := a.Manager.GetJobState(&job); state == nil || state.ActiveState != "active"{
			a.Manager.StartJob(&job)
		}
	}

	// Fetch local jobs again since state may have changed above
	localJobs = a.Manager.GetJobs()

	ttl := uint64(parseDuration(a.ServiceTTL).Seconds())
	for _, job := range localJobs {
		_, ok := registeredJobs[job.Name]

		if ok {
			a.Registry.UpdateJob(&job, ttl)
		} else {
			a.Manager.StopJob(&job)
		}
	}
}

func New(registry *registry.Registry, machine *machine.Machine, ttl string) *Agent {
	mgr := unit.NewSystemdManager(machine)

	if ttl == "" {
		ttl = DefaultServiceTTL
	}

	agent := &Agent{registry, mgr, machine, ttl}

	return agent
}

func parseDuration(d string) time.Duration {
	duration, err := time.ParseDuration(d)
	if err != nil {
		panic(err)
	}

	return duration
}

func intervalFromTTL(ttl string) time.Duration {
	duration := parseDuration(ttl)
	return duration / refreshInterval
}
<commit_msg>fix(agent): Do not manage systemd unit states<commit_after>package agent

import (
	"log"
	"time"

	"github.com/coreos/coreinit/machine"
	"github.com/coreos/coreinit/registry"
	"github.com/coreos/coreinit/unit"
)

const (
	DefaultServiceTTL = "2s"
	DefaultMachineTTL = "10s"
	refreshInterval   = 2 // Refresh TTLs at 1/2 the TTL length
)

// The Agent owns all of the coordination between the Registry, the local
// Machine, and the local SystemdManager.
type Agent struct {
	Registry   *registry.Registry
	Manager    *unit.SystemdManager
	Machine    *machine.Machine
	ServiceTTL string
}

func (a *Agent) DoHeartbeat() {
	go a.doServiceHeartbeat()
	a.doMachineHeartbeat()
	return
}

// Keep the local statistics in the Registry up to date
func (a *Agent) doMachineHeartbeat() {
	interval := intervalFromTTL(DefaultMachineTTL)

	c := time.Tick(interval)
	for _ = range c {
		log.Println("tick machine heartbeat")
		a.UpdateMachine()
	}
}

func (a *Agent) UpdateMachine() {
	addrs := a.Machine.GetAddresses()
	ttl := parseDuration(DefaultMachineTTL)
	log.Println("Updating machine", a.Machine, "with addrs", addrs)
	a.Registry.SetMachineAddrs(a.Machine, addrs, ttl)
}

// Keep the state of local units in the Registry up to date
func (a *Agent) doServiceHeartbeat() {
	interval := intervalFromTTL(a.ServiceTTL)

	c := time.Tick(interval)
	for _ = range c {
		log.Println("tick service heartbeat")
		a.UpdateJobs()
	}
}

func (a *Agent) UpdateJobs() {
	registeredJobs := a.Registry.GetMachineJobs(a.Machine)
	localJobs := a.Manager.GetJobs()

	for _, job := range registeredJobs {
		_, ok := localJobs[job.Name]
		if !ok {
			a.Manager.StartJob(&job)
		} else if state := a.Manager.GetJobState(&job); state == nil {
			a.Manager.StartJob(&job)
		}
	}

	// Fetch local jobs again since state may have changed above
	localJobs = a.Manager.GetJobs()

	ttl := uint64(parseDuration(a.ServiceTTL).Seconds())
	for _, job := range localJobs {
		_, ok := registeredJobs[job.Name]

		if ok {
			a.Registry.UpdateJob(&job, ttl)
		} else {
			a.Manager.StopJob(&job)
		}
	}
}

func New(registry *registry.Registry, machine *machine.Machine, ttl string) *Agent {
	mgr := unit.NewSystemdManager(machine)

	if ttl == "" {
		ttl = DefaultServiceTTL
	}

	agent := &Agent{registry, mgr, machine, ttl}

	return agent
}

func parseDuration(d string) time.Duration {
	duration, err := time.ParseDuration(d)
	if err != nil {
		panic(err)
	}

	return duration
}

func intervalFromTTL(ttl string) time.Duration {
	duration := parseDuration(ttl)
	return duration / refreshInterval
}
<|endoftext|>


<commit_before>package alias

import (
	"context"
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"unicode"

	"github.com/zetamatta/nyagos/completion"
	"github.com/zetamatta/nyagos/shell"
)

var dbg = false

type callableT interface {
	String() string
	Call(ctx context.Context, cmd *shell.Cmd) (int, error)
}

type AliasFunc struct {
	BaseStr string
}

func New(baseStr string) *AliasFunc {
	return &AliasFunc{baseStr}
}

func (this *AliasFunc) String() string {
	return this.BaseStr
}

func (this *AliasFunc) Call(ctx context.Context, cmd *shell.Cmd) (next int, err error) {
	isReplaced := false
	if dbg {
		print("AliasFunc.Call('", cmd.Arg(0), "')\n")
	}
	cmdline := paramMatch.ReplaceAllStringFunc(this.BaseStr, func(s string) string {
		if s == "$~*" {
			isReplaced = true
			if cmd.Args() != nil && len(cmd.Args()) >= 2 {
				return strings.Join(cmd.Args()[1:], " ")
			} else {
				return ""
			}
		} else if s == "$*" {
			isReplaced = true
			if cmd.Args() != nil && len(cmd.Args()) >= 2 {
				return strings.Join(cmd.RawArgs()[1:], " ")
			} else {
				return ""
			}
		} else if len(s) >= 3 && s[0] == '$' && s[1] == '~' && unicode.IsDigit(rune(s[2])) {
			i, err := strconv.ParseInt(s[2:], 10, 0)
			if err == nil {
				isReplaced = true
				if 0 <= i && cmd.Args() != nil && int(i) < len(cmd.Args()) {
					return cmd.Arg(int(i))
				} else {
					return ""
				}
			}
		}
		i, err := strconv.ParseInt(s[1:], 10, 0)
		if err == nil {
			isReplaced = true
			if 0 <= i && cmd.Args() != nil && int(i) < len(cmd.Args()) {
				return cmd.RawArg(int(i))
			} else {
				return ""
			}
		}
		return s
	})

	if !isReplaced {
		var buffer strings.Builder
		buffer.WriteString(this.BaseStr)
		for _, s := range cmd.RawArgs()[1:] {
			fmt.Fprintf(&buffer, " %s", s)
		}
		cmdline = buffer.String()
	}
	if dbg {
		print("replaced cmdline=='", cmdline, "'\n")
	}
	next, err = cmd.Interpret(ctx, cmdline)
	return
}

var Table = map[string]callableT{}
var paramMatch = regexp.MustCompile(`\$(\~)?(\*|[0-9]+)`)

func AllNames() []completion.Element {
	names := make([]completion.Element, 0, len(Table))
	for name1 := range Table {
		names = append(names, completion.Element1(name1))
	}
	return names
}

var nextHook shell.HookT

type noAliasT string

func hook(ctx context.Context, cmd *shell.Cmd) (int, bool, error) {
	lowerName := strings.ToLower(cmd.Arg(0))
	ctxKey := noAliasT(lowerName)
	if ctx.Value(ctxKey) != nil {
		return nextHook(ctx, cmd)
	}
	callee, ok := Table[lowerName]
	if !ok {
		return nextHook(ctx, cmd)
	}
	next, err := callee.Call(context.WithValue(ctx, ctxKey, true), cmd)
	return next, true, err
}

func Init() {
	nextHook = shell.SetHook(hook)
}
<commit_msg>Fix for golint: alias/*.go<commit_after>package alias

import (
	"context"
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"unicode"

	"github.com/zetamatta/nyagos/completion"
	"github.com/zetamatta/nyagos/shell"
)

var dbg = false

type callableT interface {
	String() string
	Call(ctx context.Context, cmd *shell.Cmd) (int, error)
}

// Func is the type for string-type alias. It has a Call method
type Func struct {
	BaseStr string
}

// New is the constructor for Func
func New(baseStr string) *Func {
	return &Func{baseStr}
}

// String is the method to support fmt.Stringer
func (f *Func) String() string {
	return f.BaseStr
}

// Call is the method to support callableT and it calls the alias-function.
func (f *Func) Call(ctx context.Context, cmd *shell.Cmd) (next int, err error) {
	isReplaced := false
	if dbg {
		print("Func.Call('", cmd.Arg(0), "')\n")
	}
	cmdline := paramMatch.ReplaceAllStringFunc(f.BaseStr, func(s string) string {
		if s == "$~*" {
			isReplaced = true
			if cmd.Args() != nil && len(cmd.Args()) >= 2 {
				return strings.Join(cmd.Args()[1:], " ")
			}
			return ""
		} else if s == "$*" {
			isReplaced = true
			if cmd.Args() != nil && len(cmd.Args()) >= 2 {
				return strings.Join(cmd.RawArgs()[1:], " ")
			}
			return ""
		} else if len(s) >= 3 && s[0] == '$' && s[1] == '~' && unicode.IsDigit(rune(s[2])) {
			i, err := strconv.ParseInt(s[2:], 10, 0)
			if err == nil {
				isReplaced = true
				if 0 <= i && cmd.Args() != nil && int(i) < len(cmd.Args()) {
					return cmd.Arg(int(i))
				}
				return ""
			}
		}
		i, err := strconv.ParseInt(s[1:], 10, 0)
		if err == nil {
			isReplaced = true
			if 0 <= i && cmd.Args() != nil && int(i) < len(cmd.Args()) {
				return cmd.RawArg(int(i))
			}
			return ""
		}
		return s
	})

	if !isReplaced {
		var buffer strings.Builder
		buffer.WriteString(f.BaseStr)
		for _, s := range cmd.RawArgs()[1:] {
			fmt.Fprintf(&buffer, " %s", s)
		}
		cmdline = buffer.String()
	}
	if dbg {
		print("replaced cmdline=='", cmdline, "'\n")
	}
	next, err = cmd.Interpret(ctx, cmdline)
	return
}

// Table is the ALL ALIAS table !
var Table = map[string]callableT{}
var paramMatch = regexp.MustCompile(`\$(\~)?(\*|[0-9]+)`)

// AllNames returns all-alias names for completion
func AllNames() []completion.Element {
	names := make([]completion.Element, 0, len(Table))
	for name1 := range Table {
		names = append(names, completion.Element1(name1))
	}
	return names
}

var nextHook shell.HookT

type noAliasT string

func hook(ctx context.Context, cmd *shell.Cmd) (int, bool, error) {
	lowerName := strings.ToLower(cmd.Arg(0))
	ctxKey := noAliasT(lowerName)
	if ctx.Value(ctxKey) != nil {
		return nextHook(ctx, cmd)
	}
	callee, ok := Table[lowerName]
	if !ok {
		return nextHook(ctx, cmd)
	}
	next, err := callee.Call(context.WithValue(ctx, ctxKey, true), cmd)
	return next, true, err
}

// Init is the package initializer which inserts hook-function into shell package.
func Init() {
	nextHook = shell.SetHook(hook)
}
<|endoftext|>


<commit_before>package rest

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"path/filepath"
	"strconv"
	"strings"
)

const (
	volumesPath      = "/api/1.0/volumes"
	volumeCreatePath = "/api/1.0/volume/%s"
	volumeStopPath   = "/api/1.0/volume/%s/stop"
)

type peer struct {
	ID     string `json:"id"`
	Name   string `json:"name"`
	Status string `json:"status"`
}

type volume struct {
	Name       string `json:"name"`
	UUID       string `json:"uuid"`
	Type       string `json:"type"`
	Status     string `json:"status"`
	NumBricks  int    `json:"num_bricks"`
	Distribute int    `json:"distribute"`
	Stripe     int    `json:"stripe"`
	Replica    int    `json:"replica"`
	Transport  string `json:"transport"`
}

type response struct {
	Ok  bool   `json:"ok"`
	Err string `json:"error,omitempty"`
}

type peerResponse struct {
	Data []peer `json:"data",omitempty`
	response
}

type volumeResponse struct {
	Data []volume `json:"data",omitempty`
	response
}

// Client is the http client that sends requests to the gluster API.
type Client struct {
	addr string
	base string
}

// NewClient initializes a new client.
func NewClient(addr, base string) *Client {
	return &Client{addr, base}
}

// VolumeExist returns whether a volume exist in the cluster with a given name or not.
func (r Client) VolumeExist(name string) (bool, error) {
	vols, err := r.volumes()
	if err != nil {
		return false, err
	}

	for _, v := range vols {
		if v.Name == name {
			return true, nil
		}
	}

	return false, nil
}

func (r Client) volumes() ([]volume, error) {
	u := fmt.Sprintf("%s%s", r.addr, volumesPath)

	res, err := http.Get(u)
	if err != nil {
		return nil, err
	}

	var d volumeResponse
	if err := json.NewDecoder(res.Body).Decode(&d); err != nil {
		return nil, err
	}

	if !d.Ok {
		return nil, fmt.Errorf(d.Err)
	}
	return d.Data, nil
}

// CreateVolume creates a new volume with the given name in the cluster.
func (r Client) CreateVolume(name string, peers []string) error {
	u := fmt.Sprintf("%s%s", r.addr, fmt.Sprintf(volumeCreatePath, name))
	fmt.Println(u)

	bricks := make([]string, len(peers))
	for i, p := range peers {
		bricks[i] = fmt.Sprintf("%s:%s", p, filepath.Join(r.base, name))
	}

	params := url.Values{
		"bricks":    {strings.Join(bricks, ",")},
		"replica":   {strconv.Itoa(len(peers))},
		"transport": {"tcp"},
		"start":     {"true"},
		"force":     {"true"},
	}

	resp, err := http.PostForm(u, params)
	if err != nil {
		return err
	}

	return responseCheck(resp)
}

// StopVolume stops the volume with the given name in the cluster.
func (r Client) StopVolume(name string) error {
	u := fmt.Sprintf("%s%s", r.addr, fmt.Sprintf(volumeStopPath, name))

	req, err := http.NewRequest("PUT", u, nil)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}

	return responseCheck(resp)
}

func responseCheck(resp *http.Response) error {
	var p response
	if err := json.NewDecoder(resp.Body).Decode(&p); err != nil {
		return err
	}

	if !p.Ok {
		return fmt.Errorf(p.Err)
	}

	return nil
}
<commit_msg>Fix json tag.<commit_after>package rest

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"path/filepath"
	"strconv"
	"strings"
)

const (
	volumesPath      = "/api/1.0/volumes"
	volumeCreatePath = "/api/1.0/volume/%s"
	volumeStopPath   = "/api/1.0/volume/%s/stop"
)

type peer struct {
	ID     string `json:"id"`
	Name   string `json:"name"`
	Status string `json:"status"`
}

type volume struct {
	Name       string `json:"name"`
	UUID       string `json:"uuid"`
	Type       string `json:"type"`
	Status     string `json:"status"`
	NumBricks  int    `json:"num_bricks"`
	Distribute int    `json:"distribute"`
	Stripe     int    `json:"stripe"`
	Replica    int    `json:"replica"`
	Transport  string `json:"transport"`
}

type response struct {
	Ok  bool   `json:"ok"`
	Err string `json:"error,omitempty"`
}

type peerResponse struct {
	Data []peer `json:"data,omitempty"`
	response
}

type volumeResponse struct {
	Data []volume `json:"data,omitempty"`
	response
}

// Client is the http client that sends requests to the gluster API.
type Client struct {
	addr string
	base string
}

// NewClient initializes a new client.
func NewClient(addr, base string) *Client {
	return &Client{addr, base}
}

// VolumeExist returns whether a volume exist in the cluster with a given name or not.
func (r Client) VolumeExist(name string) (bool, error) {
	vols, err := r.volumes()
	if err != nil {
		return false, err
	}

	for _, v := range vols {
		if v.Name == name {
			return true, nil
		}
	}

	return false, nil
}

func (r Client) volumes() ([]volume, error) {
	u := fmt.Sprintf("%s%s", r.addr, volumesPath)

	res, err := http.Get(u)
	if err != nil {
		return nil, err
	}

	var d volumeResponse
	if err := json.NewDecoder(res.Body).Decode(&d); err != nil {
		return nil, err
	}

	if !d.Ok {
		return nil, fmt.Errorf(d.Err)
	}
	return d.Data, nil
}

// CreateVolume creates a new volume with the given name in the cluster.
func (r Client) CreateVolume(name string, peers []string) error {
	u := fmt.Sprintf("%s%s", r.addr, fmt.Sprintf(volumeCreatePath, name))
	fmt.Println(u)

	bricks := make([]string, len(peers))
	for i, p := range peers {
		bricks[i] = fmt.Sprintf("%s:%s", p, filepath.Join(r.base, name))
	}

	params := url.Values{
		"bricks":    {strings.Join(bricks, ",")},
		"replica":   {strconv.Itoa(len(peers))},
		"transport": {"tcp"},
		"start":     {"true"},
		"force":     {"true"},
	}

	resp, err := http.PostForm(u, params)
	if err != nil {
		return err
	}

	return responseCheck(resp)
}

// StopVolume stops the volume with the given name in the cluster.
func (r Client) StopVolume(name string) error {
	u := fmt.Sprintf("%s%s", r.addr, fmt.Sprintf(volumeStopPath, name))

	req, err := http.NewRequest("PUT", u, nil)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}

	return responseCheck(resp)
}

func responseCheck(resp *http.Response) error {
	var p response
	if err := json.NewDecoder(resp.Body).Decode(&p); err != nil {
		return err
	}

	if !p.Ok {
		return fmt.Errorf(p.Err)
	}

	return nil
}
<|endoftext|>


<commit_before>package ov

import (
	"encoding/json"
	"fmt"
	"github.com/HewlettPackard/oneview-golang/rest"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
)

// The Marshal() will omit the bool attibutes below if they are false.
// Please remove the omitempty option and use it as and when required.

type StorageVolume struct {
	Category                  string                    `json:"category,omitempty"`
	Created                   string                    `json:"created,omitempty"`
	Description               utils.Nstring             `json:"description,omitempty"`
	ETAG                      string                    `json:"eTag,omitempty"`
	Name                      string                    `json:"name,omitempty"`
	State                     string                    `json:"state,omitempty"`
	Status                    string                    `json:"status,omitempty"`
	Type                      string                    `json:"type,omitempty"`
	URI                       utils.Nstring             `json:"uri,omitempty"`
	DeviceVolumeName          string                    `json:"deviceVolumeName,omitempty"`
	RequestingRefresh         bool                      `json:"requestingRefresh,omitempty"`
	AllocatedCapacity         string                    `json:"allocatedCapacity,omitempty"`
	InitialScopeUris          utils.Nstring             `json:"initialScopeUris,omitempty"`
	DeviceSpecificAttributes  *DeviceSpecificAttributes `json:"deviceSpecificAttributes,omitempty"`
	VolumeTemplateUri         utils.Nstring             `json:"volumeTemplateUri,omitempty"`
	IsShareable               bool                      `json:"isShareable,omitempty"`
	StoragePoolUri            utils.Nstring             `json:"storagePoolUri,omitempty"`
	StorageSystemUri          utils.Nstring             `json:"storageSystemUri,omitempty"`
	ProvisionedCapacity       string                    `json:"provisionedCapacity,omitempty"`
	Properties                *Properties               `json:"properties,omitempty"`
	TemplateURI               utils.Nstring             `json:"templateURI,omitempty"`
	IsPermanent               bool                      `json:"isPermanent,omitempty"`
	ProvisioningTypeForUpdate string                    `json:"provisioningType,omitempty"`
	TemplateVersion           string                    `json:"templateVersion,omitempty"`
	//	Wwn										string				`json:""`

	/*
	   Category              string        `json:"category,omitempty"`              //  "type": "StorageVolume",
	   Created               string        `json:"created,omitempty"`               //  "created": "2016-06-20T22:48:14.422Z"
	   Description           string        `json:"description,omitempty"`           //  "description": "Integration test volume 2",
	   ETAG                  string        `json:"eTag,omitempty"`                  //  "eTag": "2016-06-20T22:48:17.704Z",            string        `json:"modified,omitempty"`              // "modified": "20150831T154835.250Z",
	   Name                  string        `json:"name,omitempty"`                  //  "name": "Volume_2",
	   State                 string        `json:"state,omitempty"`                 //  "state": "Configured",
	   Status                string        `json:"status,omitempty"`                //  "status": "OK",
	   Type                  string        `json:"type,omitempty"`                  //  "type": "StorageVolume",
	   URI                   utils.Nstring `json:"uri,omitempty"`                   //  "uri": "/rest/storage-volumes/527801AC-B6B6-4A63-8510-D32906C9C57B"
	   Shareable							string				`json:"shareable,omitempty"`                                //  "shareable": false,
	   AllocatedCapacity			string				`json:""`																 //  "allocatedCapacity": "1073741824",
	   DeviceType						string				`json:""`																 //  "deviceType": "SSD",
	   DeviceVolumeName			string				`json:""`                                //  "deviceVolumeName": "Volume_2",
	   IsPermanent						string 				`json:""`                                //  "isPermanent": true,
	   RaidLevel							string				`json:""`                								 //  "raidLevel": "RAID5",
	   RefreshState					string				`json:""`                                //  "refreshState": "NotRefreshing",
	   RevertToSnapshotUri		string				`json:""`                                //  "revertToSnapshotUri": null,
	   SnapshotPoolUri				string				`json:""`                                //  "snapshotPoolUri": "/rest/storage-pools/000D692C-74B3-44AC-B297-3741AABE29F8",
	   Snapshots							string				`json:""`                                //  "snapshots": null,
	   StateReason						string				`json:""`                                //  "stateReason": "None",
	   StoragePoolUri				string				`json:"storagePoolUri,omitempty"`        //  "storagePoolUri": "/rest/storage-pools/000D692C-74B3-44AC-B297-3741AABE29F8",
	   StorageSystemUri			string				`json:"storageSystemUri,omitempty"`      //  "storageSystemUri": "/rest/storage-systems/TXQ1000307",
	   ProvisionType					string 				`json:"provisionType,omitempty"`         //  "provisionType": "Full",
	   ProvisionedCapacity		string				`json:"provisionedCapacity,omitempty"`   //  "provisionedCapacity": "1073741824",
	   ProvisioningParameters []ProvisioningParameters		`json:"provisioningParameters,omitempty"`
	   //	Wwn										string				`json:""`                                //  "wwn": "DC:57:93:56:32:00:10:00:30:71:46:64:62:89:52:11",

	*/
}

type ProvisioningParameters struct {
	StoragePoolUri    utils.Nstring `json:"storagePoolUri,omitempty"`
	ProvisionType     string        `json:"provisionType,omitempty"`
	RequestedCapacity string        `json:"requestedCapacity,omitempty"`
	Shareable         bool          `json:"shareable,omitempty"`
}

type Properties struct {
	Name                string        `json:"name,omitempty"`
	Storagepool         utils.Nstring `json:"storagePool,omitempty"`
	Size                int           `json:"size,omitempty"`
	ProvisioningType    string        `json:"provisioningType,omitempty"`
	DataTransferLimit   int           `json:"dataTransferLimit,omitempty"`
	IsDeduplicated      bool          `json:"isDeduplicated,omitempty"`
	IsEncrypted         bool          `json:"isEncrypted,omitempty"`
	IsPinned            bool          `json:"isPinned,omitempty"`
	isCompressed        bool          `json:"IsCompressed,omitempty"`
	DataProtectionLevel string        `json:"dataProtectionLevel,omitempty"`
}

type DeviceSpecificAttributes struct {
	ApplicationCategory           string        `json:"applicationCategory,omitempty"`
	BlockSize                     int           `json:"blockSize,omitempty"`
	DataTransferLimit             int           `json:"dataTransferLimit,omitempty"`
	FolderId                      string        `json:"folderId,omitempty"`
	FolderName                    string        `json:"folderName,omitempty"`
	IopsLimit                     int           `json:"iopsLimit,omitempty"`
	IsDeduplicated                bool          `json:"isDeduplicated,omitempty"`
	IsEncrypted                   bool          `json:"isEncrypted,omitempty"`
	IsPinned                      bool          `json:"isPinned,omitempty"`
	PreviouslyDeduplicated        bool          `json:"previouslyDeduplicated,omitempty"`
	isCompressed                  bool          `json:"IsCompressed,omitempty"`
	Transport                     string        `json:"transport,omitempty"`
	Iqn                           string        `json:"iqn,omitempty"`
	NumberOfReplicas              int           `json:"numberOfReplicas,omitempty"`
	DataProtectionLevel           string        `json:"dataProtectionLevel,omitempty"`
	Id                            int           `json:"id,omitempty"`
	Uri                           utils.Nstring `json:"uri,omitempty"`
	CopyState                     string        `json:"copyState,omitempty"`
	SnapshotPoolUri               utils.Nstring `json:"snapshotPoolUri,omitempty"`
	IsAdaptiveOptimizationEnabled bool          `json:"isAdaptiveOptimizationEnabled,omitempty"`
}

type StorageVolumesList struct {
	Total       int             `json:"total,omitempty"`       // "total": 1,
	Count       int             `json:"count,omitempty"`       // "count": 1,
	Start       int             `json:"start,omitempty"`       // "start": 0,
	PrevPageURI utils.Nstring   `json:"prevPageUri,omitempty"` // "prevPageUri": null,
	NextPageURI utils.Nstring   `json:"nextPageUri,omitempty"` // "nextPageUri": null,
	URI         utils.Nstring   `json:"uri,omitempty"`         // "uri": "/rest/server-profiles?filter=connectionTemplateUri%20matches%7769cae0-b680-435b-9b87-9b864c81657fsort=name:asc"
	Members     []StorageVolume `json:"members,omitempty"`     // "members":[]
}

func (c *OVClient) GetStorageVolumeByName(name string) (StorageVolume, error) {
	var (
		sVol StorageVolume
	)
	sVols, err := c.GetStorageVolumes(fmt.Sprintf("name matches '%s'", name), "name:asc")
	if sVols.Total > 0 {
		return sVols.Members[0], err
	} else {
		return sVol, err
	}
}

func (c *OVClient) GetStorageVolumes(filter string, sort string) (StorageVolumesList, error) {
	var (
		uri   = "/rest/storage-volumes"
		q     map[string]interface{}
		sVols StorageVolumesList
	)
	q = make(map[string]interface{})
	if len(filter) > 0 {
		q["filter"] = filter
	}

	if sort != "" {
		q["sort"] = sort
	}

	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())
	// Setup query
	if len(q) > 0 {
		c.SetQueryString(q)
	}

	data, err := c.RestAPICall(rest.GET, uri, nil)
	if err != nil {
		return sVols, err
	}

	log.Debugf("GetStorageVolumes %s", data)
	if err := json.Unmarshal([]byte(data), &sVols); err != nil {
		return sVols, err
	}
	return sVols, nil
}

func (c *OVClient) CreateStorageVolume(sVol StorageVolume) error {
	log.Infof("Initializing creation of storage volume for %s.", sVol.Name)
	var (
		uri = "/rest/storage-volumes"
		t   *Task
	)
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	t = t.NewProfileTask(c)
	t.ResetTask()
	log.Debugf("REST : %s \n %+v\n", uri, sVol)
	log.Debugf("task -> %+v", t)

	data, err := c.RestAPICall(rest.POST, uri, sVol)
	if err != nil {
		t.TaskIsDone = true
		log.Errorf("Error submitting new storage volume request: %s", err)
		return err
	}

	log.Debugf("Response New StorageVolume %s", data)
	if err := json.Unmarshal([]byte(data), &t); err != nil {
		t.TaskIsDone = true
		log.Errorf("Error with task un-marshal: %s", err)
		return err
	}

	err = t.Wait()
	if err != nil {
		return err
	}

	return nil
}

func (c *OVClient) DeleteStorageVolume(name string) error {
	var (
		sVol StorageVolume
		err  error
		t    *Task
		uri  string
	)

	sVol, err = c.GetStorageVolumeByName(name)
	if err != nil {
		return err
	}
	if sVol.Name != "" {
		t = t.NewProfileTask(c)
		t.ResetTask()
		log.Debugf("REST : %s \n %+v\n", sVol.URI, sVol)
		log.Debugf("task -> %+v", t)
		uri = sVol.URI.String()
		if uri == "" {
			log.Warn("Unable to post delete, no uri found.")
			t.TaskIsDone = true
			return err
		}
		data, err := c.RestAPICall(rest.DELETE, uri, nil)
		if err != nil {
			log.Errorf("Error submitting delete storage volume request: %s", err)
			t.TaskIsDone = true
			return err
		}

		log.Debugf("Response delete storage volume %s", data)
		if err := json.Unmarshal([]byte(data), &t); err != nil {
			t.TaskIsDone = true
			log.Errorf("Error with task un-marshal: %s", err)
			return err
		}
		err = t.Wait()
		if err != nil {
			return err
		}
		return nil
	} else {
		log.Infof("StorageVolume could not be found to delete, %s, skipping delete ...", name)
	}
	return nil
}

func (c *OVClient) UpdateStorageVolume(sVol StorageVolume) error {
	log.Infof("Initializing update of storage volume for %s.", sVol.Name)
	var (
		uri = sVol.URI.String()
		t   *Task
	)
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	t = t.NewProfileTask(c)
	t.ResetTask()
	log.Debugf("REST : %s \n %+v\n", uri, sVol)
	log.Debugf("task -> %+v", t)
	data, err := c.RestAPICall(rest.PUT, uri, sVol)
	if err != nil {
		t.TaskIsDone = true
		log.Errorf("Error submitting update StorageVolume request: %s", err)
		return err
	}
	log.Debugf("Response update StorageVolume %s", data)
	if err := json.Unmarshal([]byte(data), &t); err != nil {
		t.TaskIsDone = true
		log.Errorf("Error with task un-marshal: %s", err)
		return err
	}

	err = t.Wait()
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>review comments<commit_after>package ov

import (
	"encoding/json"
	"fmt"
	"github.com/HewlettPackard/oneview-golang/rest"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
)

// The Marshal() will omit the bool attibutes below if they are false.
// Please remove the omitempty option and use it as and when required.

type StorageVolume struct {
	Category                  string                    `json:"category,omitempty"`
	Created                   string                    `json:"created,omitempty"`
	Description               utils.Nstring             `json:"description,omitempty"`
	ETAG                      string                    `json:"eTag,omitempty"`
	Name                      string                    `json:"name,omitempty"`
	State                     string                    `json:"state,omitempty"`
	Status                    string                    `json:"status,omitempty"`
	Type                      string                    `json:"type,omitempty"`
	URI                       utils.Nstring             `json:"uri,omitempty"`
	DeviceVolumeName          string                    `json:"deviceVolumeName,omitempty"`
	RequestingRefresh         bool                      `json:"requestingRefresh,omitempty"`
	AllocatedCapacity         string                    `json:"allocatedCapacity,omitempty"`
	InitialScopeUris          utils.Nstring             `json:"initialScopeUris,omitempty"`
	DeviceSpecificAttributes  *DeviceSpecificAttributes `json:"deviceSpecificAttributes,omitempty"`
	VolumeTemplateUri         utils.Nstring             `json:"volumeTemplateUri,omitempty"`
	IsShareable               bool                      `json:"isShareable,omitempty"`
	StoragePoolUri            utils.Nstring             `json:"storagePoolUri,omitempty"`
	StorageSystemUri          utils.Nstring             `json:"storageSystemUri,omitempty"`
	ProvisionedCapacity       string                    `json:"provisionedCapacity,omitempty"`
	Properties                *Properties               `json:"properties,omitempty"`
	TemplateURI               utils.Nstring             `json:"templateURI,omitempty"`
	IsPermanent               bool                      `json:"isPermanent,omitempty"`
	ProvisioningTypeForUpdate string                    `json:"provisioningType,omitempty"`
	TemplateVersion           string                    `json:"templateVersion,omitempty"`
	//	Wwn										string				`json:""`

	/*
	   Category              string        `json:"category,omitempty"`              //  "type": "StorageVolume",
	   Created               string        `json:"created,omitempty"`               //  "created": "2016-06-20T22:48:14.422Z"
	   Description           string        `json:"description,omitempty"`           //  "description": "Integration test volume 2",
	   ETAG                  string        `json:"eTag,omitempty"`                  //  "eTag": "2016-06-20T22:48:17.704Z",            string        `json:"modified,omitempty"`              // "modified": "20150831T154835.250Z",
	   Name                  string        `json:"name,omitempty"`                  //  "name": "Volume_2",
	   State                 string        `json:"state,omitempty"`                 //  "state": "Configured",
	   Status                string        `json:"status,omitempty"`                //  "status": "OK",
	   Type                  string        `json:"type,omitempty"`                  //  "type": "StorageVolume",
	   URI                   utils.Nstring `json:"uri,omitempty"`                   //  "uri": "/rest/storage-volumes/527801AC-B6B6-4A63-8510-D32906C9C57B"
	   Shareable							string				`json:"shareable,omitempty"`                                //  "shareable": false,
	   AllocatedCapacity			string				`json:""`																 //  "allocatedCapacity": "1073741824",
	   DeviceType						string				`json:""`																 //  "deviceType": "SSD",
	   DeviceVolumeName			string				`json:""`                                //  "deviceVolumeName": "Volume_2",
	   IsPermanent						string 				`json:""`                                //  "isPermanent": true,
	   RaidLevel							string				`json:""`                								 //  "raidLevel": "RAID5",
	   RefreshState					string				`json:""`                                //  "refreshState": "NotRefreshing",
	   RevertToSnapshotUri		string				`json:""`                                //  "revertToSnapshotUri": null,
	   SnapshotPoolUri				string				`json:""`                                //  "snapshotPoolUri": "/rest/storage-pools/000D692C-74B3-44AC-B297-3741AABE29F8",
	   Snapshots							string				`json:""`                                //  "snapshots": null,
	   StateReason						string				`json:""`                                //  "stateReason": "None",
	   StoragePoolUri				string				`json:"storagePoolUri,omitempty"`        //  "storagePoolUri": "/rest/storage-pools/000D692C-74B3-44AC-B297-3741AABE29F8",
	   StorageSystemUri			string				`json:"storageSystemUri,omitempty"`      //  "storageSystemUri": "/rest/storage-systems/TXQ1000307",
	   ProvisionType					string 				`json:"provisionType,omitempty"`         //  "provisionType": "Full",
	   ProvisionedCapacity		string				`json:"provisionedCapacity,omitempty"`   //  "provisionedCapacity": "1073741824",
	   ProvisioningParameters []ProvisioningParameters		`json:"provisioningParameters,omitempty"`
	   //	Wwn										string				`json:""`                                //  "wwn": "DC:57:93:56:32:00:10:00:30:71:46:64:62:89:52:11",

	*/
}

type ProvisioningParameters struct {
	StoragePoolUri    utils.Nstring `json:"storagePoolUri,omitempty"`
	ProvisionType     string        `json:"provisionType,omitempty"`
	RequestedCapacity string        `json:"requestedCapacity,omitempty"`
	Shareable         bool          `json:"shareable,omitempty"`
}

type Properties struct {
	Name                string        `json:"name,omitempty"`
	Storagepool         utils.Nstring `json:"storagePool,omitempty"`
	Size                int           `json:"size,omitempty"`
	ProvisioningType    string        `json:"provisioningType,omitempty"`
	DataTransferLimit   int           `json:"dataTransferLimit,omitempty"`
	IsDeduplicated      bool          `json:"isDeduplicated,omitempty"`
	IsEncrypted         bool          `json:"isEncrypted,omitempty"`
	IsPinned            bool          `json:"isPinned,omitempty"`
	IsCompressed        bool          `json:"isCompressed,omitempty"`
	DataProtectionLevel string        `json:"dataProtectionLevel,omitempty"`
}

type DeviceSpecificAttributes struct {
	ApplicationCategory           string        `json:"applicationCategory,omitempty"`
	BlockSize                     int           `json:"blockSize,omitempty"`
	DataTransferLimit             int           `json:"dataTransferLimit,omitempty"`
	FolderId                      string        `json:"folderId,omitempty"`
	FolderName                    string        `json:"folderName,omitempty"`
	IopsLimit                     int           `json:"iopsLimit,omitempty"`
	IsDeduplicated                bool          `json:"isDeduplicated,omitempty"`
	IsEncrypted                   bool          `json:"isEncrypted,omitempty"`
	IsPinned                      bool          `json:"isPinned,omitempty"`
	PreviouslyDeduplicated        bool          `json:"previouslyDeduplicated,omitempty"`
	IsCompressed                  bool          `json:"isCompressed,omitempty"`
	Transport                     string        `json:"transport,omitempty"`
	Iqn                           string        `json:"iqn,omitempty"`
	NumberOfReplicas              int           `json:"numberOfReplicas,omitempty"`
	DataProtectionLevel           string        `json:"dataProtectionLevel,omitempty"`
	Id                            int           `json:"id,omitempty"`
	Uri                           utils.Nstring `json:"uri,omitempty"`
	CopyState                     string        `json:"copyState,omitempty"`
	SnapshotPoolUri               utils.Nstring `json:"snapshotPoolUri,omitempty"`
	IsAdaptiveOptimizationEnabled bool          `json:"isAdaptiveOptimizationEnabled,omitempty"`
}

type StorageVolumesList struct {
	Total       int             `json:"total,omitempty"`       // "total": 1,
	Count       int             `json:"count,omitempty"`       // "count": 1,
	Start       int             `json:"start,omitempty"`       // "start": 0,
	PrevPageURI utils.Nstring   `json:"prevPageUri,omitempty"` // "prevPageUri": null,
	NextPageURI utils.Nstring   `json:"nextPageUri,omitempty"` // "nextPageUri": null,
	URI         utils.Nstring   `json:"uri,omitempty"`         // "uri": "/rest/server-profiles?filter=connectionTemplateUri%20matches%7769cae0-b680-435b-9b87-9b864c81657fsort=name:asc"
	Members     []StorageVolume `json:"members,omitempty"`     // "members":[]
}

func (c *OVClient) GetStorageVolumeByName(name string) (StorageVolume, error) {
	var (
		sVol StorageVolume
	)
	sVols, err := c.GetStorageVolumes(fmt.Sprintf("name matches '%s'", name), "name:asc")
	if sVols.Total > 0 {
		return sVols.Members[0], err
	} else {
		return sVol, err
	}
}

func (c *OVClient) GetStorageVolumes(filter string, sort string) (StorageVolumesList, error) {
	var (
		uri   = "/rest/storage-volumes"
		q     map[string]interface{}
		sVols StorageVolumesList
	)
	q = make(map[string]interface{})
	if len(filter) > 0 {
		q["filter"] = filter
	}

	if sort != "" {
		q["sort"] = sort
	}

	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())
	// Setup query
	if len(q) > 0 {
		c.SetQueryString(q)
	}

	data, err := c.RestAPICall(rest.GET, uri, nil)
	if err != nil {
		return sVols, err
	}

	log.Debugf("GetStorageVolumes %s", data)
	if err := json.Unmarshal([]byte(data), &sVols); err != nil {
		return sVols, err
	}
	return sVols, nil
}

func (c *OVClient) CreateStorageVolume(sVol StorageVolume) error {
	log.Infof("Initializing creation of storage volume for %s.", sVol.Name)
	var (
		uri = "/rest/storage-volumes"
		t   *Task
	)
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	t = t.NewProfileTask(c)
	t.ResetTask()
	log.Debugf("REST : %s \n %+v\n", uri, sVol)
	log.Debugf("task -> %+v", t)

	data, err := c.RestAPICall(rest.POST, uri, sVol)
	if err != nil {
		t.TaskIsDone = true
		log.Errorf("Error submitting new storage volume request: %s", err)
		return err
	}

	log.Debugf("Response New StorageVolume %s", data)
	if err := json.Unmarshal([]byte(data), &t); err != nil {
		t.TaskIsDone = true
		log.Errorf("Error with task un-marshal: %s", err)
		return err
	}

	err = t.Wait()
	if err != nil {
		return err
	}

	return nil
}

func (c *OVClient) DeleteStorageVolume(name string) error {
	var (
		sVol StorageVolume
		err  error
		t    *Task
		uri  string
	)

	sVol, err = c.GetStorageVolumeByName(name)
	if err != nil {
		return err
	}
	if sVol.Name != "" {
		t = t.NewProfileTask(c)
		t.ResetTask()
		log.Debugf("REST : %s \n %+v\n", sVol.URI, sVol)
		log.Debugf("task -> %+v", t)
		uri = sVol.URI.String()
		if uri == "" {
			log.Warn("Unable to post delete, no uri found.")
			t.TaskIsDone = true
			return err
		}
		data, err := c.RestAPICall(rest.DELETE, uri, nil)
		if err != nil {
			log.Errorf("Error submitting delete storage volume request: %s", err)
			t.TaskIsDone = true
			return err
		}

		log.Debugf("Response delete storage volume %s", data)
		if err := json.Unmarshal([]byte(data), &t); err != nil {
			t.TaskIsDone = true
			log.Errorf("Error with task un-marshal: %s", err)
			return err
		}
		err = t.Wait()
		if err != nil {
			return err
		}
		return nil
	} else {
		log.Infof("StorageVolume could not be found to delete, %s, skipping delete ...", name)
	}
	return nil
}

func (c *OVClient) UpdateStorageVolume(sVol StorageVolume) error {
	log.Infof("Initializing update of storage volume for %s.", sVol.Name)
	var (
		uri = sVol.URI.String()
		t   *Task
	)
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	t = t.NewProfileTask(c)
	t.ResetTask()
	log.Debugf("REST : %s \n %+v\n", uri, sVol)
	log.Debugf("task -> %+v", t)
	data, err := c.RestAPICall(rest.PUT, uri, sVol)
	if err != nil {
		t.TaskIsDone = true
		log.Errorf("Error submitting update StorageVolume request: %s", err)
		return err
	}
	log.Debugf("Response update StorageVolume %s", data)
	if err := json.Unmarshal([]byte(data), &t); err != nil {
		t.TaskIsDone = true
		log.Errorf("Error with task un-marshal: %s", err)
		return err
	}

	err = t.Wait()
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>