<commit_before>package proxiedsites

import (
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"github.com/getlantern/detour"
	"github.com/getlantern/golog"
	"github.com/getlantern/proxiedsites"

	"github.com/getlantern/flashlight/config"
	"github.com/getlantern/flashlight/ui"
)

const (
	messageType = `ProxiedSites`
)

var (
	log = golog.LoggerFor("flashlight.proxiedsites")

	service    *ui.Service
	PACURL     string
	startMutex sync.Mutex
)

func Configure(cfg *proxiedsites.Config) {
	delta := proxiedsites.Configure(cfg)
	startMutex.Lock()

	if delta != nil {
		updateDetour(delta)
	}
	if service == nil {
		// Initializing service.
		if err := start(); err != nil {
			log.Errorf("Unable to register service: %q", err)
		}
	} else if delta != nil {
		// Sending delta.
		message := ui.Envelope{
			EnvelopeType: ui.EnvelopeType{messageType},
			Message:      delta,
		}
		b, err := json.Marshal(message)

		if err != nil {
			log.Errorf("Unable to publish delta to UI: %v", err)
		} else {
			service.Out <- b
		}
	}

	startMutex.Unlock()
}

func updateDetour(delta *proxiedsites.Delta) {
	curWl := detour.DumpWhitelist()
	// for simplicity, detour matches whitelist using host:port string
	// so we add ports to each proxiedsites
	for _, v := range delta.Deletions {
		delete(curWl, v+":80")
		delete(curWl, v+":443")
	}
	for _, v := range delta.Additions {
		curWl[v+":80"] = time.Now()
		curWl[v+":443"] = time.Now()
	}
	detour.InitWhitelist(curWl)
}

func start() (err error) {
	newMessage := func() interface{} {
		return &proxiedsites.Delta{}
	}

	// Registering a websocket service.
	helloFn := func(write func(interface{}) error) error {
		return write(proxiedsites.ActiveDelta())
	}

	if service, err = ui.Register(messageType, newMessage, helloFn); err != nil {
		return fmt.Errorf("Unable to register channel: %q", err)
	}

	// Initializing reader.
	go read()

	return nil
}

func read() {
	for msg := range service.In {
		config.Update(func(updated *config.Config) error {
			log.Debugf("Applying update from UI")
			updated.ProxiedSites.Delta.Merge(msg.(*proxiedsites.Delta))
			return nil
		})
	}
}
<commit_msg>set detour country to iran<commit_after>package proxiedsites

import (
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"github.com/getlantern/detour"
	"github.com/getlantern/golog"
	"github.com/getlantern/proxiedsites"

	"github.com/getlantern/flashlight/config"
	"github.com/getlantern/flashlight/ui"
)

const (
	messageType = `ProxiedSites`
)

var (
	log = golog.LoggerFor("flashlight.proxiedsites")

	service    *ui.Service
	PACURL     string
	startMutex sync.Mutex
)

func Configure(cfg *proxiedsites.Config) {
	delta := proxiedsites.Configure(cfg)
	startMutex.Lock()

	if delta != nil {
		updateDetour(delta)
	}
	if service == nil {
		// Initializing service.
		if err := start(); err != nil {
			log.Errorf("Unable to register service: %q", err)
		}
	} else if delta != nil {
		// Sending delta.
		message := ui.Envelope{
			EnvelopeType: ui.EnvelopeType{messageType},
			Message:      delta,
		}
		b, err := json.Marshal(message)

		if err != nil {
			log.Errorf("Unable to publish delta to UI: %v", err)
		} else {
			service.Out <- b
		}
	}

	startMutex.Unlock()
}

func updateDetour(delta *proxiedsites.Delta) {
	// TODO: subscribe changes of geolookup and set country accordingly
	// safe to hardcode here as IR has all detection rules
	detour.SetCountry("IR")
	curWl := detour.DumpWhitelist()
	// for simplicity, detour matches whitelist using host:port string
	// so we add ports to each proxiedsites
	for _, v := range delta.Deletions {
		delete(curWl, v+":80")
		delete(curWl, v+":443")
	}
	for _, v := range delta.Additions {
		curWl[v+":80"] = time.Now()
		curWl[v+":443"] = time.Now()
	}
	detour.InitWhitelist(curWl)
}

func start() (err error) {
	newMessage := func() interface{} {
		return &proxiedsites.Delta{}
	}

	// Registering a websocket service.
	helloFn := func(write func(interface{}) error) error {
		return write(proxiedsites.ActiveDelta())
	}

	if service, err = ui.Register(messageType, newMessage, helloFn); err != nil {
		return fmt.Errorf("Unable to register channel: %q", err)
	}

	// Initializing reader.
	go read()

	return nil
}

func read() {
	for msg := range service.In {
		config.Update(func(updated *config.Config) error {
			log.Debugf("Applying update from UI")
			updated.ProxiedSites.Delta.Merge(msg.(*proxiedsites.Delta))
			return nil
		})
	}
}
<|endoftext|>


<commit_before>// [ $GOOS != nacl ] || exit 0  # no network
// $G $D/$F.go && $L $F.$A && ./$A.out

// Copyright 2010 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 main

import (
	"fmt"
	"net"
	"os"
)

func main() {
	os.Stdout.Close()
	var listen, _ = net.Listen("tcp", "127.0.0.1:0")

	go func() {
		for {
			var conn, _ = listen.Accept()
			fmt.Println("[SERVER] ", conn)
		}
	}()

	var conn, _ = net.Dial("tcp", "", listen.Addr().String())
	fmt.Println("[CLIENT] ", conn)
}
<commit_msg>test/fixedbugs/bug243.go: instead of closing stdout, remove the print statements.<commit_after>// [ $GOOS != nacl ] || exit 0  # no network
// $G $D/$F.go && $L $F.$A && ./$A.out

// Copyright 2010 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 main

import (
	"fmt"
	"net"
)

func main() {
	var listen, _ = net.Listen("tcp", "127.0.0.1:0")

	go func() {
		for {
			var conn, _ = listen.Accept()
		}
	}()

	var conn, _ = net.Dial("tcp", "", listen.Addr().String())
}
<|endoftext|>


<commit_before>package cmd

// Version is the current version of the buffalo binary
const Version = "0.8.0.dev"
<commit_msg>Adds a buffalo version command to the CLI<commit_after>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// Version is the current version of the buffalo binary
const Version = "0.8.0.dev"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of buffalo",
	Long:  `All software has versions.  This is buffalo's.`,
	Run: func(c *cobra.Command, args []string) {
		fmt.Println("Buffalo version %s", Version)
	},
}
<|endoftext|>


<commit_before>package wellington

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"
)

func TestWatch_rebuild(t *testing.T) {
	tdir, err := ioutil.TempDir(os.TempDir(), "testwatch_")
	if err != nil {
		t.Fatal(err)
	}
	tfile := filepath.Join(tdir, "_new.scss")
	fh, err := os.Create(tfile)
	if err != nil {
		t.Fatal(err)
	}

	w := NewWatcher()
	w.Dirs = []string{tdir}
	w.PartialMap.AddRelation("tswif", tfile)
	err = w.Watch()
	if err != nil {
		t.Fatal(err)
	}
	rebuildChan = make(chan []string, 1)
	done := make(chan bool, 1)
	go func(t *testing.T) {
		select {
		case <-rebuildChan:
			done <- true
		case <-time.After(2 * time.Second):
			done <- false
		}
		done <- true
	}(t)
	fh.WriteString("boom")
	success := <-done
	if !success {
		t.Fatal("Timeout waiting for rebuild")
	}

}

func TestWatch(t *testing.T) {
	w := NewWatcher()
	err := w.Watch()
	if err == nil {
		t.Error("No errors thrown for nil directories")
	}
	w.FileWatcher.Close()

	watcherChan = make(chan string, 1)
	w = NewWatcher()
	w.Dirs = []string{"test"}
	err = w.Watch()

	// Test file creation event
	go func() {
		select {
		case <-watcherChan:
			break
		case <-time.After(2 * time.Second):
			fmt.Printf("timeout %d\n", len(watcherChan))
			t.Error("Timeout without creating file")
		}
	}()

	testFile := "test/watchfile.lock"
	f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
	defer func() {
		// Give time for filesystem to sync before deleting file
		time.Sleep(50 * time.Millisecond)
		os.Remove(testFile)
		f.Close()
	}()
	if err != nil {
		t.Fatalf("creating test file failed: %s", err)
	}
	f.Sync()

	// Test file modification event
	go func() {
		select {
		case <-watcherChan:
			break
		case <-time.After(2 * time.Second):
			fmt.Printf("timeout %d\n", len(watcherChan))
			t.Error("Timeout without detecting write")
		}
	}()

	f.WriteString("data")
	f.Sync()

}

func TestRebuild(t *testing.T) {
	w := NewWatcher()
	err := w.rebuild("file/event")

	if e := fmt.Sprintf("build args are nil"); e != err.Error() {
		t.Fatalf("wanted: %s\ngot: %s", e, err)
	}
}

func TestAppendUnique(t *testing.T) {
	lst := []string{"a", "b", "c"}
	new := appendUnique(lst, "a")
	if len(new) != len(lst) {
		t.Errorf("got: %d wanted: %d", len(new), len(lst))
	}
}
<commit_msg>test appendUnique success case<commit_after>package wellington

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"
)

func TestWatch_rebuild(t *testing.T) {
	tdir, err := ioutil.TempDir(os.TempDir(), "testwatch_")
	if err != nil {
		t.Fatal(err)
	}
	tfile := filepath.Join(tdir, "_new.scss")
	fh, err := os.Create(tfile)
	if err != nil {
		t.Fatal(err)
	}

	w := NewWatcher()
	w.Dirs = []string{tdir}
	w.PartialMap.AddRelation("tswif", tfile)
	err = w.Watch()
	if err != nil {
		t.Fatal(err)
	}
	rebuildChan = make(chan []string, 1)
	done := make(chan bool, 1)
	go func(t *testing.T) {
		select {
		case <-rebuildChan:
			done <- true
		case <-time.After(2 * time.Second):
			done <- false
		}
		done <- true
	}(t)
	fh.WriteString("boom")
	success := <-done
	if !success {
		t.Fatal("Timeout waiting for rebuild")
	}

}

func TestWatch(t *testing.T) {
	w := NewWatcher()
	err := w.Watch()
	if err == nil {
		t.Error("No errors thrown for nil directories")
	}
	w.FileWatcher.Close()

	watcherChan = make(chan string, 1)
	w = NewWatcher()
	w.Dirs = []string{"test"}
	err = w.Watch()

	// Test file creation event
	go func() {
		select {
		case <-watcherChan:
			break
		case <-time.After(2 * time.Second):
			fmt.Printf("timeout %d\n", len(watcherChan))
			t.Error("Timeout without creating file")
		}
	}()

	testFile := "test/watchfile.lock"
	f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
	defer func() {
		// Give time for filesystem to sync before deleting file
		time.Sleep(50 * time.Millisecond)
		os.Remove(testFile)
		f.Close()
	}()
	if err != nil {
		t.Fatalf("creating test file failed: %s", err)
	}
	f.Sync()

	// Test file modification event
	go func() {
		select {
		case <-watcherChan:
			break
		case <-time.After(2 * time.Second):
			fmt.Printf("timeout %d\n", len(watcherChan))
			t.Error("Timeout without detecting write")
		}
	}()

	f.WriteString("data")
	f.Sync()

}

func TestRebuild(t *testing.T) {
	w := NewWatcher()
	err := w.rebuild("file/event")

	if e := fmt.Sprintf("build args are nil"); e != err.Error() {
		t.Fatalf("wanted: %s\ngot: %s", e, err)
	}
}

func TestAppendUnique(t *testing.T) {
	lst := []string{"a", "b", "c"}
	new := appendUnique(lst, "a")
	if len(new) != len(lst) {
		t.Errorf("got: %d wanted: %d", len(new), len(lst))
	}

	new = appendUnique(lst, "d")
	if len(new) != len(lst)+1 {
		t.Errorf("got: %d wanted: %d", len(new), len(lst)+1)
	}
}
<|endoftext|>


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

package expr

import (
	"fmt"

	"github.com/google/nftables/binaryutil"
	"github.com/mdlayher/netlink"
	"golang.org/x/sys/unix"
)

// Lookup represents a match against the contents of a set.
type Lookup struct {
	SourceRegister uint32
	DestRegister   uint32

	SetID   uint32
	SetName string
}

func (e *Lookup) marshal() ([]byte, error) {
	// See: https://git.netfilter.org/libnftnl/tree/src/expr/lookup.c?id=6dc1c3d8bb64077da7f3f28c7368fb087d10a492#n115
	var opAttrs []netlink.Attribute
	if e.SourceRegister != 0 {
		opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_LOOKUP_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)})
	}
	if e.DestRegister != 0 {
		opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_LOOKUP_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)})
	}
	opAttrs = append(opAttrs,
		netlink.Attribute{Type: unix.NFTA_LOOKUP_SET, Data: []byte(e.SetName + "\x00")},
		netlink.Attribute{Type: unix.NFTA_LOOKUP_SET_ID, Data: binaryutil.BigEndian.PutUint32(e.SetID)},
	)
	opData, err := netlink.MarshalAttributes(opAttrs)
	if err != nil {
		return nil, err
	}

	return netlink.MarshalAttributes([]netlink.Attribute{
		{Type: unix.NFTA_EXPR_NAME, Data: []byte("lookup\x00")},
		{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: opData},
	})
}

func (e *Lookup) unmarshal(data []byte) error {
	return fmt.Errorf("not yet implemented")
}
<commit_msg>Add support for inverted set lookups. (#10)<commit_after>// Copyright 2018 Google LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package expr

import (
	"fmt"

	"github.com/google/nftables/binaryutil"
	"github.com/mdlayher/netlink"
	"golang.org/x/sys/unix"
)

// Lookup represents a match against the contents of a set.
type Lookup struct {
	SourceRegister uint32
	DestRegister   uint32

	SetID   uint32
	SetName string
	Invert  bool
}

func (e *Lookup) marshal() ([]byte, error) {
	// See: https://git.netfilter.org/libnftnl/tree/src/expr/lookup.c?id=6dc1c3d8bb64077da7f3f28c7368fb087d10a492#n115
	var opAttrs []netlink.Attribute
	if e.SourceRegister != 0 {
		opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_LOOKUP_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)})
	}
	if e.DestRegister != 0 {
		opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_LOOKUP_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)})
	}
	if e.Invert {
		opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_LOOKUP_FLAGS, Data: binaryutil.BigEndian.PutUint32(unix.NFT_LOOKUP_F_INV)})
	}
	opAttrs = append(opAttrs,
		netlink.Attribute{Type: unix.NFTA_LOOKUP_SET, Data: []byte(e.SetName + "\x00")},
		netlink.Attribute{Type: unix.NFTA_LOOKUP_SET_ID, Data: binaryutil.BigEndian.PutUint32(e.SetID)},
	)
	opData, err := netlink.MarshalAttributes(opAttrs)
	if err != nil {
		return nil, err
	}

	return netlink.MarshalAttributes([]netlink.Attribute{
		{Type: unix.NFTA_EXPR_NAME, Data: []byte("lookup\x00")},
		{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: opData},
	})
}

func (e *Lookup) unmarshal(data []byte) error {
	return fmt.Errorf("not yet implemented")
}
<|endoftext|>


<commit_before>package exec

import (
	"context"
	"io"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/cncd/pipeline/pipeline"
	"github.com/cncd/pipeline/pipeline/backend"
	"github.com/cncd/pipeline/pipeline/backend/docker"
	"github.com/cncd/pipeline/pipeline/frontend"
	"github.com/cncd/pipeline/pipeline/frontend/yaml"
	"github.com/cncd/pipeline/pipeline/frontend/yaml/compiler"
	"github.com/cncd/pipeline/pipeline/frontend/yaml/linter"
	"github.com/cncd/pipeline/pipeline/interrupt"
	"github.com/cncd/pipeline/pipeline/multipart"
	"github.com/drone/envsubst"

	"github.com/urfave/cli"
)

// Command exports the exec command.
var Command = cli.Command{
	Name:  "exec",
	Usage: "execute a local build",
	Action: func(c *cli.Context) {
		if err := exec(c); err != nil {
			log.Fatalln(err)
		}
	},
	Flags: []cli.Flag{
		cli.BoolTFlag{
			Name:   "local",
			Usage:  "build from local directory",
			EnvVar: "DRONE_LOCAL",
		},
		cli.DurationFlag{
			Name:   "timeout",
			Usage:  "build timeout",
			Value:  time.Hour,
			EnvVar: "DRONE_TIMEOUT",
		},
		cli.StringSliceFlag{
			Name:   "volumes",
			Usage:  "build volumes",
			EnvVar: "DRONE_VOLUMES",
		},
		cli.StringSliceFlag{
			Name:   "network",
			Usage:  "external networks",
			EnvVar: "DRONE_NETWORKS",
		},
		cli.StringFlag{
			Name:   "prefix",
			Value:  "drone",
			Usage:  "prefix containers created by drone",
			EnvVar: "DRONE_DOCKER_PREFIX",
			Hidden: true,
		},
		cli.StringSliceFlag{
			Name:  "privileged",
			Usage: "privileged plugins",
			Value: &cli.StringSlice{
				"plugins/docker",
				"plugins/gcr",
				"plugins/ecr",
			},
		},

		//
		// Please note the below flags are mirrored in the pipec and
		// should be kept synchronized. Do not edit directly
		// https://github.com/cncd/pipeline/pipec
		//

		//
		// workspace default
		//
		cli.StringFlag{
			Name:   "workspace-base",
			Value:  "/drone",
			EnvVar: "DRONE_WORKSPACE_BASE",
		},
		cli.StringFlag{
			Name:   "workspace-path",
			Value:  "src",
			EnvVar: "DRONE_WORKSPACE_PATH",
		},
		//
		// netrc parameters
		//
		cli.StringFlag{
			Name:   "netrc-username",
			EnvVar: "DRONE_NETRC_USERNAME",
		},
		cli.StringFlag{
			Name:   "netrc-password",
			EnvVar: "DRONE_NETRC_PASSWORD",
		},
		cli.StringFlag{
			Name:   "netrc-machine",
			EnvVar: "DRONE_NETRC_MACHINE",
		},
		//
		// metadata parameters
		//
		cli.StringFlag{
			Name:   "system-arch",
			Value:  "linux/amd64",
			EnvVar: "DRONE_SYSTEM_ARCH",
		},
		cli.StringFlag{
			Name:   "system-name",
			Value:  "pipec",
			EnvVar: "DRONE_SYSTEM_NAME",
		},
		cli.StringFlag{
			Name:   "system-link",
			Value:  "https://github.com/cncd/pipec",
			EnvVar: "DRONE_SYSTEM_LINK",
		},
		cli.StringFlag{
			Name:   "repo-name",
			EnvVar: "DRONE_REPO_NAME",
		},
		cli.StringFlag{
			Name:   "repo-link",
			EnvVar: "DRONE_REPO_LINK",
		},
		cli.StringFlag{
			Name:   "repo-remote-url",
			EnvVar: "DRONE_REPO_REMOTE",
		},
		cli.StringFlag{
			Name:   "repo-private",
			EnvVar: "DRONE_REPO_PRIVATE",
		},
		cli.IntFlag{
			Name:   "build-number",
			EnvVar: "DRONE_BUILD_NUMBER",
		},
		cli.IntFlag{
			Name:   "parent-build-number",
			EnvVar: "DRONE_PARENT_BUILD_NUMBER",
		},
		cli.Int64Flag{
			Name:   "build-created",
			EnvVar: "DRONE_BUILD_CREATED",
		},
		cli.Int64Flag{
			Name:   "build-started",
			EnvVar: "DRONE_BUILD_STARTED",
		},
		cli.Int64Flag{
			Name:   "build-finished",
			EnvVar: "DRONE_BUILD_FINISHED",
		},
		cli.StringFlag{
			Name:   "build-status",
			EnvVar: "DRONE_BUILD_STATUS",
		},
		cli.StringFlag{
			Name:   "build-event",
			EnvVar: "DRONE_BUILD_EVENT",
		},
		cli.StringFlag{
			Name:   "build-link",
			EnvVar: "DRONE_BUILD_LINK",
		},
		cli.StringFlag{
			Name:   "build-target",
			EnvVar: "DRONE_BUILD_TARGET",
		},
		cli.StringFlag{
			Name:   "commit-sha",
			EnvVar: "DRONE_COMMIT_SHA",
		},
		cli.StringFlag{
			Name:   "commit-ref",
			EnvVar: "DRONE_COMMIT_REF",
		},
		cli.StringFlag{
			Name:   "commit-refspec",
			EnvVar: "DRONE_COMMIT_REFSPEC",
		},
		cli.StringFlag{
			Name:   "commit-branch",
			EnvVar: "DRONE_COMMIT_BRANCH",
		},
		cli.StringFlag{
			Name:   "commit-message",
			EnvVar: "DRONE_COMMIT_MESSAGE",
		},
		cli.StringFlag{
			Name:   "commit-author-name",
			EnvVar: "DRONE_COMMIT_AUTHOR_NAME",
		},
		cli.StringFlag{
			Name:   "commit-author-avatar",
			EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR",
		},
		cli.StringFlag{
			Name:   "commit-author-email",
			EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
		},
		cli.IntFlag{
			Name:   "prev-build-number",
			EnvVar: "DRONE_PREV_BUILD_NUMBER",
		},
		cli.Int64Flag{
			Name:   "prev-build-created",
			EnvVar: "DRONE_PREV_BUILD_CREATED",
		},
		cli.Int64Flag{
			Name:   "prev-build-started",
			EnvVar: "DRONE_PREV_BUILD_STARTED",
		},
		cli.Int64Flag{
			Name:   "prev-build-finished",
			EnvVar: "DRONE_PREV_BUILD_FINISHED",
		},
		cli.StringFlag{
			Name:   "prev-build-status",
			EnvVar: "DRONE_PREV_BUILD_STATUS",
		},
		cli.StringFlag{
			Name:   "prev-build-event",
			EnvVar: "DRONE_PREV_BUILD_EVENT",
		},
		cli.StringFlag{
			Name:   "prev-build-link",
			EnvVar: "DRONE_PREV_BUILD_LINK",
		},
		cli.StringFlag{
			Name:   "prev-commit-sha",
			EnvVar: "DRONE_PREV_COMMIT_SHA",
		},
		cli.StringFlag{
			Name:   "prev-commit-ref",
			EnvVar: "DRONE_PREV_COMMIT_REF",
		},
		cli.StringFlag{
			Name:   "prev-commit-refspec",
			EnvVar: "DRONE_PREV_COMMIT_REFSPEC",
		},
		cli.StringFlag{
			Name:   "prev-commit-branch",
			EnvVar: "DRONE_PREV_COMMIT_BRANCH",
		},
		cli.StringFlag{
			Name:   "prev-commit-message",
			EnvVar: "DRONE_PREV_COMMIT_MESSAGE",
		},
		cli.StringFlag{
			Name:   "prev-commit-author-name",
			EnvVar: "DRONE_PREV_COMMIT_AUTHOR_NAME",
		},
		cli.StringFlag{
			Name:   "prev-commit-author-avatar",
			EnvVar: "DRONE_PREV_COMMIT_AUTHOR_AVATAR",
		},
		cli.StringFlag{
			Name:   "prev-commit-author-email",
			EnvVar: "DRONE_PREV_COMMIT_AUTHOR_EMAIL",
		},
		cli.IntFlag{
			Name:   "job-number",
			EnvVar: "DRONE_JOB_NUMBER",
		},
	},
}

func exec(c *cli.Context) error {
	file := c.Args().First()
	if file == "" {
		file = ".drone.yml"
	}

	metadata := metadataFromContext(c)
	environ := metadata.Environ()
	secrets := []compiler.Secret{}
	for k, v := range metadata.EnvironDrone() {
		environ[k] = v
	}
	for _, env := range os.Environ() {
		k := strings.Split(env, "=")[0]
		v := strings.Split(env, "=")[1]
		environ[k] = v
		secrets = append(secrets, compiler.Secret{
			Name:  k,
			Value: v,
		})
	}

	tmpl, err := envsubst.ParseFile(file)
	if err != nil {
		return err
	}
	confstr, err := tmpl.Execute(func(name string) string {
		return environ[name]
	})
	if err != nil {
		return err
	}

	conf, err := yaml.ParseString(confstr)
	if err != nil {
		return err
	}

	// configure volumes for local execution
	volumes := c.StringSlice("volumes")
	if c.Bool("local") {
		var (
			workspaceBase = conf.Workspace.Base
			workspacePath = conf.Workspace.Path
		)
		if workspaceBase == "" {
			workspaceBase = c.String("workspace-base")
		}
		if workspacePath == "" {
			workspacePath = c.String("workspace-path")
		}
		dir, _ := filepath.Abs(filepath.Dir(file))
		volumes = append(volumes, "drone_default:"+workspaceBase)
		volumes = append(volumes, dir+":"+path.Join(workspaceBase, workspacePath))
	}

	// lint the yaml file
	if lerr := linter.New(linter.WithTrusted(true)).Lint(conf); lerr != nil {
		return lerr
	}

	// compiles the yaml file
	compiled := compiler.New(
		compiler.WithEscalated(
			c.StringSlice("privileged")...,
		),
		compiler.WithVolumes(volumes...),
		compiler.WithWorkspace(
			c.String("workspace-base"),
			c.String("workspace-path"),
		),
		compiler.WithNetworks(
			c.StringSlice("network")...,
		),
		compiler.WithPrefix(
			c.String("prefix"),
		),
		compiler.WithProxy(),
		compiler.WithLocal(
			c.Bool("local"),
		),
		compiler.WithNetrc(
			c.String("netrc-username"),
			c.String("netrc-password"),
			c.String("netrc-machine"),
		),
		compiler.WithMetadata(metadata),
		compiler.WithSecret(secrets...),
	).Compile(conf)

	engine, err := docker.NewEnv()
	if err != nil {
		return err
	}

	ctx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
	defer cancel()
	ctx = interrupt.WithContext(ctx)

	return pipeline.New(compiled,
		pipeline.WithContext(ctx),
		pipeline.WithTracer(pipeline.DefaultTracer),
		pipeline.WithLogger(defaultLogger),
		pipeline.WithEngine(engine),
	).Run()
}

// return the metadata from the cli context.
func metadataFromContext(c *cli.Context) frontend.Metadata {
	return frontend.Metadata{
		Repo: frontend.Repo{
			Name:    c.String("repo-name"),
			Link:    c.String("repo-link"),
			Remote:  c.String("repo-remote-url"),
			Private: c.Bool("repo-private"),
		},
		Curr: frontend.Build{
			Number:   c.Int("build-number"),
			Parent:   c.Int("parent-build-number"),
			Created:  c.Int64("build-created"),
			Started:  c.Int64("build-started"),
			Finished: c.Int64("build-finished"),
			Status:   c.String("build-status"),
			Event:    c.String("build-event"),
			Link:     c.String("build-link"),
			Target:   c.String("build-target"),
			Commit: frontend.Commit{
				Sha:     c.String("commit-sha"),
				Ref:     c.String("commit-ref"),
				Refspec: c.String("commit-refspec"),
				Branch:  c.String("commit-branch"),
				Message: c.String("commit-message"),
				Author: frontend.Author{
					Name:   c.String("commit-author-name"),
					Email:  c.String("commit-author-email"),
					Avatar: c.String("commit-author-avatar"),
				},
			},
		},
		Prev: frontend.Build{
			Number:   c.Int("prev-build-number"),
			Created:  c.Int64("prev-build-created"),
			Started:  c.Int64("prev-build-started"),
			Finished: c.Int64("prev-build-finished"),
			Status:   c.String("prev-build-status"),
			Event:    c.String("prev-build-event"),
			Link:     c.String("prev-build-link"),
			Commit: frontend.Commit{
				Sha:     c.String("prev-commit-sha"),
				Ref:     c.String("prev-commit-ref"),
				Refspec: c.String("prev-commit-refspec"),
				Branch:  c.String("prev-commit-branch"),
				Message: c.String("prev-commit-message"),
				Author: frontend.Author{
					Name:   c.String("prev-commit-author-name"),
					Email:  c.String("prev-commit-author-email"),
					Avatar: c.String("prev-commit-author-avatar"),
				},
			},
		},
		Job: frontend.Job{
			Number: c.Int("job-number"),
		},
		Sys: frontend.System{
			Name: c.String("system-name"),
			Link: c.String("system-link"),
			Arch: c.String("system-arch"),
		},
	}
}

var defaultLogger = pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reader) error {
	part, err := rc.NextPart()
	if err != nil {
		return err
	}

	logstream := NewLineWriter(proc.Alias)
	io.Copy(logstream, part)

	return nil
})
<commit_msg>Take into account volume prefix<commit_after>package exec

import (
	"context"
	"io"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/cncd/pipeline/pipeline"
	"github.com/cncd/pipeline/pipeline/backend"
	"github.com/cncd/pipeline/pipeline/backend/docker"
	"github.com/cncd/pipeline/pipeline/frontend"
	"github.com/cncd/pipeline/pipeline/frontend/yaml"
	"github.com/cncd/pipeline/pipeline/frontend/yaml/compiler"
	"github.com/cncd/pipeline/pipeline/frontend/yaml/linter"
	"github.com/cncd/pipeline/pipeline/interrupt"
	"github.com/cncd/pipeline/pipeline/multipart"
	"github.com/drone/envsubst"

	"github.com/urfave/cli"
)

// Command exports the exec command.
var Command = cli.Command{
	Name:  "exec",
	Usage: "execute a local build",
	Action: func(c *cli.Context) {
		if err := exec(c); err != nil {
			log.Fatalln(err)
		}
	},
	Flags: []cli.Flag{
		cli.BoolTFlag{
			Name:   "local",
			Usage:  "build from local directory",
			EnvVar: "DRONE_LOCAL",
		},
		cli.DurationFlag{
			Name:   "timeout",
			Usage:  "build timeout",
			Value:  time.Hour,
			EnvVar: "DRONE_TIMEOUT",
		},
		cli.StringSliceFlag{
			Name:   "volumes",
			Usage:  "build volumes",
			EnvVar: "DRONE_VOLUMES",
		},
		cli.StringSliceFlag{
			Name:   "network",
			Usage:  "external networks",
			EnvVar: "DRONE_NETWORKS",
		},
		cli.StringFlag{
			Name:   "prefix",
			Value:  "drone",
			Usage:  "prefix containers created by drone",
			EnvVar: "DRONE_DOCKER_PREFIX",
			Hidden: true,
		},
		cli.StringSliceFlag{
			Name:  "privileged",
			Usage: "privileged plugins",
			Value: &cli.StringSlice{
				"plugins/docker",
				"plugins/gcr",
				"plugins/ecr",
			},
		},

		//
		// Please note the below flags are mirrored in the pipec and
		// should be kept synchronized. Do not edit directly
		// https://github.com/cncd/pipeline/pipec
		//

		//
		// workspace default
		//
		cli.StringFlag{
			Name:   "workspace-base",
			Value:  "/drone",
			EnvVar: "DRONE_WORKSPACE_BASE",
		},
		cli.StringFlag{
			Name:   "workspace-path",
			Value:  "src",
			EnvVar: "DRONE_WORKSPACE_PATH",
		},
		//
		// netrc parameters
		//
		cli.StringFlag{
			Name:   "netrc-username",
			EnvVar: "DRONE_NETRC_USERNAME",
		},
		cli.StringFlag{
			Name:   "netrc-password",
			EnvVar: "DRONE_NETRC_PASSWORD",
		},
		cli.StringFlag{
			Name:   "netrc-machine",
			EnvVar: "DRONE_NETRC_MACHINE",
		},
		//
		// metadata parameters
		//
		cli.StringFlag{
			Name:   "system-arch",
			Value:  "linux/amd64",
			EnvVar: "DRONE_SYSTEM_ARCH",
		},
		cli.StringFlag{
			Name:   "system-name",
			Value:  "pipec",
			EnvVar: "DRONE_SYSTEM_NAME",
		},
		cli.StringFlag{
			Name:   "system-link",
			Value:  "https://github.com/cncd/pipec",
			EnvVar: "DRONE_SYSTEM_LINK",
		},
		cli.StringFlag{
			Name:   "repo-name",
			EnvVar: "DRONE_REPO_NAME",
		},
		cli.StringFlag{
			Name:   "repo-link",
			EnvVar: "DRONE_REPO_LINK",
		},
		cli.StringFlag{
			Name:   "repo-remote-url",
			EnvVar: "DRONE_REPO_REMOTE",
		},
		cli.StringFlag{
			Name:   "repo-private",
			EnvVar: "DRONE_REPO_PRIVATE",
		},
		cli.IntFlag{
			Name:   "build-number",
			EnvVar: "DRONE_BUILD_NUMBER",
		},
		cli.IntFlag{
			Name:   "parent-build-number",
			EnvVar: "DRONE_PARENT_BUILD_NUMBER",
		},
		cli.Int64Flag{
			Name:   "build-created",
			EnvVar: "DRONE_BUILD_CREATED",
		},
		cli.Int64Flag{
			Name:   "build-started",
			EnvVar: "DRONE_BUILD_STARTED",
		},
		cli.Int64Flag{
			Name:   "build-finished",
			EnvVar: "DRONE_BUILD_FINISHED",
		},
		cli.StringFlag{
			Name:   "build-status",
			EnvVar: "DRONE_BUILD_STATUS",
		},
		cli.StringFlag{
			Name:   "build-event",
			EnvVar: "DRONE_BUILD_EVENT",
		},
		cli.StringFlag{
			Name:   "build-link",
			EnvVar: "DRONE_BUILD_LINK",
		},
		cli.StringFlag{
			Name:   "build-target",
			EnvVar: "DRONE_BUILD_TARGET",
		},
		cli.StringFlag{
			Name:   "commit-sha",
			EnvVar: "DRONE_COMMIT_SHA",
		},
		cli.StringFlag{
			Name:   "commit-ref",
			EnvVar: "DRONE_COMMIT_REF",
		},
		cli.StringFlag{
			Name:   "commit-refspec",
			EnvVar: "DRONE_COMMIT_REFSPEC",
		},
		cli.StringFlag{
			Name:   "commit-branch",
			EnvVar: "DRONE_COMMIT_BRANCH",
		},
		cli.StringFlag{
			Name:   "commit-message",
			EnvVar: "DRONE_COMMIT_MESSAGE",
		},
		cli.StringFlag{
			Name:   "commit-author-name",
			EnvVar: "DRONE_COMMIT_AUTHOR_NAME",
		},
		cli.StringFlag{
			Name:   "commit-author-avatar",
			EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR",
		},
		cli.StringFlag{
			Name:   "commit-author-email",
			EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
		},
		cli.IntFlag{
			Name:   "prev-build-number",
			EnvVar: "DRONE_PREV_BUILD_NUMBER",
		},
		cli.Int64Flag{
			Name:   "prev-build-created",
			EnvVar: "DRONE_PREV_BUILD_CREATED",
		},
		cli.Int64Flag{
			Name:   "prev-build-started",
			EnvVar: "DRONE_PREV_BUILD_STARTED",
		},
		cli.Int64Flag{
			Name:   "prev-build-finished",
			EnvVar: "DRONE_PREV_BUILD_FINISHED",
		},
		cli.StringFlag{
			Name:   "prev-build-status",
			EnvVar: "DRONE_PREV_BUILD_STATUS",
		},
		cli.StringFlag{
			Name:   "prev-build-event",
			EnvVar: "DRONE_PREV_BUILD_EVENT",
		},
		cli.StringFlag{
			Name:   "prev-build-link",
			EnvVar: "DRONE_PREV_BUILD_LINK",
		},
		cli.StringFlag{
			Name:   "prev-commit-sha",
			EnvVar: "DRONE_PREV_COMMIT_SHA",
		},
		cli.StringFlag{
			Name:   "prev-commit-ref",
			EnvVar: "DRONE_PREV_COMMIT_REF",
		},
		cli.StringFlag{
			Name:   "prev-commit-refspec",
			EnvVar: "DRONE_PREV_COMMIT_REFSPEC",
		},
		cli.StringFlag{
			Name:   "prev-commit-branch",
			EnvVar: "DRONE_PREV_COMMIT_BRANCH",
		},
		cli.StringFlag{
			Name:   "prev-commit-message",
			EnvVar: "DRONE_PREV_COMMIT_MESSAGE",
		},
		cli.StringFlag{
			Name:   "prev-commit-author-name",
			EnvVar: "DRONE_PREV_COMMIT_AUTHOR_NAME",
		},
		cli.StringFlag{
			Name:   "prev-commit-author-avatar",
			EnvVar: "DRONE_PREV_COMMIT_AUTHOR_AVATAR",
		},
		cli.StringFlag{
			Name:   "prev-commit-author-email",
			EnvVar: "DRONE_PREV_COMMIT_AUTHOR_EMAIL",
		},
		cli.IntFlag{
			Name:   "job-number",
			EnvVar: "DRONE_JOB_NUMBER",
		},
	},
}

func exec(c *cli.Context) error {
	file := c.Args().First()
	if file == "" {
		file = ".drone.yml"
	}

	metadata := metadataFromContext(c)
	environ := metadata.Environ()
	secrets := []compiler.Secret{}
	for k, v := range metadata.EnvironDrone() {
		environ[k] = v
	}
	for _, env := range os.Environ() {
		k := strings.Split(env, "=")[0]
		v := strings.Split(env, "=")[1]
		environ[k] = v
		secrets = append(secrets, compiler.Secret{
			Name:  k,
			Value: v,
		})
	}

	tmpl, err := envsubst.ParseFile(file)
	if err != nil {
		return err
	}
	confstr, err := tmpl.Execute(func(name string) string {
		return environ[name]
	})
	if err != nil {
		return err
	}

	conf, err := yaml.ParseString(confstr)
	if err != nil {
		return err
	}

	// configure volumes for local execution
	volumes := c.StringSlice("volumes")
	if c.Bool("local") {
		var (
			workspaceBase = conf.Workspace.Base
			workspacePath = conf.Workspace.Path
		)
		if workspaceBase == "" {
			workspaceBase = c.String("workspace-base")
		}
		if workspacePath == "" {
			workspacePath = c.String("workspace-path")
		}
		dir, _ := filepath.Abs(filepath.Dir(file))
		volumes = append(volumes, c.String("prefix")+"_default:"+workspaceBase)
		volumes = append(volumes, dir+":"+path.Join(workspaceBase, workspacePath))
	}

	// lint the yaml file
	if lerr := linter.New(linter.WithTrusted(true)).Lint(conf); lerr != nil {
		return lerr
	}

	// compiles the yaml file
	compiled := compiler.New(
		compiler.WithEscalated(
			c.StringSlice("privileged")...,
		),
		compiler.WithVolumes(volumes...),
		compiler.WithWorkspace(
			c.String("workspace-base"),
			c.String("workspace-path"),
		),
		compiler.WithNetworks(
			c.StringSlice("network")...,
		),
		compiler.WithPrefix(
			c.String("prefix"),
		),
		compiler.WithProxy(),
		compiler.WithLocal(
			c.Bool("local"),
		),
		compiler.WithNetrc(
			c.String("netrc-username"),
			c.String("netrc-password"),
			c.String("netrc-machine"),
		),
		compiler.WithMetadata(metadata),
		compiler.WithSecret(secrets...),
	).Compile(conf)

	engine, err := docker.NewEnv()
	if err != nil {
		return err
	}

	ctx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
	defer cancel()
	ctx = interrupt.WithContext(ctx)

	return pipeline.New(compiled,
		pipeline.WithContext(ctx),
		pipeline.WithTracer(pipeline.DefaultTracer),
		pipeline.WithLogger(defaultLogger),
		pipeline.WithEngine(engine),
	).Run()
}

// return the metadata from the cli context.
func metadataFromContext(c *cli.Context) frontend.Metadata {
	return frontend.Metadata{
		Repo: frontend.Repo{
			Name:    c.String("repo-name"),
			Link:    c.String("repo-link"),
			Remote:  c.String("repo-remote-url"),
			Private: c.Bool("repo-private"),
		},
		Curr: frontend.Build{
			Number:   c.Int("build-number"),
			Parent:   c.Int("parent-build-number"),
			Created:  c.Int64("build-created"),
			Started:  c.Int64("build-started"),
			Finished: c.Int64("build-finished"),
			Status:   c.String("build-status"),
			Event:    c.String("build-event"),
			Link:     c.String("build-link"),
			Target:   c.String("build-target"),
			Commit: frontend.Commit{
				Sha:     c.String("commit-sha"),
				Ref:     c.String("commit-ref"),
				Refspec: c.String("commit-refspec"),
				Branch:  c.String("commit-branch"),
				Message: c.String("commit-message"),
				Author: frontend.Author{
					Name:   c.String("commit-author-name"),
					Email:  c.String("commit-author-email"),
					Avatar: c.String("commit-author-avatar"),
				},
			},
		},
		Prev: frontend.Build{
			Number:   c.Int("prev-build-number"),
			Created:  c.Int64("prev-build-created"),
			Started:  c.Int64("prev-build-started"),
			Finished: c.Int64("prev-build-finished"),
			Status:   c.String("prev-build-status"),
			Event:    c.String("prev-build-event"),
			Link:     c.String("prev-build-link"),
			Commit: frontend.Commit{
				Sha:     c.String("prev-commit-sha"),
				Ref:     c.String("prev-commit-ref"),
				Refspec: c.String("prev-commit-refspec"),
				Branch:  c.String("prev-commit-branch"),
				Message: c.String("prev-commit-message"),
				Author: frontend.Author{
					Name:   c.String("prev-commit-author-name"),
					Email:  c.String("prev-commit-author-email"),
					Avatar: c.String("prev-commit-author-avatar"),
				},
			},
		},
		Job: frontend.Job{
			Number: c.Int("job-number"),
		},
		Sys: frontend.System{
			Name: c.String("system-name"),
			Link: c.String("system-link"),
			Arch: c.String("system-arch"),
		},
	}
}

var defaultLogger = pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reader) error {
	part, err := rc.NextPart()
	if err != nil {
		return err
	}

	logstream := NewLineWriter(proc.Alias)
	io.Copy(logstream, part)

	return nil
})
<|endoftext|>


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

package memfs

import (
	"fmt"
	"os"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/syncutil"
)

// Common attributes for files and directories.
//
// TODO(jacobsa): Add tests for interacting with a file/directory after it has
// been unlinked, including creating a new file. Make sure we don't screw up
// and reuse an inode ID while it is still in use.
type inode struct {
	/////////////////////////
	// Constant data
	/////////////////////////

	// Is this a directory? If not, it is a file.
	dir bool

	/////////////////////////
	// Mutable state
	/////////////////////////

	mu syncutil.InvariantMutex

	// The number of times this inode is linked into a parent directory. This may
	// be zero if the inode has been unlinked but not yet forgotten, because some
	// process still has an  open file handle.
	//
	// INVARIANT: linkCount >= 0
	linkCount int // GUARDED_BY(mu)

	// The current attributes of this inode.
	//
	// INVARIANT: No non-permission mode bits are set besides os.ModeDir
	// INVARIANT: If dir, then os.ModeDir is set
	// INVARIANT: If !dir, then os.ModeDir is not set
	// INVARIANT: attributes.Size == len(contents)
	attributes fuse.InodeAttributes // GUARDED_BY(mu)

	// For directories, entries describing the children of the directory. Unused
	// entries are of type DT_Unknown.
	//
	// This array can never be shortened, nor can its elements be moved, because
	// we use its indices for Dirent.Offset, which is exposed to the user who
	// might be calling readdir in a loop while concurrently modifying the
	// directory. Unused entries can, however, be reused.
	//
	// TODO(jacobsa): Add good tests exercising concurrent modifications while
	// doing readdir, seekdir, etc. calls.
	//
	// INVARIANT: If dir is false, this is nil.
	// INVARIANT: For each i, entries[i].Offset == i+1
	// INVARIANT: Contains no duplicate names in used entries.
	entries []fuseutil.Dirent // GUARDED_BY(mu)

	// For files, the current contents of the file.
	//
	// INVARIANT: If dir is true, this is nil.
	contents []byte // GUARDED_BY(mu)
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Initially the link count is one.
func newInode(attrs fuse.InodeAttributes) (in *inode) {
	in = &inode{
		linkCount:  1,
		dir:        (attrs.Mode&os.ModeDir != 0),
		attributes: attrs,
	}

	in.mu = syncutil.NewInvariantMutex(in.checkInvariants)
	return
}

func (inode *inode) checkInvariants() {
	// Check the link count.
	if inode.linkCount < 0 {
		panic(fmt.Sprintf("Negative link count: %v", inode.linkCount))
	}

	// No non-permission mode bits should be set besides os.ModeDir.
	if inode.attributes.Mode & ^(os.ModePerm|os.ModeDir) != 0 {
		panic(fmt.Sprintf("Unexpected mode: %v", inode.attributes.Mode))
	}

	// Check os.ModeDir.
	if inode.dir != (inode.attributes.Mode&os.ModeDir == os.ModeDir) {
		panic(
			fmt.Sprintf(
				"Unexpected mode: %v, dir: %v",
				inode.attributes.Mode,
				inode.dir))
	}

	// Check directory-specific stuff.
	if inode.dir {
		if inode.contents != nil {
			panic("Non-nil contents in a directory.")
		}

		childNames := make(map[string]struct{})
		for i, e := range inode.entries {
			if e.Offset != fuse.DirOffset(i+1) {
				panic(fmt.Sprintf("Unexpected offset: %v", e.Offset))
			}

			if e.Type != fuseutil.DT_Unknown {
				if _, ok := childNames[e.Name]; ok {
					panic(fmt.Sprintf("Duplicate name: %s", e.Name))
				}

				childNames[e.Name] = struct{}{}
			}
		}
	}

	// Check file-specific stuff.
	if !inode.dir {
		if inode.entries != nil {
			panic("Non-nil entries in a file.")
		}
	}

	// Check the size.
	if inode.attributes.Size != uint64(len(inode.contents)) {
		panic(
			fmt.Sprintf(
				"Unexpected size: %v vs. %v",
				inode.attributes.Size,
				len(inode.contents)))
	}
}

// Return the index of the child within inode.entries, if it exists.
//
// REQUIRES: inode.dir
// SHARED_LOCKS_REQUIRED(inode.mu)
func (inode *inode) findChild(name string) (i int, ok bool) {
	if !inode.dir {
		panic("findChild called on non-directory.")
	}

	var e fuseutil.Dirent
	for i, e = range inode.entries {
		if e.Name == name {
			ok = true
			return
		}
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Public methods
////////////////////////////////////////////////////////////////////////

// Return the number of children of the directory.
//
// REQUIRES: inode.dir
// SHARED_LOCKS_REQUIRED(inode.mu)
func (inode *inode) Len() (n int) {
	for _, e := range inode.entries {
		if e.Type != fuseutil.DT_Unknown {
			n++
		}
	}

	return
}

// Find an entry for the given child name and return its inode ID.
//
// REQUIRES: inode.dir
// SHARED_LOCKS_REQUIRED(inode.mu)
func (inode *inode) LookUpChild(name string) (id fuse.InodeID, ok bool) {
	index, ok := inode.findChild(name)
	if ok {
		id = inode.entries[index].Inode
	}

	return
}

// Add an entry for a child.
//
// REQUIRES: inode.dir
// REQUIRES: dt != fuseutil.DT_Unknown
// EXCLUSIVE_LOCKS_REQUIRED(inode.mu)
func (inode *inode) AddChild(
	id fuse.InodeID,
	name string,
	dt fuseutil.DirentType) {
	var index int

	// No matter where we place the entry, make sure it has the correct Offset
	// field.
	defer func() {
		inode.entries[index].Offset = fuse.DirOffset(index + 1)
	}()

	// Set up the entry.
	e := fuseutil.Dirent{
		Inode: id,
		Name:  name,
		Type:  dt,
	}

	// Look for a gap in which we can insert it.
	for index = range inode.entries {
		if inode.entries[index].Type == fuseutil.DT_Unknown {
			inode.entries[index] = e
			return
		}
	}

	// Append it to the end.
	index = len(inode.entries)
	inode.entries = append(inode.entries, e)
}

// Remove an entry for a child.
//
// REQUIRES: inode.dir
// REQUIRES: An entry for the given name exists.
// EXCLUSIVE_LOCKS_REQUIRED(inode.mu)
func (inode *inode) RemoveChild(name string) {
	// Find the entry.
	i, ok := inode.findChild(name)
	if !ok {
		panic(fmt.Sprintf("Unknown child: %s", name))
	}

	// Mark it as unused.
	inode.entries[i] = fuseutil.Dirent{
		Type:   fuseutil.DT_Unknown,
		Offset: fuse.DirOffset(i + 1),
	}
}

// Serve a ReadDir request.
//
// REQUIRES: inode.dir
// SHARED_LOCKS_REQUIRED(inode.mu)
func (inode *inode) ReadDir(offset int, size int) (data []byte, err error) {
	if !inode.dir {
		panic("ReadDir called on non-directory.")
	}

	for i := offset; i < len(inode.entries); i++ {
		e := inode.entries[i]

		// Skip unused entries.
		if e.Type == fuseutil.DT_Unknown {
			continue
		}

		data = fuseutil.AppendDirent(data, inode.entries[i])

		// Trim and stop early if we've exceeded the requested size.
		if len(data) > size {
			data = data[:size]
			break
		}
	}

	return
}

// Write to the file's contents. See documentation for ioutil.WriterAt.
//
// REQUIRES: !inode.dir
// EXCLUSIVE_LOCKS_REQUIRED(inode.mu)
func (inode *inode) WriteAt(p []byte, off int64) (n int, err error) {
	if inode.dir {
		panic("WriteAt called on directory.")
	}

	// Ensure that the contents slice is long enough.
	newLen := int(off) + len(p)
	if len(inode.contents) < newLen {
		padding := make([]byte, newLen-len(inode.contents))
		inode.contents = append(inode.contents, padding...)
	}

	// Copy in the data.
	n = copy(inode.contents[off:], p)

	// Sanity check.
	if n != len(p) {
		panic(fmt.Sprintf("Unexpected short copy: %v", n))
	}

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

package memfs

import (
	"fmt"
	"os"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/syncutil"
)

// Common attributes for files and directories.
//
// TODO(jacobsa): Add tests for interacting with a file/directory after it has
// been unlinked, including creating a new file. Make sure we don't screw up
// and reuse an inode ID while it is still in use.
type inode struct {
	/////////////////////////
	// Constant data
	/////////////////////////

	// Is this a directory? If not, it is a file.
	dir bool

	/////////////////////////
	// Mutable state
	/////////////////////////

	mu syncutil.InvariantMutex

	// The number of times this inode is linked into a parent directory. This may
	// be zero if the inode has been unlinked but not yet forgotten, because some
	// process still has an  open file handle.
	//
	// INVARIANT: linkCount >= 0
	linkCount int // GUARDED_BY(mu)

	// The current attributes of this inode.
	//
	// INVARIANT: No non-permission mode bits are set besides os.ModeDir
	// INVARIANT: If dir, then os.ModeDir is set
	// INVARIANT: If !dir, then os.ModeDir is not set
	// INVARIANT: attributes.Size == len(contents)
	attributes fuse.InodeAttributes // GUARDED_BY(mu)

	// For directories, entries describing the children of the directory. Unused
	// entries are of type DT_Unknown.
	//
	// This array can never be shortened, nor can its elements be moved, because
	// we use its indices for Dirent.Offset, which is exposed to the user who
	// might be calling readdir in a loop while concurrently modifying the
	// directory. Unused entries can, however, be reused.
	//
	// TODO(jacobsa): Add good tests exercising concurrent modifications while
	// doing readdir, seekdir, etc. calls.
	//
	// INVARIANT: If dir is false, this is nil.
	// INVARIANT: For each i, entries[i].Offset == i+1
	// INVARIANT: Contains no duplicate names in used entries.
	entries []fuseutil.Dirent // GUARDED_BY(mu)

	// For files, the current contents of the file.
	//
	// INVARIANT: If dir is true, this is nil.
	contents []byte // GUARDED_BY(mu)
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Initially the link count is one.
func newInode(attrs fuse.InodeAttributes) (in *inode) {
	in = &inode{
		linkCount:  1,
		dir:        (attrs.Mode&os.ModeDir != 0),
		attributes: attrs,
	}

	in.mu = syncutil.NewInvariantMutex(in.checkInvariants)
	return
}

func (inode *inode) checkInvariants() {
	// Check the link count.
	if inode.linkCount < 0 {
		panic(fmt.Sprintf("Negative link count: %v", inode.linkCount))
	}

	// No non-permission mode bits should be set besides os.ModeDir.
	if inode.attributes.Mode & ^(os.ModePerm|os.ModeDir) != 0 {
		panic(fmt.Sprintf("Unexpected mode: %v", inode.attributes.Mode))
	}

	// Check os.ModeDir.
	if inode.dir != (inode.attributes.Mode&os.ModeDir == os.ModeDir) {
		panic(
			fmt.Sprintf(
				"Unexpected mode: %v, dir: %v",
				inode.attributes.Mode,
				inode.dir))
	}

	// Check directory-specific stuff.
	if inode.dir {
		if inode.contents != nil {
			panic("Non-nil contents in a directory.")
		}

		childNames := make(map[string]struct{})
		for i, e := range inode.entries {
			if e.Offset != fuse.DirOffset(i+1) {
				panic(fmt.Sprintf("Unexpected offset: %v", e.Offset))
			}

			if e.Type != fuseutil.DT_Unknown {
				if _, ok := childNames[e.Name]; ok {
					panic(fmt.Sprintf("Duplicate name: %s", e.Name))
				}

				childNames[e.Name] = struct{}{}
			}
		}
	}

	// Check file-specific stuff.
	if !inode.dir {
		if inode.entries != nil {
			panic("Non-nil entries in a file.")
		}
	}

	// Check the size.
	if inode.attributes.Size != uint64(len(inode.contents)) {
		panic(
			fmt.Sprintf(
				"Unexpected size: %v vs. %v",
				inode.attributes.Size,
				len(inode.contents)))
	}
}

// Return the index of the child within inode.entries, if it exists.
//
// REQUIRES: inode.dir
// SHARED_LOCKS_REQUIRED(inode.mu)
func (inode *inode) findChild(name string) (i int, ok bool) {
	if !inode.dir {
		panic("findChild called on non-directory.")
	}

	var e fuseutil.Dirent
	for i, e = range inode.entries {
		if e.Name == name {
			ok = true
			return
		}
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Public methods
////////////////////////////////////////////////////////////////////////

// Return the number of children of the directory.
//
// REQUIRES: inode.dir
// SHARED_LOCKS_REQUIRED(inode.mu)
func (inode *inode) Len() (n int) {
	for _, e := range inode.entries {
		if e.Type != fuseutil.DT_Unknown {
			n++
		}
	}

	return
}

// Find an entry for the given child name and return its inode ID.
//
// REQUIRES: inode.dir
// SHARED_LOCKS_REQUIRED(inode.mu)
func (inode *inode) LookUpChild(name string) (id fuse.InodeID, ok bool) {
	index, ok := inode.findChild(name)
	if ok {
		id = inode.entries[index].Inode
	}

	return
}

// Add an entry for a child.
//
// REQUIRES: inode.dir
// REQUIRES: dt != fuseutil.DT_Unknown
// EXCLUSIVE_LOCKS_REQUIRED(inode.mu)
func (inode *inode) AddChild(
	id fuse.InodeID,
	name string,
	dt fuseutil.DirentType) {
	var index int

	// No matter where we place the entry, make sure it has the correct Offset
	// field.
	defer func() {
		inode.entries[index].Offset = fuse.DirOffset(index + 1)
	}()

	// Set up the entry.
	e := fuseutil.Dirent{
		Inode: id,
		Name:  name,
		Type:  dt,
	}

	// Look for a gap in which we can insert it.
	for index = range inode.entries {
		if inode.entries[index].Type == fuseutil.DT_Unknown {
			inode.entries[index] = e
			return
		}
	}

	// Append it to the end.
	index = len(inode.entries)
	inode.entries = append(inode.entries, e)
}

// Remove an entry for a child.
//
// REQUIRES: inode.dir
// REQUIRES: An entry for the given name exists.
// EXCLUSIVE_LOCKS_REQUIRED(inode.mu)
func (inode *inode) RemoveChild(name string) {
	// Find the entry.
	i, ok := inode.findChild(name)
	if !ok {
		panic(fmt.Sprintf("Unknown child: %s", name))
	}

	// Mark it as unused.
	inode.entries[i] = fuseutil.Dirent{
		Type:   fuseutil.DT_Unknown,
		Offset: fuse.DirOffset(i + 1),
	}
}

// Serve a ReadDir request.
//
// REQUIRES: inode.dir
// SHARED_LOCKS_REQUIRED(inode.mu)
func (inode *inode) ReadDir(offset int, size int) (data []byte, err error) {
	if !inode.dir {
		panic("ReadDir called on non-directory.")
	}

	for i := offset; i < len(inode.entries); i++ {
		e := inode.entries[i]

		// Skip unused entries.
		if e.Type == fuseutil.DT_Unknown {
			continue
		}

		data = fuseutil.AppendDirent(data, inode.entries[i])

		// Trim and stop early if we've exceeded the requested size.
		if len(data) > size {
			data = data[:size]
			break
		}
	}

	return
}

// Write to the file's contents. See documentation for ioutil.WriterAt.
//
// REQUIRES: !inode.dir
// EXCLUSIVE_LOCKS_REQUIRED(inode.mu)
func (inode *inode) WriteAt(p []byte, off int64) (n int, err error) {
	if inode.dir {
		panic("WriteAt called on directory.")
	}

	// Ensure that the contents slice is long enough.
	newLen := int(off) + len(p)
	if len(inode.contents) < newLen {
		padding := make([]byte, newLen-len(inode.contents))
		inode.contents = append(inode.contents, padding...)
		inode.attributes.Size = uint64(newLen)
	}

	// Copy in the data.
	n = copy(inode.contents[off:], p)

	// Sanity check.
	if n != len(p) {
		panic(fmt.Sprintf("Unexpected short copy: %v", n))
	}

	return
}
<|endoftext|>


<commit_before>package oneandone_cloudserver_api

import (

)

type FirewallPolicy struct {
}

type FirewallPolicyCreateData struct {
}

// GET /firewall_policies
func (api *API) GetFirewallPolicies() []FirewallPolicy {
	return []FirewallPolicy{}
}

// POST /firewall_policies
func (api *API) CreateFirewallPolicy(configuration FirewallPolicyCreateData) FirewallPolicy {
	return FirewallPolicy{}
}

// GET /firewall_policies/{id}
func (api *API) GetFirewallPolicy(Id string) FirewallPolicy {
	return FirewallPolicy{}
}

// DELETE /firewall_policies/{id}
func (fwp *FirewallPolicy) Delete() FirewallPolicy {
	return FirewallPolicy{}
}

// PUT /firewall_policies/{id}

// GET /firewall_policies/{id}/server_ips

// PUT /firewall_policies/{id}/server_ips

// GET /firewall_policies/{id}/server_ips/{id}

// DELETE /firewall_policies/{id}/server_ips/{id}

// GET /firewall_policies/{id}/rules

// PUT /firewall_policies/{id}/rules

// GET /firewall_policies/{id}/rules/{id}

// DELETE /firewall_policies/{id}/rules/{id}

<commit_msg>created code for create, read and delete of firewall policies<commit_after>package oneandone_cloudserver_api

import (
	log "github.com/Sirupsen/logrus"
)

type FirewallPolicy struct {
	withId
	withName
	withDescription
	// should be fixed: Status        Status                   `json:"status"`
	Status        string                   `json:"state"`
	DefaultPolicy int                      `json:"default"`
	Rules         []FirewallPolicyRules    `json:"rules"`
	ServerIps     []FirewallPolicyServerIp `json:"server_ips"`
	withApi
}

type FirewallPolicyRules struct {
	withId
	Protocol string `json:"protocol"`
	PortFrom *int   `json:"port_from"`
	PortTo   *int   `json:"port_to"`
	SourceIp string `json:"source"`
}

type FirewallPolicyServerIp struct {
	withId
	Ip         string `json:"ip"`
	ServerName string `json:"server_name"`
}

type FirewallPolicyCreateData struct {
	Name        string                          `json:"name"`
	Description string                          `json:"description"`
	Rules       []FirewallPolicyRulesCreateData `json:"rules"`
}

type FirewallPolicyRulesCreateData struct {
	Protocol string `json:"protocol"`
	PortFrom *int   `json:"port_from"`
	PortTo   *int   `json:"port_to"`
	SourceIp string `json:"source"`
}

// GET /firewall_policies
func (api *API) GetFirewallPolicies() []FirewallPolicy {
	log.Debug("requesting information about firewall policies")
	session := api.prepareSession()
	res := []FirewallPolicy{}
	resp, _ := session.Get(createUrl(api, "firewall_policies"), nil, &res, nil)
	logResult(resp, 200)
	for index, _ := range res {
		res[index].api = api
	}
	return res
}

// POST /firewall_policies
func (api *API) CreateFirewallPolicy(configuration FirewallPolicyCreateData) FirewallPolicy {
	log.Debug("requesting to create a new firewall policy")
	s := api.prepareSession()
	res := FirewallPolicy{}
	resp, _ := s.Post(createUrl(api, "firewall_policies"), configuration, &res, nil)
	logResult(resp, 201)
	res.api = api
	return res
}

// GET /firewall_policies/{id}
func (api *API) GetFirewallPolicy(Id string) FirewallPolicy {
	log.Debug("requesting to about firewall policy ", Id)
	session := api.prepareSession()
	res := FirewallPolicy{}
	resp, _ := session.Get(createUrl(api, "firewall_policies", Id), nil, &res, nil)
	logResult(resp, 200)
	res.api = api
	return res
}

// DELETE /firewall_policies/{id}
func (fwp *FirewallPolicy) Delete() FirewallPolicy {
	log.Debug("Requested to delete firewall policy ", fwp.Id)
	session := fwp.api.prepareSession()
	res := FirewallPolicy{}
	resp, _ := session.Delete(createUrl(fwp.api, "firewall_policies", fwp.Id), &res, nil)
	logResult(resp, 200)
	res.api = fwp.api
	return res

}

// PUT /firewall_policies/{id}

// GET /firewall_policies/{id}/server_ips

// PUT /firewall_policies/{id}/server_ips

// GET /firewall_policies/{id}/server_ips/{id}

// DELETE /firewall_policies/{id}/server_ips/{id}

// GET /firewall_policies/{id}/rules

// PUT /firewall_policies/{id}/rules

// GET /firewall_policies/{id}/rules/{id}

// DELETE /firewall_policies/{id}/rules/{id}
<|endoftext|>


<commit_before>// Package gogitlog implements a very simple wrapper around the
// Go "log" package, providing support for a toggle-able debug flag
// and a couple of functions that log or not based on that flag.
package slog

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"runtime"
	"sync"
	"syscall"
	"time"
	"unsafe"
)

var timeFormat = "2006-01-02T15:04:05.000000"
var logger = New(INFO)

type severity int32 // sync/atomic int32

const (
	DEBUG severity = iota
	INFO
	WARNING
	ERROR
	FATAL
)

var severityName = []string{
	DEBUG:   "DEBUG",
	INFO:    "INFO",
	WARNING: "WARNING",
	ERROR:   "ERROR",
	FATAL:   "FATAL",
}

type LeveledLogger struct {
	*log.Logger
	severity severity
	mx       sync.Mutex
}

func (l *LeveledLogger) header(s severity, t *time.Time) *bytes.Buffer {
	b := new(bytes.Buffer)
	fmt.Fprintf(b, "%s %-5.5s ", t.Format(timeFormat), severityName[s])
	return b
}

func (l *LeveledLogger) logln(s severity, v ...interface{}) {
	if l.severity >= s {
		t := time.Now()
		buf := l.header(s, &t)
		fmt.Fprintln(buf, v...)
		buf.WriteTo(os.Stderr)
	}
}

func (l *LeveledLogger) logf(s severity, format string, v ...interface{}) {
	if l.severity >= s {
		t := time.Now()
		buf := l.header(s, &t)
		fmt.Fprintf(buf, format, v...)
		if buf.Bytes()[buf.Len()-1] != '\n' {
			buf.WriteByte('\n')
		}
		buf.WriteTo(os.Stderr)
	}
}

func New(level severity) *LeveledLogger {
	return &LeveledLogger{
		log.New(os.Stderr, "", log.LstdFlags),
		level,
		sync.Mutex{},
	}
}

// isatty returns true if f is a TTY, false otherwise.
func isatty(f *os.File) bool {
	switch runtime.GOOS {
	case "darwin":
	case "linux":
	default:
		return false
	}
	var t [2]byte
	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
		f.Fd(), syscall.TIOCGPGRP,
		uintptr(unsafe.Pointer(&t)))
	return errno == 0
}

func GetLevel() severity {
	return logger.severity
}

func SetLevel(s severity) {
	logger.severity = s
}

func IsDebug() bool {
	if logger.severity == DEBUG {
		return true
	}
	return false
}

func Debugf(format string, v ...interface{}) {
	logger.logf(DEBUG, format, v...)
}

func Debugln(v ...interface{}) {
	logger.logln(DEBUG, v...)
}

func Infof(format string, v ...interface{}) {
	logger.logf(INFO, format, v...)
}

func Infoln(v ...interface{}) {
	logger.logln(INFO, v...)
}

func Warningf(format string, v ...interface{}) {
	logger.logf(WARNING, format, v...)
}

func Warningln(v ...interface{}) {
	logger.logln(WARNING, v...)
}

func Errorf(format string, v ...interface{}) {
	logger.logf(ERROR, format, v...)
}

func Errorln(v ...interface{}) {
	logger.logln(ERROR, v...)
}

func Fatalf(format string, v ...interface{}) {
	logger.logf(FATAL, format, v...)
	os.Exit(1)
}

func Fatalln(v ...interface{}) {
	logger.logln(FATAL, v...)
	os.Exit(1)
}

// Logs to the default Logger. See Logger.Panicf
func Panicf(format string, v ...interface{}) {
	logger.logf(FATAL, format, v...)
	panic(fmt.Sprintf(format, v...))
}

// Logs to the default Logger. See Logger.Panicln
func Panicln(v ...interface{}) {
	logger.logln(FATAL, v...)
	panic(fmt.Sprintln(v...))
}
<commit_msg>updates<commit_after>// Package gogitlog implements a very simple wrapper around the
// Go "log" package, providing support for a toggle-able debug flag
// and a couple of functions that log or not based on that flag.
package slog

import (
	"bytes"
	"fmt"
	"os"
	"sync"
	"time"
)

var timeFormat = "2006-01-02T15:04:05.000000"
var logger = New(INFO, "")

type severity int32 // sync/atomic int32

const (
	DEBUG severity = iota
	INFO
	WARNING
	ERROR
	FATAL
)

var severityName = []string{
	DEBUG:   "DEBUG",
	INFO:    "INFO",
	WARNING: "WARNING",
	ERROR:   "ERROR",
	FATAL:   "FATAL",
}

type LeveledLogger struct {
	prefix   string
	severity severity
	mx       sync.Mutex
}

func (l *LeveledLogger) header(s severity, t *time.Time) *bytes.Buffer {
	b := new(bytes.Buffer)
	fmt.Fprintf(b, "%s %-5.5s %s", t.Format(timeFormat), severityName[s], l.prefix)
	return b
}

func (l *LeveledLogger) logln(s severity, v ...interface{}) {
	if l.severity >= s {
		t := time.Now()
		buf := l.header(s, &t)
		fmt.Fprintln(buf, v...)
		buf.WriteTo(os.Stderr)
	}
}

func (l *LeveledLogger) logf(s severity, format string, v ...interface{}) {
	if l.severity >= s {
		t := time.Now()
		buf := l.header(s, &t)
		fmt.Fprintf(buf, format, v...)
		if buf.Bytes()[buf.Len()-1] != '\n' {
			buf.WriteByte('\n')
		}
		buf.WriteTo(os.Stderr)
	}
}

func (l *LeveledLogger) GetLevel() severity {
	return l.severity
}

func (l *LeveledLogger) SetLevel(s severity) {
	l.severity = s
}

func (l *LeveledLogger) IsDebug() bool {
	if l.severity == DEBUG {
		return true
	}
	return false
}

func (l *LeveledLogger) Debugf(format string, v ...interface{}) {
	l.logf(DEBUG, format, v...)
}

func (l *LeveledLogger) Debugln(v ...interface{}) {
	l.logln(DEBUG, v...)
}

func (l *LeveledLogger) Infof(format string, v ...interface{}) {
	l.logf(INFO, format, v...)
}

func (l *LeveledLogger) Infoln(v ...interface{}) {
	l.logln(INFO, v...)
}

func (l *LeveledLogger) Warningf(format string, v ...interface{}) {
	l.logf(WARNING, format, v...)
}

func (l *LeveledLogger) Warningln(v ...interface{}) {
	l.logln(WARNING, v...)
}

func (l *LeveledLogger) Errorf(format string, v ...interface{}) {
	l.logf(ERROR, format, v...)
}

func (l *LeveledLogger) Errorln(v ...interface{}) {
	l.logln(ERROR, v...)
}

func (l *LeveledLogger) Fatalf(format string, v ...interface{}) {
	l.logf(FATAL, format, v...)
	os.Exit(1)
}

func (l *LeveledLogger) Fatalln(v ...interface{}) {
	l.logln(FATAL, v...)
	os.Exit(1)
}

func (l *LeveledLogger) Panicf(format string, v ...interface{}) {
	l.logf(FATAL, format, v...)
	panic(fmt.Sprintf(format, v...))
}

func (l *LeveledLogger) Panicln(v ...interface{}) {
	l.logln(FATAL, v...)
	panic(fmt.Sprintln(v...))
}

func New(level severity, prefix string) *LeveledLogger {
	return &LeveledLogger{
		prefix,
		level,
		sync.Mutex{},
	}
}

/*
// isatty returns true if f is a TTY, false otherwise.
func isatty(f *os.File) bool {
	switch runtime.GOOS {
	case "darwin":
	case "linux":
	default:
		return false
	}
	var t [2]byte
	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
		f.Fd(), syscall.TIOCGPGRP,
		uintptr(unsafe.Pointer(&t)))
	return errno == 0
}
*/

func GetLevel() severity {
	return logger.GetLevel()
}

func SetLevel(s severity) {
	logger.SetLevel(s)
}

func IsDebug() bool {
	return logger.IsDebug()
}

func Debugf(format string, v ...interface{}) {
	logger.Debugf(format, v...)
}

func Debugln(v ...interface{}) {
	logger.Debugln(v...)
}

func Infof(format string, v ...interface{}) {
	logger.Infof(format, v...)
}

func Infoln(v ...interface{}) {
	logger.Infoln(v...)
}

func Warningf(format string, v ...interface{}) {
	logger.Warningf(format, v...)
}

func Warningln(v ...interface{}) {
	logger.Warningln(v...)
}

func Errorf(format string, v ...interface{}) {
	logger.Errorf(format, v...)
}

func Errorln(v ...interface{}) {
	logger.Errorln(v...)
}

func Fatalf(format string, v ...interface{}) {
	logger.Fatalf(format, v...)
}

func Fatalln(v ...interface{}) {
	logger.Fatalln(v...)
}

func Panicf(format string, v ...interface{}) {
	logger.Panicf(format, v...)
}

func Panicln(v ...interface{}) {
	logger.Panicln(v...)
}
<|endoftext|>


<commit_before>package azurerm

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/storage"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

// The KeySource of storage.Encryption appears to require this value
// for Encryption services to work
var storageAccountEncryptionSource = "Microsoft.Storage"

const blobStorageAccountDefaultAccessTier = "Hot"

func resourceArmStorageAccount() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmStorageAccountCreate,
		Read:   resourceArmStorageAccountRead,
		Update: resourceArmStorageAccountUpdate,
		Delete: resourceArmStorageAccountDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateArmStorageAccountName,
			},

			"resource_group_name": {
				Type:             schema.TypeString,
				Required:         true,
				ForceNew:         true,
				DiffSuppressFunc: resourceAzurermResourceGroupNameDiffSuppress,
			},

			"location": {
				Type:      schema.TypeString,
				Required:  true,
				ForceNew:  true,
				StateFunc: azureRMNormalizeLocation,
			},

			"account_kind": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				ValidateFunc: validation.StringInSlice([]string{
					string(storage.Storage),
					string(storage.BlobStorage),
				}, true),
				Default: string(storage.Storage),
			},

			"account_type": {
				Type:         schema.TypeString,
				Required:     true,
				ValidateFunc: validateArmStorageAccountType,
			},

			// Only valid for BlobStorage accounts, defaults to "Hot" in create function
			"access_tier": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ValidateFunc: validation.StringInSlice([]string{
					string(storage.Cool),
					string(storage.Hot),
				}, true),
			},

			"enable_blob_encryption": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"primary_location": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_location": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"primary_blob_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_blob_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"primary_queue_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_queue_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"primary_table_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_table_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			// NOTE: The API does not appear to expose a secondary file endpoint
			"primary_file_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"primary_access_key": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_access_key": {
				Type:     schema.TypeString,
				Computed: true,
			},

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

func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient)
	storageClient := client.storageServiceClient

	resourceGroupName := d.Get("resource_group_name").(string)
	storageAccountName := d.Get("name").(string)
	accountKind := d.Get("account_kind").(string)
	accountType := d.Get("account_type").(string)

	location := d.Get("location").(string)
	tags := d.Get("tags").(map[string]interface{})
	enableBlobEncryption := d.Get("enable_blob_encryption").(bool)

	sku := storage.Sku{
		Name: storage.SkuName(accountType),
	}

	opts := storage.AccountCreateParameters{
		Location: &location,
		Sku:      &sku,
		Tags:     expandTags(tags),
		Kind:     storage.Kind(accountKind),
		Properties: &storage.AccountPropertiesCreateParameters{
			Encryption: &storage.Encryption{
				Services: &storage.EncryptionServices{
					Blob: &storage.EncryptionService{
						Enabled: &enableBlobEncryption,
					},
				},
				KeySource: &storageAccountEncryptionSource,
			},
		},
	}

	// AccessTier is only valid for BlobStorage accounts
	if accountKind == string(storage.BlobStorage) {
		accessTier, ok := d.GetOk("access_tier")
		if !ok {
			// default to "Hot"
			accessTier = blobStorageAccountDefaultAccessTier
		}

		opts.Properties.AccessTier = storage.AccessTier(accessTier.(string))
	}

	// Create
	cancelCtx, _ := context.WithTimeout(client.StopContext, 1*time.Hour)
	_, createErr := storageClient.Create(
		resourceGroupName, storageAccountName, opts, cancelCtx.Done())

	// The only way to get the ID back apparently is to read the resource again
	read, err := storageClient.GetProperties(resourceGroupName, storageAccountName)

	// Set the ID right away if we have one
	if err == nil && read.ID != nil {
		log.Printf("[INFO] storage account %q ID: %q", storageAccountName, *read.ID)
		d.SetId(*read.ID)
	}

	// If we had a create error earlier then we return with that error now.
	// We do this later here so that we can grab the ID above is possible.
	if createErr != nil {
		return fmt.Errorf(
			"Error creating Azure Storage Account '%s': %s",
			storageAccountName, createErr)
	}

	// Check the read error now that we know it would exist without a create err
	if err != nil {
		return err
	}

	// If we got no ID then the resource group doesn't yet exist
	if read.ID == nil {
		return fmt.Errorf("Cannot read Storage Account %s (resource group %s) ID",
			storageAccountName, resourceGroupName)
	}

	log.Printf("[DEBUG] Waiting for Storage Account (%s) to become available", storageAccountName)
	stateConf := &resource.StateChangeConf{
		Pending:    []string{"Updating", "Creating"},
		Target:     []string{"Succeeded"},
		Refresh:    storageAccountStateRefreshFunc(client, resourceGroupName, storageAccountName),
		Timeout:    30 * time.Minute,
		MinTimeout: 15 * time.Second,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf("Error waiting for Storage Account (%s) to become available: %s", storageAccountName, err)
	}

	return resourceArmStorageAccountRead(d, meta)
}

// resourceArmStorageAccountUpdate is unusual in the ARM API where most resources have a combined
// and idempotent operation for CreateOrUpdate. In particular updating all of the parameters
// available requires a call to Update per parameter...
func resourceArmStorageAccountUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).storageServiceClient
	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	storageAccountName := id.Path["storageAccounts"]
	resourceGroupName := id.ResourceGroup

	d.Partial(true)

	if d.HasChange("account_type") {
		accountType := d.Get("account_type").(string)

		sku := storage.Sku{
			Name: storage.SkuName(accountType),
		}

		opts := storage.AccountUpdateParameters{
			Sku: &sku,
		}
		_, err := client.Update(resourceGroupName, storageAccountName, opts)
		if err != nil {
			return fmt.Errorf("Error updating Azure Storage Account type %q: %s", storageAccountName, err)
		}

		d.SetPartial("account_type")
	}

	if d.HasChange("access_tier") {
		accessTier := d.Get("access_tier").(string)

		opts := storage.AccountUpdateParameters{
			Properties: &storage.AccountPropertiesUpdateParameters{
				AccessTier: storage.AccessTier(accessTier),
			},
		}
		_, err := client.Update(resourceGroupName, storageAccountName, opts)
		if err != nil {
			return fmt.Errorf("Error updating Azure Storage Account access_tier %q: %s", storageAccountName, err)
		}

		d.SetPartial("access_tier")
	}

	if d.HasChange("tags") {
		tags := d.Get("tags").(map[string]interface{})

		opts := storage.AccountUpdateParameters{
			Tags: expandTags(tags),
		}
		_, err := client.Update(resourceGroupName, storageAccountName, opts)
		if err != nil {
			return fmt.Errorf("Error updating Azure Storage Account tags %q: %s", storageAccountName, err)
		}

		d.SetPartial("tags")
	}

	if d.HasChange("enable_blob_encryption") {
		enableBlobEncryption := d.Get("enable_blob_encryption").(bool)

		opts := storage.AccountUpdateParameters{
			Properties: &storage.AccountPropertiesUpdateParameters{
				Encryption: &storage.Encryption{
					Services: &storage.EncryptionServices{
						Blob: &storage.EncryptionService{
							Enabled: &enableBlobEncryption,
						},
					},
					KeySource: &storageAccountEncryptionSource,
				},
			},
		}
		_, err := client.Update(resourceGroupName, storageAccountName, opts)
		if err != nil {
			return fmt.Errorf("Error updating Azure Storage Account enable_blob_encryption %q: %s", storageAccountName, err)
		}

		d.SetPartial("enable_blob_encryption")
	}

	d.Partial(false)
	return nil
}

func resourceArmStorageAccountRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).storageServiceClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	name := id.Path["storageAccounts"]
	resGroup := id.ResourceGroup

	resp, err := client.GetProperties(resGroup, name)
	if err != nil {
		if resp.StatusCode == http.StatusNotFound {
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading the state of AzureRM Storage Account %q: %s", name, err)
	}

	keys, err := client.ListKeys(resGroup, name)
	if err != nil {
		return err
	}

	accessKeys := *keys.Keys
	d.Set("resource_group_name", resGroup)
	d.Set("primary_access_key", accessKeys[0].Value)
	d.Set("secondary_access_key", accessKeys[1].Value)
	d.Set("location", resp.Location)
	d.Set("account_kind", resp.Kind)
	d.Set("account_type", resp.Sku.Name)
	d.Set("primary_location", resp.Properties.PrimaryLocation)
	d.Set("secondary_location", resp.Properties.SecondaryLocation)

	if resp.Properties.AccessTier != "" {
		d.Set("access_tier", resp.Properties.AccessTier)
	}

	if resp.Properties.PrimaryEndpoints != nil {
		d.Set("primary_blob_endpoint", resp.Properties.PrimaryEndpoints.Blob)
		d.Set("primary_queue_endpoint", resp.Properties.PrimaryEndpoints.Queue)
		d.Set("primary_table_endpoint", resp.Properties.PrimaryEndpoints.Table)
		d.Set("primary_file_endpoint", resp.Properties.PrimaryEndpoints.File)
	}

	if resp.Properties.SecondaryEndpoints != nil {
		if resp.Properties.SecondaryEndpoints.Blob != nil {
			d.Set("secondary_blob_endpoint", resp.Properties.SecondaryEndpoints.Blob)
		} else {
			d.Set("secondary_blob_endpoint", "")
		}
		if resp.Properties.SecondaryEndpoints.Queue != nil {
			d.Set("secondary_queue_endpoint", resp.Properties.SecondaryEndpoints.Queue)
		} else {
			d.Set("secondary_queue_endpoint", "")
		}
		if resp.Properties.SecondaryEndpoints.Table != nil {
			d.Set("secondary_table_endpoint", resp.Properties.SecondaryEndpoints.Table)
		} else {
			d.Set("secondary_table_endpoint", "")
		}
	}

	if resp.Properties.Encryption != nil {
		if resp.Properties.Encryption.Services.Blob != nil {
			d.Set("enable_blob_encryption", resp.Properties.Encryption.Services.Blob.Enabled)
		}
	}

	d.Set("name", resp.Name)

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmStorageAccountDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).storageServiceClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	name := id.Path["storageAccounts"]
	resGroup := id.ResourceGroup

	_, err = client.Delete(resGroup, name)
	if err != nil {
		return fmt.Errorf("Error issuing AzureRM delete request for storage account %q: %s", name, err)
	}

	return nil
}

func validateArmStorageAccountName(v interface{}, k string) (ws []string, es []error) {
	input := v.(string)

	if !regexp.MustCompile(`\A([a-z0-9]{3,24})\z`).MatchString(input) {
		es = append(es, fmt.Errorf("name can only consist of lowercase letters and numbers, and must be between 3 and 24 characters long"))
	}

	return
}

func validateArmStorageAccountType(v interface{}, k string) (ws []string, es []error) {
	validAccountTypes := []string{"standard_lrs", "standard_zrs",
		"standard_grs", "standard_ragrs", "premium_lrs"}

	input := strings.ToLower(v.(string))

	for _, valid := range validAccountTypes {
		if valid == input {
			return
		}
	}

	es = append(es, fmt.Errorf("Invalid storage account type %q", input))
	return
}

func storageAccountStateRefreshFunc(client *ArmClient, resourceGroupName string, storageAccountName string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		res, err := client.storageServiceClient.GetProperties(resourceGroupName, storageAccountName)
		if err != nil {
			return nil, "", fmt.Errorf("Error issuing read request in storageAccountStateRefreshFunc to Azure ARM for Storage Account '%s' (RG: '%s'): %s", storageAccountName, resourceGroupName, err)
		}

		return res, string(res.Properties.ProvisioningState), nil
	}
}
<commit_msg>providers/azurerm: don't leak the context cancellation function<commit_after>package azurerm

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/storage"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

// The KeySource of storage.Encryption appears to require this value
// for Encryption services to work
var storageAccountEncryptionSource = "Microsoft.Storage"

const blobStorageAccountDefaultAccessTier = "Hot"

func resourceArmStorageAccount() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmStorageAccountCreate,
		Read:   resourceArmStorageAccountRead,
		Update: resourceArmStorageAccountUpdate,
		Delete: resourceArmStorageAccountDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateArmStorageAccountName,
			},

			"resource_group_name": {
				Type:             schema.TypeString,
				Required:         true,
				ForceNew:         true,
				DiffSuppressFunc: resourceAzurermResourceGroupNameDiffSuppress,
			},

			"location": {
				Type:      schema.TypeString,
				Required:  true,
				ForceNew:  true,
				StateFunc: azureRMNormalizeLocation,
			},

			"account_kind": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				ValidateFunc: validation.StringInSlice([]string{
					string(storage.Storage),
					string(storage.BlobStorage),
				}, true),
				Default: string(storage.Storage),
			},

			"account_type": {
				Type:         schema.TypeString,
				Required:     true,
				ValidateFunc: validateArmStorageAccountType,
			},

			// Only valid for BlobStorage accounts, defaults to "Hot" in create function
			"access_tier": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ValidateFunc: validation.StringInSlice([]string{
					string(storage.Cool),
					string(storage.Hot),
				}, true),
			},

			"enable_blob_encryption": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"primary_location": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_location": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"primary_blob_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_blob_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"primary_queue_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_queue_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"primary_table_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_table_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			// NOTE: The API does not appear to expose a secondary file endpoint
			"primary_file_endpoint": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"primary_access_key": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"secondary_access_key": {
				Type:     schema.TypeString,
				Computed: true,
			},

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

func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient)
	storageClient := client.storageServiceClient

	resourceGroupName := d.Get("resource_group_name").(string)
	storageAccountName := d.Get("name").(string)
	accountKind := d.Get("account_kind").(string)
	accountType := d.Get("account_type").(string)

	location := d.Get("location").(string)
	tags := d.Get("tags").(map[string]interface{})
	enableBlobEncryption := d.Get("enable_blob_encryption").(bool)

	sku := storage.Sku{
		Name: storage.SkuName(accountType),
	}

	opts := storage.AccountCreateParameters{
		Location: &location,
		Sku:      &sku,
		Tags:     expandTags(tags),
		Kind:     storage.Kind(accountKind),
		Properties: &storage.AccountPropertiesCreateParameters{
			Encryption: &storage.Encryption{
				Services: &storage.EncryptionServices{
					Blob: &storage.EncryptionService{
						Enabled: &enableBlobEncryption,
					},
				},
				KeySource: &storageAccountEncryptionSource,
			},
		},
	}

	// AccessTier is only valid for BlobStorage accounts
	if accountKind == string(storage.BlobStorage) {
		accessTier, ok := d.GetOk("access_tier")
		if !ok {
			// default to "Hot"
			accessTier = blobStorageAccountDefaultAccessTier
		}

		opts.Properties.AccessTier = storage.AccessTier(accessTier.(string))
	}

	// Create
	cancelCtx, cancelFunc := context.WithTimeout(client.StopContext, 1*time.Hour)
	_, createErr := storageClient.Create(
		resourceGroupName, storageAccountName, opts, cancelCtx.Done())
	cancelFunc()

	// The only way to get the ID back apparently is to read the resource again
	read, err := storageClient.GetProperties(resourceGroupName, storageAccountName)

	// Set the ID right away if we have one
	if err == nil && read.ID != nil {
		log.Printf("[INFO] storage account %q ID: %q", storageAccountName, *read.ID)
		d.SetId(*read.ID)
	}

	// If we had a create error earlier then we return with that error now.
	// We do this later here so that we can grab the ID above is possible.
	if createErr != nil {
		return fmt.Errorf(
			"Error creating Azure Storage Account '%s': %s",
			storageAccountName, createErr)
	}

	// Check the read error now that we know it would exist without a create err
	if err != nil {
		return err
	}

	// If we got no ID then the resource group doesn't yet exist
	if read.ID == nil {
		return fmt.Errorf("Cannot read Storage Account %s (resource group %s) ID",
			storageAccountName, resourceGroupName)
	}

	log.Printf("[DEBUG] Waiting for Storage Account (%s) to become available", storageAccountName)
	stateConf := &resource.StateChangeConf{
		Pending:    []string{"Updating", "Creating"},
		Target:     []string{"Succeeded"},
		Refresh:    storageAccountStateRefreshFunc(client, resourceGroupName, storageAccountName),
		Timeout:    30 * time.Minute,
		MinTimeout: 15 * time.Second,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf("Error waiting for Storage Account (%s) to become available: %s", storageAccountName, err)
	}

	return resourceArmStorageAccountRead(d, meta)
}

// resourceArmStorageAccountUpdate is unusual in the ARM API where most resources have a combined
// and idempotent operation for CreateOrUpdate. In particular updating all of the parameters
// available requires a call to Update per parameter...
func resourceArmStorageAccountUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).storageServiceClient
	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	storageAccountName := id.Path["storageAccounts"]
	resourceGroupName := id.ResourceGroup

	d.Partial(true)

	if d.HasChange("account_type") {
		accountType := d.Get("account_type").(string)

		sku := storage.Sku{
			Name: storage.SkuName(accountType),
		}

		opts := storage.AccountUpdateParameters{
			Sku: &sku,
		}
		_, err := client.Update(resourceGroupName, storageAccountName, opts)
		if err != nil {
			return fmt.Errorf("Error updating Azure Storage Account type %q: %s", storageAccountName, err)
		}

		d.SetPartial("account_type")
	}

	if d.HasChange("access_tier") {
		accessTier := d.Get("access_tier").(string)

		opts := storage.AccountUpdateParameters{
			Properties: &storage.AccountPropertiesUpdateParameters{
				AccessTier: storage.AccessTier(accessTier),
			},
		}
		_, err := client.Update(resourceGroupName, storageAccountName, opts)
		if err != nil {
			return fmt.Errorf("Error updating Azure Storage Account access_tier %q: %s", storageAccountName, err)
		}

		d.SetPartial("access_tier")
	}

	if d.HasChange("tags") {
		tags := d.Get("tags").(map[string]interface{})

		opts := storage.AccountUpdateParameters{
			Tags: expandTags(tags),
		}
		_, err := client.Update(resourceGroupName, storageAccountName, opts)
		if err != nil {
			return fmt.Errorf("Error updating Azure Storage Account tags %q: %s", storageAccountName, err)
		}

		d.SetPartial("tags")
	}

	if d.HasChange("enable_blob_encryption") {
		enableBlobEncryption := d.Get("enable_blob_encryption").(bool)

		opts := storage.AccountUpdateParameters{
			Properties: &storage.AccountPropertiesUpdateParameters{
				Encryption: &storage.Encryption{
					Services: &storage.EncryptionServices{
						Blob: &storage.EncryptionService{
							Enabled: &enableBlobEncryption,
						},
					},
					KeySource: &storageAccountEncryptionSource,
				},
			},
		}
		_, err := client.Update(resourceGroupName, storageAccountName, opts)
		if err != nil {
			return fmt.Errorf("Error updating Azure Storage Account enable_blob_encryption %q: %s", storageAccountName, err)
		}

		d.SetPartial("enable_blob_encryption")
	}

	d.Partial(false)
	return nil
}

func resourceArmStorageAccountRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).storageServiceClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	name := id.Path["storageAccounts"]
	resGroup := id.ResourceGroup

	resp, err := client.GetProperties(resGroup, name)
	if err != nil {
		if resp.StatusCode == http.StatusNotFound {
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading the state of AzureRM Storage Account %q: %s", name, err)
	}

	keys, err := client.ListKeys(resGroup, name)
	if err != nil {
		return err
	}

	accessKeys := *keys.Keys
	d.Set("resource_group_name", resGroup)
	d.Set("primary_access_key", accessKeys[0].Value)
	d.Set("secondary_access_key", accessKeys[1].Value)
	d.Set("location", resp.Location)
	d.Set("account_kind", resp.Kind)
	d.Set("account_type", resp.Sku.Name)
	d.Set("primary_location", resp.Properties.PrimaryLocation)
	d.Set("secondary_location", resp.Properties.SecondaryLocation)

	if resp.Properties.AccessTier != "" {
		d.Set("access_tier", resp.Properties.AccessTier)
	}

	if resp.Properties.PrimaryEndpoints != nil {
		d.Set("primary_blob_endpoint", resp.Properties.PrimaryEndpoints.Blob)
		d.Set("primary_queue_endpoint", resp.Properties.PrimaryEndpoints.Queue)
		d.Set("primary_table_endpoint", resp.Properties.PrimaryEndpoints.Table)
		d.Set("primary_file_endpoint", resp.Properties.PrimaryEndpoints.File)
	}

	if resp.Properties.SecondaryEndpoints != nil {
		if resp.Properties.SecondaryEndpoints.Blob != nil {
			d.Set("secondary_blob_endpoint", resp.Properties.SecondaryEndpoints.Blob)
		} else {
			d.Set("secondary_blob_endpoint", "")
		}
		if resp.Properties.SecondaryEndpoints.Queue != nil {
			d.Set("secondary_queue_endpoint", resp.Properties.SecondaryEndpoints.Queue)
		} else {
			d.Set("secondary_queue_endpoint", "")
		}
		if resp.Properties.SecondaryEndpoints.Table != nil {
			d.Set("secondary_table_endpoint", resp.Properties.SecondaryEndpoints.Table)
		} else {
			d.Set("secondary_table_endpoint", "")
		}
	}

	if resp.Properties.Encryption != nil {
		if resp.Properties.Encryption.Services.Blob != nil {
			d.Set("enable_blob_encryption", resp.Properties.Encryption.Services.Blob.Enabled)
		}
	}

	d.Set("name", resp.Name)

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmStorageAccountDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).storageServiceClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	name := id.Path["storageAccounts"]
	resGroup := id.ResourceGroup

	_, err = client.Delete(resGroup, name)
	if err != nil {
		return fmt.Errorf("Error issuing AzureRM delete request for storage account %q: %s", name, err)
	}

	return nil
}

func validateArmStorageAccountName(v interface{}, k string) (ws []string, es []error) {
	input := v.(string)

	if !regexp.MustCompile(`\A([a-z0-9]{3,24})\z`).MatchString(input) {
		es = append(es, fmt.Errorf("name can only consist of lowercase letters and numbers, and must be between 3 and 24 characters long"))
	}

	return
}

func validateArmStorageAccountType(v interface{}, k string) (ws []string, es []error) {
	validAccountTypes := []string{"standard_lrs", "standard_zrs",
		"standard_grs", "standard_ragrs", "premium_lrs"}

	input := strings.ToLower(v.(string))

	for _, valid := range validAccountTypes {
		if valid == input {
			return
		}
	}

	es = append(es, fmt.Errorf("Invalid storage account type %q", input))
	return
}

func storageAccountStateRefreshFunc(client *ArmClient, resourceGroupName string, storageAccountName string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		res, err := client.storageServiceClient.GetProperties(resourceGroupName, storageAccountName)
		if err != nil {
			return nil, "", fmt.Errorf("Error issuing read request in storageAccountStateRefreshFunc to Azure ARM for Storage Account '%s' (RG: '%s'): %s", storageAccountName, resourceGroupName, err)
		}

		return res, string(res.Properties.ProvisioningState), nil
	}
}
<|endoftext|>