<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/docopt/docopt-go"
	"github.com/jesand/crowds/amt"
	xsdt "github.com/metaleap/go-xsd/types"
	"os"
	"reflect"
	"sort"
)

const (
	USAGE = `hiclusterd - Web service hosting for hicluster

Usage:
  amtadmin balance --amt=<path> [--sandbox]
  amtadmin hit --amt=<path> --id=<id> [--sandbox]
  amtadmin -h | --help
  amtadmin --version

Options:
  balance       Get the account balance
  hits          List HIT information
  --amt=<path>  The path to a file containing AMT credentials
  --sandbox     Address the AMT sandbox instead of the production site
  --id=<id>     The ID of the object you want to view
`
)

type AmtCred struct {
	AccessKey, SecretKey string
}

func main() {

	// Parse the command line
	args, _ := docopt.Parse(USAGE, nil, true, "1.0", false)

	// Initialize the AMT client
	var (
		credPath = args["--amt"].(string)
		sandbox  = args["--sandbox"].(bool)
		amtCred  AmtCred
		client   *amt.AmtClient
	)
	if f, err := os.Open(credPath); err != nil {
		fmt.Printf("Error: Could not open %s - %v", credPath, err)
		return
	} else if err = json.NewDecoder(f).Decode(&amtCred); err != nil {
		fmt.Printf("Error: Could not parse %s - %v", credPath, err)
		return
	} else {
		client = amt.NewClient(amtCred.AccessKey, amtCred.SecretKey, sandbox)
	}

	switch {
	case args["balance"].(bool):
		RunBalance(client)
	case args["hit"].(bool):
		hitId, _ := args["--id"].(string)
		RunHit(client, hitId)
	}
}

func getObjectFields(object interface{}, vals map[string]string) {
	v := reflect.Indirect(reflect.ValueOf(object))
	if !v.IsValid() {
		return
	}
	t := v.Type()
	switch t.Kind() {
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			getObjectFields(v.Index(i).Interface(), vals)
		}
	case reflect.Struct:
		for i := 0; i < t.NumField(); i++ {
			field := t.Field(i)
			switch field.Type.Kind() {
			case reflect.Struct, reflect.Ptr, reflect.Slice:
				getObjectFields(v.Field(i).Interface(), vals)
			default:
				if field.Type == reflect.TypeOf(xsdt.Int(0)) {
					vals[field.Name] = fmt.Sprintf("%d", v.Field(i).Interface())
				} else if field.Type == reflect.TypeOf(xsdt.Long(0)) {
					vals[field.Name] = fmt.Sprintf("%d", v.Field(i).Interface())
				} else {
					vals[field.Name] = v.Field(i).String()
				}
			}
		}
	}
}

func printObject(object interface{}) {
	var (
		fields   []string
		vals     = make(map[string]string)
		fieldLen int
	)
	getObjectFields(object, vals)
	for name, _ := range vals {
		fields = append(fields, name)
		if len(name) > fieldLen {
			fieldLen = len(name)
		}
	}
	sort.Strings(fields)
	format := fmt.Sprintf("%%%ds: %%s\n", fieldLen)
	for _, name := range fields {
		fmt.Printf(format, name, vals[name])
	}
}

func RunBalance(client *amt.AmtClient) {
	balance, err := client.GetAccountBalance()
	if err != nil {
		fmt.Printf("Error: The AMT request failed: %v\n", err)
		return
	}
	printObject(balance)
}

func RunHit(client *amt.AmtClient, hitId string) {
	if hit, err := client.GetHIT(hitId); err != nil {
		fmt.Printf("Error: The AMT request failed: %v\n", err)
		return
	} else if len(hit.Hits) > 0 && hit.Hits[0].Request != nil &&
		hit.Hits[0].Request.Errors != nil {

		printObject(hit.Hits[0].Request)
	} else {
		printObject(hit)
	}
}
<commit_msg>added amtadmin commands<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/docopt/docopt-go"
	"github.com/jesand/crowds/amt"
	xsdt "github.com/metaleap/go-xsd/types"
	"os"
	"reflect"
	"sort"
	"strconv"
)

const (
	USAGE = `hiclusterd - Web service hosting for hicluster

Usage:
  amtadmin balance --amt=<path> [--sandbox]
  amtadmin show [--hit=<id>] [--assn=<id>] --amt=<path> [--sandbox]
  amtadmin hits [--sort=<field>] [--desc] [--page=<num>] [--pageSize=<num>] ` +
		`--amt=<path> [--sandbox]
  amtadmin assns --hit=<id> [--status=<str>] [--sort=<field>] [--desc] ` +
		`[--page=<num>] [--pageSize=<num>] --amt=<path> [--sandbox]
  amtadmin -h | --help
  amtadmin --version

Options:
  balance           Get the account balance
  show              Display the status of a HIT or Assignment
  hits              Find matching HITs
  assns             Find assignments for a HIT
  --amt=<path>      The path to a file containing AMT credentials
  --sandbox         Address the AMT sandbox instead of the production site
  --hit=<id>        The ID of the HIT you want to view
  --assn=<id>       The ID of the assignment you want to view
  --sort=<field>    The field to sort by. For hits, one of: CreationTime,
                    Enumeration, Expiration, Reward, or Title. For assns, one
                    of: AcceptTime, SubmitTime, or AssignmentStatus.
  --status=<str>    The assignment status to search for. Can be:
                    Submitted, Approved, or Rejected.
  --desc            Sort results in descending order
  --page=<num>      The page number of results to display [default: 1]
  --pageSize=<num>  The number of results to display per page [default: 10]
`
)

type AmtCred struct {
	AccessKey, SecretKey string
}

func main() {

	// Parse the command line
	args, _ := docopt.Parse(USAGE, nil, true, "1.0", false)

	// Initialize the AMT client
	var (
		credPath = args["--amt"].(string)
		sandbox  = args["--sandbox"].(bool)
		amtCred  AmtCred
		client   amt.AmtClient
	)
	if f, err := os.Open(credPath); err != nil {
		fmt.Printf("Error: Could not open %s - %v", credPath, err)
		return
	} else if err = json.NewDecoder(f).Decode(&amtCred); err != nil {
		fmt.Printf("Error: Could not parse %s - %v", credPath, err)
		return
	} else {
		client = amt.NewClient(amtCred.AccessKey, amtCred.SecretKey, sandbox)
	}

	switch {
	case args["balance"].(bool):
		RunBalance(client)

	case args["show"].(bool):
		hitId, _ := args["--hit"].(string)
		assnId, _ := args["--assn"].(string)
		RunShow(client, hitId, assnId)

	case args["hits"].(bool):
		var (
			sort, _               = args["--sort"].(string)
			desc                  = args["--desc"].(bool)
			page, pageErr         = strconv.Atoi(args["--page"].(string))
			pageSize, pageSizeErr = strconv.Atoi(args["--pageSize"].(string))
		)
		if sort == "" {
			sort = "CreationTime"
		}
		if pageErr != nil {
			fmt.Printf("Invalid --page argument\n")
		} else if pageSizeErr != nil {
			fmt.Printf("Invald --pageSize argument\n")
		} else {
			RunHits(client, sort, desc, page, pageSize)
		}

	case args["assns"].(bool):
		var (
			hitId, _              = args["--hit"].(string)
			status, _             = args["--status"].(string)
			sort, _               = args["--sort"].(string)
			desc                  = args["--desc"].(bool)
			page, pageErr         = strconv.Atoi(args["--page"].(string))
			pageSize, pageSizeErr = strconv.Atoi(args["--pageSize"].(string))
			statuses              []string
		)
		if sort == "" {
			sort = "AcceptTime"
		}
		if status != "" {
			statuses = append(statuses, status)
		}
		if pageErr != nil {
			fmt.Printf("Invalid --page argument\n")
		} else if pageSizeErr != nil {
			fmt.Printf("Invald --pageSize argument\n")
		} else {
			RunAssns(client, hitId, statuses, sort, desc, page, pageSize)
		}
	}
}

func getObjectFields(object interface{}, vals map[string]string) {
	v := reflect.Indirect(reflect.ValueOf(object))
	if !v.IsValid() {
		return
	}
	t := v.Type()
	switch t.Kind() {
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			getObjectFields(v.Index(i).Interface(), vals)
		}
	case reflect.Struct:
		for i := 0; i < t.NumField(); i++ {
			field := t.Field(i)
			switch field.Type.Kind() {
			case reflect.Struct, reflect.Ptr, reflect.Slice:
				getObjectFields(v.Field(i).Interface(), vals)
			default:
				if field.Type == reflect.TypeOf(xsdt.Int(0)) {
					vals[field.Name] = fmt.Sprintf("%d", v.Field(i).Interface())
				} else if field.Type == reflect.TypeOf(xsdt.Long(0)) {
					vals[field.Name] = fmt.Sprintf("%d", v.Field(i).Interface())
				} else {
					vals[field.Name] = v.Field(i).String()
				}
			}
		}
	}
}

func printObject(object interface{}) {
	var (
		fields   []string
		vals     = make(map[string]string)
		fieldLen int
	)
	getObjectFields(object, vals)
	for name, _ := range vals {
		fields = append(fields, name)
		if len(name) > fieldLen {
			fieldLen = len(name)
		}
	}
	sort.Strings(fields)
	format := fmt.Sprintf("%%%ds: %%s\n", fieldLen)
	for _, name := range fields {
		fmt.Printf(format, name, vals[name])
	}
}

func RunBalance(client amt.AmtClient) {
	balance, err := client.GetAccountBalance()
	if err != nil {
		fmt.Printf("Error: The AMT request failed: %v\n", err)
		return
	}
	printObject(balance)
}

func RunShow(client amt.AmtClient, hitId, assnId string) {
	switch {
	case hitId != "":
		if resp, err := client.GetHIT(hitId); err != nil {
			fmt.Printf("Error: The AMT request failed: %v\n", err)
			return
		} else if len(resp.Hits) > 0 && resp.Hits[0].Request != nil &&
			resp.Hits[0].Request.Errors != nil {

			printObject(resp.Hits[0].Request)
		} else {
			printObject(resp)
		}

	case assnId != "":
		if resp, err := client.GetAssignment(assnId); err != nil {
			fmt.Printf("Error: The AMT request failed: %v\n", err)
			return
		} else if len(resp.GetAssignmentResults) > 0 &&
			resp.GetAssignmentResults[0].Request != nil &&
			resp.GetAssignmentResults[0].Request.Errors != nil {

			printObject(resp.GetAssignmentResults[0].Request)
		} else {
			printObject(resp)
		}

	default:
		fmt.Println("You must provide a value for either --hit or --assn")
	}
}

func RunHits(client amt.AmtClient, sort string, desc bool, page, pageSize int) {
	if resp, err := client.SearchHITs(sort, !desc, pageSize, page); err != nil {
		fmt.Printf("Error: The AMT request failed: %v\n", err)
		return
	} else if len(resp.SearchHITsResults) > 0 &&
		resp.SearchHITsResults[0].Request != nil &&
		resp.SearchHITsResults[0].Request.Errors != nil {

		printObject(resp.SearchHITsResults[0].Request)
	} else if len(resp.SearchHITsResults[0].Hits) == 0 {
		fmt.Println("Found no HITs for this account")
	} else {
		for i, hit := range resp.SearchHITsResults[0].Hits {
			fmt.Printf("HIT %d/%d:\n", i+1, len(resp.SearchHITsResults))
			printObject(hit)
			fmt.Println()
		}
	}
}

func RunAssns(client amt.AmtClient, hitId string, statuses []string, sort string, desc bool, page, pageSize int) {
	if resp, err := client.GetAssignmentsForHIT(hitId, statuses, sort, !desc,
		pageSize, page); err != nil {

		fmt.Printf("Error: The AMT request failed: %v\n", err)
		return
	} else if len(resp.GetAssignmentsForHITResults) > 0 &&
		resp.GetAssignmentsForHITResults[0].Request != nil &&
		resp.GetAssignmentsForHITResults[0].Request.Errors != nil {

		printObject(resp.GetAssignmentsForHITResults[0].Request)
	} else if len(resp.GetAssignmentsForHITResults[0].Assignments) == 0 {
		fmt.Println("Found no assignments for this HIT")
	} else {
		for i, assn := range resp.GetAssignmentsForHITResults[0].Assignments {
			fmt.Printf("Assignment %d/%d:\n", i+1, len(resp.GetAssignmentsForHITResults))
			printObject(assn)
			fmt.Println()
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 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 shards

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
)

type shardLoader interface {
	// Load a new file. Should be safe for concurrent calls.
	load(filename string)
	drop(filename string)
}

type shardWatcher struct {
	dir        string
	timestamps map[string]time.Time
	loader     shardLoader
	quit       chan<- struct{}
}

func (sw *shardWatcher) Close() error {
	if sw.quit != nil {
		close(sw.quit)
		sw.quit = nil
	}
	return nil
}

func NewDirectoryWatcher(dir string, loader shardLoader) (io.Closer, error) {
	quitter := make(chan struct{}, 1)
	sw := &shardWatcher{
		dir:        dir,
		timestamps: map[string]time.Time{},
		loader:     loader,
		quit:       quitter,
	}
	if err := sw.scan(); err != nil {
		return nil, err
	}

	if err := sw.watch(quitter); err != nil {
		return nil, err
	}

	return sw, nil
}

func (s *shardWatcher) String() string {
	return fmt.Sprintf("shardWatcher(%s)", s.dir)
}

func (s *shardWatcher) scan() error {
	fs, err := filepath.Glob(filepath.Join(s.dir, "*.zoekt"))
	if err != nil {
		return err
	}

	if len(s.timestamps) == 0 && len(fs) == 0 {
		return fmt.Errorf("directory %s is empty", s.dir)
	}

	ts := map[string]time.Time{}
	for _, fn := range fs {
		fi, err := os.Lstat(fn)
		if err != nil {
			continue
		}

		ts[fn] = fi.ModTime()
	}

	var toLoad []string
	for k, mtime := range ts {
		if t, ok := s.timestamps[k]; !ok || t != mtime {
			toLoad = append(toLoad, k)
			s.timestamps[k] = mtime
		}
	}

	var toDrop []string
	// Unload deleted shards.
	for k := range s.timestamps {
		if _, ok := ts[k]; !ok {
			toDrop = append(toDrop, k)
			delete(s.timestamps, k)
		}
	}

	for _, t := range toDrop {
		log.Printf("unloading: %s", t)
		s.loader.drop(t)
	}

	var wg sync.WaitGroup
	for _, t := range toLoad {
		wg.Add(1)
		go func(k string) {
			s.loader.load(k)
			wg.Done()
		}(t)
	}
	wg.Wait()

	return nil
}

func (s *shardWatcher) watch(quitter <-chan struct{}) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	if err := watcher.Add(s.dir); err != nil {
		return err
	}

	go func() {
		for {
			select {
			case <-watcher.Events:
				s.scan()
			case err := <-watcher.Errors:
				if err != nil {
					log.Println("watcher error:", err)
				}
			case <-quitter:
				watcher.Close()
				return
			}
		}
	}()
	return nil
}
<commit_msg>shards: consolidate events before calling scan<commit_after>// Copyright 2017 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 shards

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
)

type shardLoader interface {
	// Load a new file. Should be safe for concurrent calls.
	load(filename string)
	drop(filename string)
}

type shardWatcher struct {
	dir        string
	timestamps map[string]time.Time
	loader     shardLoader
	quit       chan<- struct{}
}

func (sw *shardWatcher) Close() error {
	if sw.quit != nil {
		close(sw.quit)
		sw.quit = nil
	}
	return nil
}

func NewDirectoryWatcher(dir string, loader shardLoader) (io.Closer, error) {
	quitter := make(chan struct{}, 1)
	sw := &shardWatcher{
		dir:        dir,
		timestamps: map[string]time.Time{},
		loader:     loader,
		quit:       quitter,
	}
	if err := sw.scan(); err != nil {
		return nil, err
	}

	if err := sw.watch(quitter); err != nil {
		return nil, err
	}

	return sw, nil
}

func (s *shardWatcher) String() string {
	return fmt.Sprintf("shardWatcher(%s)", s.dir)
}

func (s *shardWatcher) scan() error {
	fs, err := filepath.Glob(filepath.Join(s.dir, "*.zoekt"))
	if err != nil {
		return err
	}

	if len(s.timestamps) == 0 && len(fs) == 0 {
		return fmt.Errorf("directory %s is empty", s.dir)
	}

	ts := map[string]time.Time{}
	for _, fn := range fs {
		fi, err := os.Lstat(fn)
		if err != nil {
			continue
		}

		ts[fn] = fi.ModTime()
	}

	var toLoad []string
	for k, mtime := range ts {
		if t, ok := s.timestamps[k]; !ok || t != mtime {
			toLoad = append(toLoad, k)
			s.timestamps[k] = mtime
		}
	}

	var toDrop []string
	// Unload deleted shards.
	for k := range s.timestamps {
		if _, ok := ts[k]; !ok {
			toDrop = append(toDrop, k)
			delete(s.timestamps, k)
		}
	}

	for _, t := range toDrop {
		log.Printf("unloading: %s", t)
		s.loader.drop(t)
	}

	var wg sync.WaitGroup
	for _, t := range toLoad {
		wg.Add(1)
		go func(k string) {
			s.loader.load(k)
			wg.Done()
		}(t)
	}
	wg.Wait()

	return nil
}

func (s *shardWatcher) watch(quitter <-chan struct{}) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	if err := watcher.Add(s.dir); err != nil {
		return err
	}

	// intermediate signal channel so if there are multiple watcher.Events we
	// only call scan once.
	signal := make(chan struct{}, 1)

	go func() {
		for {
			select {
			case <-watcher.Events:
				select {
				case signal <- struct{}{}:
				default:
				}
			case err := <-watcher.Errors:
				if err != nil {
					log.Println("watcher error:", err)
				}
			case <-quitter:
				watcher.Close()
				close(signal)
				return
			}
		}
	}()

	go func() {
		for range signal {
			s.scan()
		}
	}()

	return nil
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"fmt"

	. "github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"

	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("User Access", func() {

	flag.Parse()

	BeforeEach(func() {
		tests.BeforeTestCleanup()
	})

	Describe("With default kubevirt service accounts", func() {
		table.DescribeTable("should verify permissions are correct for view, edit, and admin", func(resource string) {
			tests.SkipIfNoKubectl()

			view := tests.ViewServiceAccountName
			edit := tests.EditServiceAccountName
			admin := tests.AdminServiceAccountName

			viewVerbs := make(map[string]string)
			editVerbs := make(map[string]string)
			adminVerbs := make(map[string]string)

			// GET
			viewVerbs["get"] = "yes"
			editVerbs["get"] = "yes"
			adminVerbs["get"] = "yes"

			// List
			viewVerbs["list"] = "yes"
			editVerbs["list"] = "yes"
			adminVerbs["list"] = "yes"

			// WATCH
			viewVerbs["watch"] = "yes"
			editVerbs["watch"] = "yes"
			adminVerbs["watch"] = "yes"

			// DELETE
			viewVerbs["delete"] = "no"
			editVerbs["delete"] = "yes"
			adminVerbs["delete"] = "yes"

			// CREATE
			viewVerbs["create"] = "no"
			editVerbs["create"] = "yes"
			adminVerbs["create"] = "yes"

			// UPDATE
			viewVerbs["update"] = "no"
			editVerbs["update"] = "yes"
			adminVerbs["update"] = "yes"

			// PATCH
			viewVerbs["patch"] = "no"
			editVerbs["patch"] = "yes"
			adminVerbs["patch"] = "yes"

			// DELETE COllECTION
			viewVerbs["deleteCollection"] = "no"
			editVerbs["deleteCollection"] = "no"
			adminVerbs["deleteCollection"] = "yes"

			namespace := tests.NamespaceTestDefault
			verbs := []string{"get", "list", "watch", "delete", "create", "update", "patch", "deletecollection"}

			for _, verb := range verbs {
				// VIEW
				By(fmt.Sprintf("verifying VIEW sa for verb %s", verb))
				expectedRes, _ := viewVerbs[verb]
				as := fmt.Sprintf("system:serviceaccount:%s:%s", namespace, view)
				result, err := tests.RunKubectlCommand("auth", "can-i", "--as", as, verb, resource)
				Expect(err).ToNot(HaveOccurred())
				Expect(result).To(ContainSubstring(expectedRes))

				// EDIT
				By(fmt.Sprintf("verifying EDIT sa for verb %s", verb))
				expectedRes, _ = editVerbs[verb]
				as = fmt.Sprintf("system:serviceaccount:%s:%s", namespace, edit)
				result, err = tests.RunKubectlCommand("auth", "can-i", "--as", as, verb, resource)
				Expect(err).ToNot(HaveOccurred())
				Expect(result).To(ContainSubstring(expectedRes))

				// ADMIN
				By(fmt.Sprintf("verifying ADMIN sa for verb %s", verb))
				expectedRes, _ = adminVerbs[verb]
				as = fmt.Sprintf("system:serviceaccount:%s:%s", namespace, admin)
				result, err = tests.RunKubectlCommand("auth", "can-i", "--as", as, verb, resource)
				Expect(err).ToNot(HaveOccurred())
				Expect(result).To(ContainSubstring(expectedRes))

				// DEFAULT - the default should always return 'no' for ever verb.
				// This is primarily a sanity check.
				By(fmt.Sprintf("verifying DEFAULT sa for verb %s", verb))
				expectedRes = "no"
				as = fmt.Sprintf("system:serviceaccount:%s:default", namespace)
				result, err = tests.RunKubectlCommand("auth", "can-i", "--as", as, verb, resource)
				Expect(err).ToNot(HaveOccurred())
				Expect(result).To(ContainSubstring(expectedRes))
			}
		},
			table.Entry("given a vmi", "virtualmachineinstances"),
			table.Entry("given an vm", "virtualmachines"),
			table.Entry("given a vmi preset", "virtualmachineinstancepresets"),
			table.Entry("given a vmi replica set", "virtualmachineinstancereplicasets"),
		)
	})
})
<commit_msg>Fixed access_test.go<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"fmt"

	. "github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"

	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("User Access", func() {

	flag.Parse()

	BeforeEach(func() {
		tests.BeforeTestCleanup()
	})

	Describe("With default kubevirt service accounts", func() {
		table.DescribeTable("should verify permissions are correct for view, edit, and admin", func(resource string) {
			tests.SkipIfNoKubectl()

			view := tests.ViewServiceAccountName
			edit := tests.EditServiceAccountName
			admin := tests.AdminServiceAccountName

			viewVerbs := make(map[string]string)
			editVerbs := make(map[string]string)
			adminVerbs := make(map[string]string)

			// GET
			viewVerbs["get"] = "yes"
			editVerbs["get"] = "yes"
			adminVerbs["get"] = "yes"

			// List
			viewVerbs["list"] = "yes"
			editVerbs["list"] = "yes"
			adminVerbs["list"] = "yes"

			// WATCH
			viewVerbs["watch"] = "yes"
			editVerbs["watch"] = "yes"
			adminVerbs["watch"] = "yes"

			// DELETE
			viewVerbs["delete"] = "no"
			editVerbs["delete"] = "yes"
			adminVerbs["delete"] = "yes"

			// CREATE
			viewVerbs["create"] = "no"
			editVerbs["create"] = "yes"
			adminVerbs["create"] = "yes"

			// UPDATE
			viewVerbs["update"] = "no"
			editVerbs["update"] = "yes"
			adminVerbs["update"] = "yes"

			// PATCH
			viewVerbs["patch"] = "no"
			editVerbs["patch"] = "yes"
			adminVerbs["patch"] = "yes"

			// DELETE COllECTION
			viewVerbs["deleteCollection"] = "no"
			editVerbs["deleteCollection"] = "no"
			adminVerbs["deleteCollection"] = "yes"

			namespace := tests.NamespaceTestDefault
			verbs := []string{"get", "list", "watch", "delete", "create", "update", "patch", "deletecollection"}

			for _, verb := range verbs {
				// VIEW
				By(fmt.Sprintf("verifying VIEW sa for verb %s", verb))
				expectedRes, _ := viewVerbs[verb]
				as := fmt.Sprintf("system:serviceaccount:%s:%s", namespace, view)
				result, _ := tests.RunKubectlCommand("auth", "can-i", "--as", as, verb, resource)
				Expect(result).To(ContainSubstring(expectedRes))

				// EDIT
				By(fmt.Sprintf("verifying EDIT sa for verb %s", verb))
				expectedRes, _ = editVerbs[verb]
				as = fmt.Sprintf("system:serviceaccount:%s:%s", namespace, edit)
				result, _ = tests.RunKubectlCommand("auth", "can-i", "--as", as, verb, resource)
				Expect(result).To(ContainSubstring(expectedRes))

				// ADMIN
				By(fmt.Sprintf("verifying ADMIN sa for verb %s", verb))
				expectedRes, _ = adminVerbs[verb]
				as = fmt.Sprintf("system:serviceaccount:%s:%s", namespace, admin)
				result, _ = tests.RunKubectlCommand("auth", "can-i", "--as", as, verb, resource)
				Expect(result).To(ContainSubstring(expectedRes))

				// DEFAULT - the default should always return 'no' for ever verb.
				// This is primarily a sanity check.
				By(fmt.Sprintf("verifying DEFAULT sa for verb %s", verb))
				expectedRes = "no"
				as = fmt.Sprintf("system:serviceaccount:%s:default", namespace)
				result, _ = tests.RunKubectlCommand("auth", "can-i", "--as", as, verb, resource)
				Expect(result).To(ContainSubstring(expectedRes))
			}
		},
			table.Entry("given a vmi", "virtualmachineinstances"),
			table.Entry("given an vm", "virtualmachines"),
			table.Entry("given a vmi preset", "virtualmachineinstancepresets"),
			table.Entry("given a vmi replica set", "virtualmachineinstancereplicasets"),
		)
	})
})
<|endoftext|>


<commit_before>package tls

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"

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

type keyAlgo func(d *schema.ResourceData) (interface{}, error)
type keyParser func([]byte) (interface{}, error)

var keyAlgos map[string]keyAlgo = map[string]keyAlgo{
	"RSA": func(d *schema.ResourceData) (interface{}, error) {
		rsaBits := d.Get("rsa_bits").(int)
		return rsa.GenerateKey(rand.Reader, rsaBits)
	},
	"ECDSA": func(d *schema.ResourceData) (interface{}, error) {
		curve := d.Get("ecdsa_curve").(string)
		switch curve {
		case "P224":
			return ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
		case "P256":
			return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
		case "P384":
			return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
		case "P521":
			return ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
		default:
			return nil, fmt.Errorf("invalid ecdsa_curve; must be P224, P256, P384 or P521")
		}
	},
}

var keyParsers map[string]keyParser = map[string]keyParser{
	"RSA": func(der []byte) (interface{}, error) {
		return x509.ParsePKCS1PrivateKey(der)
	},
	"ECDSA": func(der []byte) (interface{}, error) {
		return x509.ParseECPrivateKey(der)
	},
}

func resourcePrivateKey() *schema.Resource {
	return &schema.Resource{
		Create: CreatePrivateKey,
		Delete: DeletePrivateKey,
		Read:   ReadPrivateKey,

		Schema: map[string]*schema.Schema{
			"algorithm": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "Name of the algorithm to use to generate the private key",
				ForceNew:    true,
			},

			"rsa_bits": &schema.Schema{
				Type:        schema.TypeInt,
				Optional:    true,
				Description: "Number of bits to use when generating an RSA key",
				ForceNew:    true,
				Default:     2048,
			},

			"ecdsa_curve": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "ECDSA curve to use when generating a key",
				ForceNew:    true,
				Default:     "P224",
			},

			"private_key_pem": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"public_key_pem": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func CreatePrivateKey(d *schema.ResourceData, meta interface{}) error {
	keyAlgoName := d.Get("algorithm").(string)
	var keyFunc keyAlgo
	var ok bool
	if keyFunc, ok = keyAlgos[keyAlgoName]; !ok {
		return fmt.Errorf("invalid key_algorithm %#v", keyAlgoName)
	}

	key, err := keyFunc(d)
	if err != nil {
		return err
	}

	var keyPemBlock *pem.Block
	switch k := key.(type) {
	case *rsa.PrivateKey:
		keyPemBlock = &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
	case *ecdsa.PrivateKey:
		b, err := x509.MarshalECPrivateKey(k)
		if err != nil {
			return fmt.Errorf("error encoding key to PEM: %s", err)
		}
		keyPemBlock = &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	case *ecdsa.PublicKey:
		pubKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey(key))
		if err != nil {
			return fmt.Errorf("failed to marshal public key: %s", err)
		}
		pubKeyPemBlock := &pem.Block{Type: "EC PUBLIC KEY", Bytes: pubKeyBytes}
	default:
		return fmt.Errorf("unsupported private key type")
	}
	keyPem := string(pem.EncodeToMemory(keyPemBlock))

	d.SetId(hashForState(string((pubKeyBytes))))
	d.Set("private_key_pem", keyPem)

	return nil
}

func DeletePrivateKey(d *schema.ResourceData, meta interface{}) error {
	d.SetId("")
	return nil
}

func ReadPrivateKey(d *schema.ResourceData, meta interface{}) error {
	return nil
}

func publicKey(priv interface{}) interface{} {
	switch k := priv.(type) {
	case *rsa.PrivateKey:
		return &k.PublicKey
	case *ecdsa.PrivateKey:
		return &k.PublicKey
	default:
		return nil
	}
}
<commit_msg>Fixing a variable scope issue<commit_after>package tls

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"

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

type keyAlgo func(d *schema.ResourceData) (interface{}, error)
type keyParser func([]byte) (interface{}, error)

var keyAlgos map[string]keyAlgo = map[string]keyAlgo{
	"RSA": func(d *schema.ResourceData) (interface{}, error) {
		rsaBits := d.Get("rsa_bits").(int)
		return rsa.GenerateKey(rand.Reader, rsaBits)
	},
	"ECDSA": func(d *schema.ResourceData) (interface{}, error) {
		curve := d.Get("ecdsa_curve").(string)
		switch curve {
		case "P224":
			return ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
		case "P256":
			return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
		case "P384":
			return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
		case "P521":
			return ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
		default:
			return nil, fmt.Errorf("invalid ecdsa_curve; must be P224, P256, P384 or P521")
		}
	},
}

var keyParsers map[string]keyParser = map[string]keyParser{
	"RSA": func(der []byte) (interface{}, error) {
		return x509.ParsePKCS1PrivateKey(der)
	},
	"ECDSA": func(der []byte) (interface{}, error) {
		return x509.ParseECPrivateKey(der)
	},
}

func resourcePrivateKey() *schema.Resource {
	return &schema.Resource{
		Create: CreatePrivateKey,
		Delete: DeletePrivateKey,
		Read:   ReadPrivateKey,

		Schema: map[string]*schema.Schema{
			"algorithm": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "Name of the algorithm to use to generate the private key",
				ForceNew:    true,
			},

			"rsa_bits": &schema.Schema{
				Type:        schema.TypeInt,
				Optional:    true,
				Description: "Number of bits to use when generating an RSA key",
				ForceNew:    true,
				Default:     2048,
			},

			"ecdsa_curve": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "ECDSA curve to use when generating a key",
				ForceNew:    true,
				Default:     "P224",
			},

			"private_key_pem": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"public_key_pem": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func CreatePrivateKey(d *schema.ResourceData, meta interface{}) error {
	keyAlgoName := d.Get("algorithm").(string)
	var keyFunc keyAlgo
	var ok bool
	if keyFunc, ok = keyAlgos[keyAlgoName]; !ok {
		return fmt.Errorf("invalid key_algorithm %#v", keyAlgoName)
	}

	key, err := keyFunc(d)
	if err != nil {
		return err
	}

	var keyPemBlock *pem.Block
	switch k := key.(type) {
	case *rsa.PrivateKey:
		keyPemBlock = &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
	case *ecdsa.PrivateKey:
		b, err := x509.MarshalECPrivateKey(k)
		if err != nil {
			return fmt.Errorf("error encoding key to PEM: %s", err)
		}
		keyPemBlock = &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	case *ecdsa.PublicKey:
		pubKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey(key))
		if err != nil {
			return fmt.Errorf("failed to marshal public key: %s", err)
		}
		pubKeyPemBlock := &pem.Block{Type: "EC PUBLIC KEY", Bytes: pubKeyBytes}
		d.SetId(hashForState(string((pubKeyBytes))))
	default:
		return fmt.Errorf("unsupported private key type")
	}
	keyPem := string(pem.EncodeToMemory(keyPemBlock))

	d.Set("private_key_pem", keyPem)

	return nil
}

func DeletePrivateKey(d *schema.ResourceData, meta interface{}) error {
	d.SetId("")
	return nil
}

func ReadPrivateKey(d *schema.ResourceData, meta interface{}) error {
	return nil
}

func publicKey(priv interface{}) interface{} {
	switch k := priv.(type) {
	case *rsa.PrivateKey:
		return &k.PublicKey
	case *ecdsa.PrivateKey:
		return &k.PublicKey
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 1&1 Internet AG, http://1und1.de . All rights reserved. Licensed under the Apache v2 License.
 */

package oneandone_cloudserver_api

import (
	"github.com/docker/machine/log"
	"net/http"
)

type SharedStorage struct {
	withId
	Size  int    `json:"size"`
	State string `json:"state"`
	withDescription
	CloudPanelId string `json:"cloudpanel_id"`
	SizeUsed     string `json:"size_used"`
	CifsPath     string `json:"cifs_path"`
	NfsPath      string `json:"nfs_path"`
	withName
	CreationDate  string                `json:"creation_date"`
	SharedStorage []SharedStorageServer `json:"servers"`
	withApi
}

type SharedStorageServerPermissions struct {
	SharedStorageServer []SharedStorageServer `json:"servers"`
}

type SharedStorageServer struct {
	Id            string         `json:"id"`
	Name          string         `json:"name"`
	Rights        string         `json:"rights"`
	sharedStorage *SharedStorage `json:"omitempty"`
}

type SharedStorageSettings struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Size        int    `json:"size"`
}

type SharedStorageAccessCredentials struct {
	State               string `json:"state"`
	KerberosContentFile string `json:"kerberos_content_file"`
	UserDomain          string `json:"user_domain"`
	withApi
}

type SharedStorageAccessCredentialsSettings struct {
	Password string `json:"password"`
}

// GET /shared_storages
func (api *API) GetSharedStorages() ([]SharedStorage, error) {
	log.Debug("Requesting information about shared storages")
	result := []SharedStorage{}
	err := api.Client.Get(createUrl(api, SharedStoragesPathSegment), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	for index, _ := range result {
		result[index].api = api
	}
	return result, nil
}

// POST /shared_storages
func (api *API) CreateSharedStorage(configuration SharedStorageSettings) (*SharedStorage, error) {
	log.Debugf("Creating a new shared storage with name '%s'", configuration.Name)
	result := new(SharedStorage)
	err := api.Client.Post(createUrl(api, SharedStoragesPathSegment), configuration, &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// GET /shared_storages/{id}
func (api *API) GetSharedStorage(sharedStorageId string) (*SharedStorage, error) {
	log.Debugf("Requesting information about the shared storage with the id: '%s'", sharedStorageId)
	result := new(SharedStorage)
	err := api.Client.Get(createUrl(api, SharedStoragesPathSegment, sharedStorageId), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// DELETE /shared_storages/{id}
func (st *SharedStorage) Delete() (*SharedStorage, error) {
	log.Debugf("Deleteing shared storage with id: '%s'", st.Id)
	result := new(SharedStorage)
	err := st.api.Client.Delete(createUrl(st.api, SharedStoragesPathSegment, st.Id), &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.api = st.api
	return result, nil
}

// PUT /shared_storages/{id}
func (st *SharedStorage) UpdateConfig(configuration SharedStorageSettings) (*SharedStorage, error) {
	log.Debugf("Updateing the shared storage with the id: '%s'", st.Id)
	result := new(SharedStorage)
	err := st.api.Client.Put(createUrl(st.api, SharedStoragesPathSegment, st.Id), configuration, &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.api = st.api
	return result, nil
}

// GET /shared_storages/{id}/servers
func (st *SharedStorage) GetServersPermissions() ([]SharedStorageServer, error) {
	log.Debugf("Requesting servers with permissions the the shared storage with the id: '%s'", st.Id)
	result := []SharedStorageServer{}
	err := st.api.Client.Get(createUrl(st.api, SharedStoragesPathSegment, st.Id, "servers"), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	for index, _ := range result {
		result[index].sharedStorage = st
	}
	return result, nil
}

// PUT /shared_storages/{id}/servers
func (st *SharedStorage) UpdateServerPermissions(sharedStorageServerPermissions SharedStorageServerPermissions) (*SharedStorage, error) {
	log.Debugf("Updateing server permissions for the shared storage with the id: '%s'", st.Id)
	result := new(SharedStorage)
	resultError := st.api.Client.Put(createUrl(st.api, SharedStoragesPathSegment, st.Id, "servers"), &sharedStorageServerPermissions, &result, http.StatusAccepted)
	if resultError != nil {
		return nil, resultError
	}
	result.api = st.api
	return result, nil
}

// GET /shared_storages/{id}/servers/{id}
func (st *SharedStorage) GetServerPermission(sharedStorageServerId string) (*SharedStorageServer, error) {
	log.Debugf("Requesting server permissions for the server: '%s' on the shared storage: '%s' ", sharedStorageServerId, st.Id)
	result := new(SharedStorageServer)
	err := st.api.Client.Get(createUrl(st.api, SharedStoragesPathSegment, st.Id, "servers", sharedStorageServerId), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.sharedStorage = st
	return result, nil
}

// DELETE /shared_storages/{id}/servers/{id}
func (sts *SharedStorageServer) DeleteServerPermission() (*SharedStorageServer, error) {
	log.Debugf("Deleting shared storage server permission for the server: '%s' for the shared storage: '%s'", sts.Id, sts.sharedStorage.Id)
	result := new(SharedStorageServer)
	err := sts.sharedStorage.api.Client.Delete(createUrl(sts.sharedStorage.api, SharedStoragesPathSegment, sts.sharedStorage.Id, "servers", sts.Id), &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.sharedStorage = sts.sharedStorage
	return result, nil
}

// GET /shared_storages/access
func (api *API) GetSharedStorageAccessCredentials() (*SharedStorageAccessCredentials, error) {
	log.Debugf("Requesting access credentials for the shared storage access")
	result := new(SharedStorageAccessCredentials)
	err := api.Client.Get(createUrl(api, SharedStoragesPathSegment, "access"), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// PUT /shared_storages/access
func (stac *SharedStorageAccessCredentials) UpdateAccessCredentials(sharedStorageAccessCredentialsSettings SharedStorageAccessCredentialsSettings) (*SharedStorageAccessCredentials, error) {
	log.Debugf("Updateing access credentials for the shared storage access")
	result := new(SharedStorageAccessCredentials)
	err := stac.api.Client.Put(createUrl(stac.api, SharedStoragesPathSegment, "access"), &sharedStorageAccessCredentialsSettings, &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.api = stac.api
	return result, nil
}
<commit_msg>Impement WaitForState for shared storages<commit_after>/*
 * Copyright 2015 1&1 Internet AG, http://1und1.de . All rights reserved. Licensed under the Apache v2 License.
 */

package oneandone_cloudserver_api

import (
	"github.com/docker/machine/log"
	"net/http"
	"time"
)

type SharedStorage struct {
	withId
	Size  int    `json:"size"`
	State string `json:"state"`
	withDescription
	CloudPanelId string `json:"cloudpanel_id"`
	SizeUsed     string `json:"size_used"`
	CifsPath     string `json:"cifs_path"`
	NfsPath      string `json:"nfs_path"`
	withName
	CreationDate  string                `json:"creation_date"`
	SharedStorage []SharedStorageServer `json:"servers"`
	withApi
}

type SharedStorageServerPermissions struct {
	SharedStorageServer []SharedStorageServer `json:"servers"`
}

type SharedStorageServer struct {
	Id            string         `json:"id"`
	Name          string         `json:"name"`
	Rights        string         `json:"rights"`
	sharedStorage *SharedStorage `json:"omitempty"`
}

type SharedStorageSettings struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Size        int    `json:"size"`
}

type SharedStorageAccessCredentials struct {
	State               string `json:"state"`
	KerberosContentFile string `json:"kerberos_content_file"`
	UserDomain          string `json:"user_domain"`
	withApi
}

type SharedStorageAccessCredentialsSettings struct {
	Password string `json:"password"`
}

// GET /shared_storages
func (api *API) GetSharedStorages() ([]SharedStorage, error) {
	log.Debug("Requesting information about shared storages")
	result := []SharedStorage{}
	err := api.Client.Get(createUrl(api, SharedStoragesPathSegment), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	for index, _ := range result {
		result[index].api = api
	}
	return result, nil
}

// POST /shared_storages
func (api *API) CreateSharedStorage(configuration SharedStorageSettings) (*SharedStorage, error) {
	log.Debugf("Creating a new shared storage with name '%s'", configuration.Name)
	result := new(SharedStorage)
	err := api.Client.Post(createUrl(api, SharedStoragesPathSegment), configuration, &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// GET /shared_storages/{id}
func (api *API) GetSharedStorage(sharedStorageId string) (*SharedStorage, error) {
	log.Debugf("Requesting information about the shared storage with the id: '%s'", sharedStorageId)
	result := new(SharedStorage)
	err := api.Client.Get(createUrl(api, SharedStoragesPathSegment, sharedStorageId), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// DELETE /shared_storages/{id}
func (st *SharedStorage) Delete() (*SharedStorage, error) {
	log.Debugf("Deleteing shared storage with id: '%s'", st.Id)
	result := new(SharedStorage)
	err := st.api.Client.Delete(createUrl(st.api, SharedStoragesPathSegment, st.Id), &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.api = st.api
	return result, nil
}

// PUT /shared_storages/{id}
func (st *SharedStorage) UpdateConfig(configuration SharedStorageSettings) (*SharedStorage, error) {
	log.Debugf("Updateing the shared storage with the id: '%s'", st.Id)
	result := new(SharedStorage)
	err := st.api.Client.Put(createUrl(st.api, SharedStoragesPathSegment, st.Id), configuration, &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.api = st.api
	return result, nil
}

// GET /shared_storages/{id}/servers
func (st *SharedStorage) GetServersPermissions() ([]SharedStorageServer, error) {
	log.Debugf("Requesting servers with permissions the the shared storage with the id: '%s'", st.Id)
	result := []SharedStorageServer{}
	err := st.api.Client.Get(createUrl(st.api, SharedStoragesPathSegment, st.Id, "servers"), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	for index, _ := range result {
		result[index].sharedStorage = st
	}
	return result, nil
}

// PUT /shared_storages/{id}/servers
func (st *SharedStorage) UpdateServerPermissions(sharedStorageServerPermissions SharedStorageServerPermissions) (*SharedStorage, error) {
	log.Debugf("Updateing server permissions for the shared storage with the id: '%s'", st.Id)
	result := new(SharedStorage)
	resultError := st.api.Client.Put(createUrl(st.api, SharedStoragesPathSegment, st.Id, "servers"), &sharedStorageServerPermissions, &result, http.StatusAccepted)
	if resultError != nil {
		return nil, resultError
	}
	result.api = st.api
	return result, nil
}

// GET /shared_storages/{id}/servers/{id}
func (st *SharedStorage) GetServerPermission(sharedStorageServerId string) (*SharedStorageServer, error) {
	log.Debugf("Requesting server permissions for the server: '%s' on the shared storage: '%s' ", sharedStorageServerId, st.Id)
	result := new(SharedStorageServer)
	err := st.api.Client.Get(createUrl(st.api, SharedStoragesPathSegment, st.Id, "servers", sharedStorageServerId), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.sharedStorage = st
	return result, nil
}

// DELETE /shared_storages/{id}/servers/{id}
func (sts *SharedStorageServer) DeleteServerPermission() (*SharedStorageServer, error) {
	log.Debugf("Deleting shared storage server permission for the server: '%s' for the shared storage: '%s'", sts.Id, sts.sharedStorage.Id)
	result := new(SharedStorageServer)
	err := sts.sharedStorage.api.Client.Delete(createUrl(sts.sharedStorage.api, SharedStoragesPathSegment, sts.sharedStorage.Id, "servers", sts.Id), &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.sharedStorage = sts.sharedStorage
	return result, nil
}

// GET /shared_storages/access
func (api *API) GetSharedStorageAccessCredentials() (*SharedStorageAccessCredentials, error) {
	log.Debugf("Requesting access credentials for the shared storage access")
	result := new(SharedStorageAccessCredentials)
	err := api.Client.Get(createUrl(api, SharedStoragesPathSegment, "access"), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// PUT /shared_storages/access
func (stac *SharedStorageAccessCredentials) UpdateAccessCredentials(sharedStorageAccessCredentialsSettings SharedStorageAccessCredentialsSettings) (*SharedStorageAccessCredentials, error) {
	log.Debugf("Updateing access credentials for the shared storage access")
	result := new(SharedStorageAccessCredentials)
	err := stac.api.Client.Put(createUrl(stac.api, SharedStoragesPathSegment, "access"), &sharedStorageAccessCredentialsSettings, &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.api = stac.api
	return result, nil
}

// Function to perform busy-wating for a certain shared storage state.
//
// This function queries the shared storage with the given id every 5s until the shared storage's state equals the given state.
func (st *SharedStorage) WaitForState(expectedState string) error {
	sharedStorage, err := st.api.GetSharedStorage(st.Id)
	if err != nil {
		return err
	}
	log.Debugf("Wait for expected status: '%s' current: '%s'", expectedState, sharedStorage.State)
	for sharedStorage.State != expectedState {
		time.Sleep(5 * time.Second)
		sharedStorage, err := st.api.GetSharedStorage(st.Id)
		if err != nil {
			return err
		}
		if sharedStorage.State == expectedState {
			log.Debugf("The shared storage is now in the expected state: '%s'", expectedState)
			return nil
		} else {
			log.Debugf("Wait for expected status: '%s' current: '%s'", expectedState, sharedStorage.State)
		}
	}
	return nil
}<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strings"

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

// version
const VERSION = "1.0"

// Command - one command type
type Commands map[string]string

// Config - config struct
type Config struct {
	token      string   // bot token
	addExit    bool     // add /exit command
	botTimeout int      // bot timeout
	allowUsers []string // users telegram-names who allow chats with bot
	rootUsers  []string // users telegram-names who confirm new users through of it private chat
}

// ------------------------------------------------------------------
// get config
func getConfig() (commands Commands, app_config Config, err error) {
	flag.StringVar(&app_config.token, "tb-token", "", "set bot token (or set TB_TOKEN variable)")
	flag.BoolVar(&app_config.addExit, "add-exit", false, "add /exit command for terminate bot")
	flag.IntVar(&app_config.botTimeout, "timeout", 60, "bot timeout")
	allowUsers := flag.String("allow-users", "", "users telegram-names who allow chats with bot (\"user1,user2\")")
	rootUsers := flag.String("root-users", "", "users telegram-names who confirm new users through of it private chat (\"user1,user2\")")

	flag.Usage = func() {
		fmt.Printf("usage: %s [options] /chat_command \"shell command\" /chat_command2 \"shell command2\"\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}
	version := flag.Bool("version", false, "get version")
	flag.Parse()
	if *version {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	if *allowUsers != "" {
		app_config.allowUsers = strings.Split(*allowUsers, ",")
	}
	if *rootUsers != "" {
		app_config.rootUsers = strings.Split(*rootUsers, ",")
	}

	commands = Commands{}
	// need >= 2 arguments and count of it must be even
	args := flag.Args()
	if len(args) < 2 || len(args)%2 == 1 {
		return commands, app_config, fmt.Errorf("error: need pairs of chat-command and shell-command")
	}

	for i := 0; i < len(args); i += 2 {
		path, cmd := args[i], args[i+1]
		if path[0] != '/' {
			return commands, app_config, fmt.Errorf("error: path %s dont starts with /", path)
		}
		commands[path] = cmd
	}

	if app_config.token == "" {
		if app_config.token = os.Getenv("TB_TOKEN"); app_config.token == "" {
			return commands, app_config, fmt.Errorf("TB_TOKEN environment var not found. See https://core.telegram.org/bots#botfather for more information\n")
		}
	}

	return commands, app_config, nil
}

// ------------------------------------------------------------------
func main() {
	commands, app_config, err := getConfig()
	if err != nil {
		log.Fatal(err)
	}

	bot, err := tgbotapi.NewBotAPI(app_config.token)
	if err != nil {
		log.Fatal(err)
	}

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

	var ucfg tgbotapi.UpdateConfig = tgbotapi.NewUpdate(0)
	ucfg.Timeout = app_config.botTimeout
	err = bot.UpdatesChan(ucfg)
	if err != nil {
		log.Fatal(err)
	}

	go_exit := false
	users := NewUsers(app_config)

LOOP:
	for {
		select {
		case telegram_update := <-bot.Updates:

			chat_id := telegram_update.Message.Chat.ID

			parts := regexp.MustCompile(`\s+`).Split(telegram_update.Message.Text, 2)
			replay_msg := ""

			if len(parts) > 0 && len(parts[0]) > 0 && parts[0][0] == '/' {

				user_from := telegram_update.Message.From

				users.AddNew(user_from, telegram_update.Message.Chat)
				allowExec := users.IsAuthorized(user_from)

				if parts[0] == "/auth" {

					if len(parts) == 1 || parts[1] == "" {

						replay_msg = "See code in terminal with shell2telegram or ack code from root user and type:\n/auth code"
						users.DoLogin(user_from.ID)

						secretCodeMsg := fmt.Sprintf("Request access for %s. Code: %s\n", users.String(user_from.ID), users.list[user_from.ID].AuthCode)
						fmt.Print(secretCodeMsg)
						users.broadcastForRoots(bot, secretCodeMsg)

					} else if len(parts) > 1 {
						if users.IsValidCode(user_from.ID, parts[1]) {
							replay_msg = fmt.Sprintf("You (@%s) authorized.", user_from.UserName)
							users.list[user_from.ID].IsAuthorized = true
						} else {
							replay_msg = fmt.Sprintf("Code is not valid.")
						}
					}

				} else if parts[0] == "/help" {

					if allowExec {
						for cmd, shell_cmd := range commands {
							replay_msg += fmt.Sprintf("%s - %s\n", cmd, shell_cmd)
						}
						if app_config.addExit {
							replay_msg += fmt.Sprintf("%s - %s\n", "/exit", "terminate bot")
						}
					}
					replay_msg += fmt.Sprintf("%s - %s\n", "/auth [code]", "authorize user")

				} else if allowExec && app_config.addExit && parts[0] == "/exit" {
					replay_msg = "bye..."
					go_exit = true
				} else if cmd, found := commands[parts[0]]; allowExec && found {

					shell, params := "sh", []string{"-c", cmd}
					if len(parts) > 1 {
						params = append(params, parts[1])
					}

					os_exec_command := exec.Command(shell, params...)
					os_exec_command.Stderr = os.Stderr
					shell_out, err := os_exec_command.Output()
					if err != nil {
						log.Println("exec error: ", err)
						replay_msg = fmt.Sprintf("exec error: %s", err)
					} else {
						replay_msg = string(shell_out)
					}
				}

				if replay_msg != "" {
					_, err := bot.SendMessage(tgbotapi.NewMessage(chat_id, replay_msg))
					if err != nil {
						log.Print("Bot send message error:", err)
					}
					if go_exit {
						break LOOP
					}
				}
			}
		}
	}
}
<commit_msg>Changed format of user name<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strings"

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

// version
const VERSION = "1.0"

// Command - one command type
type Commands map[string]string

// Config - config struct
type Config struct {
	token      string   // bot token
	addExit    bool     // add /exit command
	botTimeout int      // bot timeout
	allowUsers []string // users telegram-names who allow chats with bot
	rootUsers  []string // users telegram-names who confirm new users through of it private chat
}

// ------------------------------------------------------------------
// get config
func getConfig() (commands Commands, app_config Config, err error) {
	flag.StringVar(&app_config.token, "tb-token", "", "set bot token (or set TB_TOKEN variable)")
	flag.BoolVar(&app_config.addExit, "add-exit", false, "add /exit command for terminate bot")
	flag.IntVar(&app_config.botTimeout, "timeout", 60, "bot timeout")
	allowUsers := flag.String("allow-users", "", "users telegram-names who allow chats with bot (\"user1,user2\")")
	rootUsers := flag.String("root-users", "", "users telegram-names who confirm new users through of it private chat (\"user1,user2\")")

	flag.Usage = func() {
		fmt.Printf("usage: %s [options] /chat_command \"shell command\" /chat_command2 \"shell command2\"\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}
	version := flag.Bool("version", false, "get version")
	flag.Parse()
	if *version {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	if *allowUsers != "" {
		app_config.allowUsers = strings.Split(*allowUsers, ",")
	}
	if *rootUsers != "" {
		app_config.rootUsers = strings.Split(*rootUsers, ",")
	}

	commands = Commands{}
	// need >= 2 arguments and count of it must be even
	args := flag.Args()
	if len(args) < 2 || len(args)%2 == 1 {
		return commands, app_config, fmt.Errorf("error: need pairs of chat-command and shell-command")
	}

	for i := 0; i < len(args); i += 2 {
		path, cmd := args[i], args[i+1]
		if path[0] != '/' {
			return commands, app_config, fmt.Errorf("error: path %s dont starts with /", path)
		}
		commands[path] = cmd
	}

	if app_config.token == "" {
		if app_config.token = os.Getenv("TB_TOKEN"); app_config.token == "" {
			return commands, app_config, fmt.Errorf("TB_TOKEN environment var not found. See https://core.telegram.org/bots#botfather for more information\n")
		}
	}

	return commands, app_config, nil
}

// ------------------------------------------------------------------
func main() {
	commands, app_config, err := getConfig()
	if err != nil {
		log.Fatal(err)
	}

	bot, err := tgbotapi.NewBotAPI(app_config.token)
	if err != nil {
		log.Fatal(err)
	}

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

	var ucfg tgbotapi.UpdateConfig = tgbotapi.NewUpdate(0)
	ucfg.Timeout = app_config.botTimeout
	err = bot.UpdatesChan(ucfg)
	if err != nil {
		log.Fatal(err)
	}

	go_exit := false
	users := NewUsers(app_config)

LOOP:
	for {
		select {
		case telegram_update := <-bot.Updates:

			chat_id := telegram_update.Message.Chat.ID

			parts := regexp.MustCompile(`\s+`).Split(telegram_update.Message.Text, 2)
			replay_msg := ""

			if len(parts) > 0 && len(parts[0]) > 0 && parts[0][0] == '/' {

				user_from := telegram_update.Message.From

				users.AddNew(user_from, telegram_update.Message.Chat)
				allowExec := users.IsAuthorized(user_from)

				if parts[0] == "/auth" {

					if len(parts) == 1 || parts[1] == "" {

						replay_msg = "See code in terminal with shell2telegram or ack code from root user and type:\n/auth code"
						users.DoLogin(user_from.ID)

						secretCodeMsg := fmt.Sprintf("Request access for %s. Code: %s\n", users.String(user_from.ID), users.list[user_from.ID].AuthCode)
						fmt.Print(secretCodeMsg)
						users.broadcastForRoots(bot, secretCodeMsg)

					} else if len(parts) > 1 {
						if users.IsValidCode(user_from.ID, parts[1]) {
							replay_msg = fmt.Sprintf("You (%s) authorized.", users.String(user_from.ID))
							users.list[user_from.ID].IsAuthorized = true
						} else {
							replay_msg = fmt.Sprintf("Code is not valid.")
						}
					}

				} else if parts[0] == "/help" {

					if allowExec {
						for cmd, shell_cmd := range commands {
							replay_msg += fmt.Sprintf("%s - %s\n", cmd, shell_cmd)
						}
						if app_config.addExit {
							replay_msg += fmt.Sprintf("%s - %s\n", "/exit", "terminate bot")
						}
					}
					replay_msg += fmt.Sprintf("%s - %s\n", "/auth [code]", "authorize user")

				} else if allowExec && app_config.addExit && parts[0] == "/exit" {
					replay_msg = "bye..."
					go_exit = true
				} else if cmd, found := commands[parts[0]]; allowExec && found {

					shell, params := "sh", []string{"-c", cmd}
					if len(parts) > 1 {
						params = append(params, parts[1])
					}

					os_exec_command := exec.Command(shell, params...)
					os_exec_command.Stderr = os.Stderr
					shell_out, err := os_exec_command.Output()
					if err != nil {
						log.Println("exec error: ", err)
						replay_msg = fmt.Sprintf("exec error: %s", err)
					} else {
						replay_msg = string(shell_out)
					}
				}

				if replay_msg != "" {
					_, err := bot.SendMessage(tgbotapi.NewMessage(chat_id, replay_msg))
					if err != nil {
						log.Print("Bot send message error:", err)
					}
					if go_exit {
						break LOOP
					}
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package docker

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"testing"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/pipeline"
	"github.com/stretchr/testify/assert"
	"syscall"
)

func killAndRm(t *testing.T) {
	t.Log("killing registry")
	_ = exec.Command("docker", "kill", "registry").Run()
	_ = exec.Command("docker", "rm", "registry").Run()
}

func TestRunPipe(t *testing.T) {
	folder, err := ioutil.TempDir("", "archivetest")
	assert.NoError(t, err)
	var dist = filepath.Join(folder, "dist")
	assert.NoError(t, os.Mkdir(dist, 0755))
	assert.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
	var binPath = filepath.Join(dist, "mybin", "mybin")
	_, err = os.Create(binPath)
	assert.NoError(t, err)

	var table = map[string]struct {
		docker config.Docker
		err    string
	}{
		"valid": {
			docker: config.Docker{
				Image:       "localhost:5000/goreleaser/test_run_pipe",
				Goos:        "linux",
				Goarch:      "amd64",
				Dockerfile:  "testdata/Dockerfile",
				Binary:      "mybin",
				Latest:      true,
				TagTemplate: "{{.Tag}}-{{.Env.FOO}}",
			},
			err: "",
		},
		"invalid": {
			docker: config.Docker{
				Image:       "localhost:5000/goreleaser/test_run_pipe_nope",
				Goos:        "linux",
				Goarch:      "amd64",
				Dockerfile:  "testdata/Dockerfile",
				Binary:      "otherbin",
				TagTemplate: "{{.Version}}",
			},
			err: "",
		},
		"template_error": {
			docker: config.Docker{
				Image:       "localhost:5000/goreleaser/test_run_pipe_template_error",
				Goos:        "linux",
				Goarch:      "amd64",
				Dockerfile:  "testdata/Dockerfile",
				Binary:      "mybin",
				Latest:      true,
				TagTemplate: "{{.Tag}",
			},
			err: `template: tag:1: unexpected "}" in operand`,
		},
	}
	var images = []string{
		"localhost:5000/goreleaser/test_run_pipe:v1.0.0-123",
		"localhost:5000/goreleaser/test_run_pipe:latest",
	}
	// this might fail as the image doesnt exist yet, so lets ignore the error
	for _, img := range images {
		_ = exec.Command("docker", "rmi", img).Run()
	}

	killAndRm(t)
	if err := exec.Command(
		"docker", "run", "-d", "-p", "5000:5000", "--name", "registry", "registry:2",
	).Run(); err != nil {
		t.Log("failed to start docker registry", err)
		t.FailNow()
	}
	defer killAndRm(t)

	for name, docker := range table {
		t.Run(name, func(tt *testing.T) {
			var ctx = &context.Context{
				Version:   "1.0.0",
				Publish:   true,
				Artifacts: artifact.New(),
				Git: context.GitInfo{
					CurrentTag: "v1.0.0",
				},
				Config: config.Project{
					ProjectName: "mybin",
					Dist:        dist,
					Dockers: []config.Docker{
						docker.docker,
					},
				},
				Env: map[string]string{"FOO": "123"},
			}
			for _, os := range []string{"linux", "darwin"} {
				for _, arch := range []string{"amd64", "386"} {
					ctx.Artifacts.Add(artifact.Artifact{
						Name:   "mybin",
						Path:   binPath,
						Goarch: arch,
						Goos:   os,
						Type:   artifact.Binary,
						Extra: map[string]string{
							"Binary": "mybin",
						},
					})
				}
			}
			if docker.err == "" {
				assert.NoError(tt, Pipe{}.Run(ctx))
			} else {
				assert.EqualError(tt, Pipe{}.Run(ctx), docker.err)
			}
		})
	}

	// this might should not fail as the image should have been created when
	// the step ran
	for _, img := range images {
		assert.NoError(t, exec.Command("docker", "rmi", img).Run())
	}
	// the test_run_pipe_nope image should not have been created, so deleting
	// it should fail
	assert.Error(t,
		exec.Command(
			"docker", "rmi", "localhost:5000/goreleaser/test_run_pipe_nope:1.0.0",
		).Run(),
	)
}

func TestDescription(t *testing.T) {
	assert.NotEmpty(t, Pipe{}.String())
}

func TestNoDockers(t *testing.T) {
	assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{}))))
}

func TestNoDockerWithoutImageName(t *testing.T) {
	assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{
		Dockers: []config.Docker{
			{
				Goos: "linux",
			},
		},
	}))))
}

func TestDockerNotInPath(t *testing.T) {
	var path = os.Getenv("PATH")
	defer func() {
		assert.NoError(t, os.Setenv("PATH", path))
	}()
	assert.NoError(t, os.Setenv("PATH", ""))
	var ctx = &context.Context{
		Version: "1.0.0",
		Config: config.Project{
			Dockers: []config.Docker{
				{
					Image: "a/b",
				},
			},
		},
	}
	assert.EqualError(t, Pipe{}.Run(ctx), ErrNoDocker.Error())
}

func TestDefault(t *testing.T) {
	var ctx = &context.Context{
		Config: config.Project{
			Builds: []config.Build{
				{
					Binary: "foo",
				},
			},
			Dockers: []config.Docker{
				{
					Latest: true,
				},
			},
		},
	}
	assert.NoError(t, Pipe{}.Default(ctx))
	assert.Len(t, ctx.Config.Dockers, 1)
	var docker = ctx.Config.Dockers[0]
	assert.Equal(t, "linux", docker.Goos)
	assert.Equal(t, "amd64", docker.Goarch)
	assert.Equal(t, ctx.Config.Builds[0].Binary, docker.Binary)
	assert.Equal(t, "Dockerfile", docker.Dockerfile)
	assert.Equal(t, "{{ .Version }}", docker.TagTemplate)
}

func TestDefaultNoDockers(t *testing.T) {
	var ctx = &context.Context{
		Config: config.Project{
			Dockers: []config.Docker{},
		},
	}
	assert.NoError(t, Pipe{}.Default(ctx))
	assert.Empty(t, ctx.Config.Dockers)
}

func TestDefaultSet(t *testing.T) {
	var ctx = &context.Context{
		Config: config.Project{
			Dockers: []config.Docker{
				{
					Goos:       "windows",
					Goarch:     "i386",
					Binary:     "bar",
					Dockerfile: "Dockerfile.foo",
				},
			},
		},
	}
	assert.NoError(t, Pipe{}.Default(ctx))
	assert.Len(t, ctx.Config.Dockers, 1)
	var docker = ctx.Config.Dockers[0]
	assert.Equal(t, "windows", docker.Goos)
	assert.Equal(t, "i386", docker.Goarch)
	assert.Equal(t, "bar", docker.Binary)
	assert.Equal(t, "{{ .Version }}", docker.TagTemplate)
	assert.Equal(t, "Dockerfile.foo", docker.Dockerfile)
}

func TestLinkFile(t *testing.T) {
	const srcFile = "/tmp/test"
	const dstFile = "/tmp/linked"
	err := ioutil.WriteFile(srcFile, []byte("foo"), 0644)
	if err != nil {
		t.Log("Cannot setup test file")
		t.Fail()
	}
	err = link(srcFile, dstFile)
	if err != nil {
		t.Log("Failed to link: ", err)
		t.Fail()
	}
	if inode(srcFile) != inode(dstFile) {
		t.Log("Inodes do not match, destination file is not a link")
		t.Fail()
	}
	// cleanup
	os.Remove(srcFile)
	os.Remove(dstFile)
}

func TestLinkDirectory(t *testing.T) {
	const srcDir = "/tmp/testdir"
	const testFile = "test"
	const dstDir = "/tmp/linkedDir"

	os.Mkdir(srcDir, 0755)
	err := ioutil.WriteFile(srcDir+"/"+testFile, []byte("foo"), 0644)
	if err != nil {
		t.Log("Cannot setup test file")
		t.Fail()
	}
	err = directoryLink(srcDir, dstDir, nil)
	if err != nil {
		t.Log("Failed to link: ", err)
		t.Fail()
	}
	if inode(srcDir+"/"+testFile) != inode(dstDir+"/"+testFile) {
		t.Log("Inodes do not match, destination file is not a link")
		t.Fail()
	}

	// cleanup
	os.RemoveAll(srcDir)
	os.RemoveAll(dstDir)
}

func inode(file string) uint64 {
	fileInfo, err := os.Stat(file)
	if err != nil {
		return 0
	}
	stat := fileInfo.Sys().(*syscall.Stat_t)
	return stat.Ino
}
<commit_msg>added one more test to cover 2-level directory linking<commit_after>package docker

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"testing"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/pipeline"
	"github.com/stretchr/testify/assert"
	"syscall"
)

func killAndRm(t *testing.T) {
	t.Log("killing registry")
	_ = exec.Command("docker", "kill", "registry").Run()
	_ = exec.Command("docker", "rm", "registry").Run()
}

func TestRunPipe(t *testing.T) {
	folder, err := ioutil.TempDir("", "archivetest")
	assert.NoError(t, err)
	var dist = filepath.Join(folder, "dist")
	assert.NoError(t, os.Mkdir(dist, 0755))
	assert.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
	var binPath = filepath.Join(dist, "mybin", "mybin")
	_, err = os.Create(binPath)
	assert.NoError(t, err)

	var table = map[string]struct {
		docker config.Docker
		err    string
	}{
		"valid": {
			docker: config.Docker{
				Image:       "localhost:5000/goreleaser/test_run_pipe",
				Goos:        "linux",
				Goarch:      "amd64",
				Dockerfile:  "testdata/Dockerfile",
				Binary:      "mybin",
				Latest:      true,
				TagTemplate: "{{.Tag}}-{{.Env.FOO}}",
			},
			err: "",
		},
		"invalid": {
			docker: config.Docker{
				Image:       "localhost:5000/goreleaser/test_run_pipe_nope",
				Goos:        "linux",
				Goarch:      "amd64",
				Dockerfile:  "testdata/Dockerfile",
				Binary:      "otherbin",
				TagTemplate: "{{.Version}}",
			},
			err: "",
		},
		"template_error": {
			docker: config.Docker{
				Image:       "localhost:5000/goreleaser/test_run_pipe_template_error",
				Goos:        "linux",
				Goarch:      "amd64",
				Dockerfile:  "testdata/Dockerfile",
				Binary:      "mybin",
				Latest:      true,
				TagTemplate: "{{.Tag}",
			},
			err: `template: tag:1: unexpected "}" in operand`,
		},
	}
	var images = []string{
		"localhost:5000/goreleaser/test_run_pipe:v1.0.0-123",
		"localhost:5000/goreleaser/test_run_pipe:latest",
	}
	// this might fail as the image doesnt exist yet, so lets ignore the error
	for _, img := range images {
		_ = exec.Command("docker", "rmi", img).Run()
	}

	killAndRm(t)
	if err := exec.Command(
		"docker", "run", "-d", "-p", "5000:5000", "--name", "registry", "registry:2",
	).Run(); err != nil {
		t.Log("failed to start docker registry", err)
		t.FailNow()
	}
	defer killAndRm(t)

	for name, docker := range table {
		t.Run(name, func(tt *testing.T) {
			var ctx = &context.Context{
				Version:   "1.0.0",
				Publish:   true,
				Artifacts: artifact.New(),
				Git: context.GitInfo{
					CurrentTag: "v1.0.0",
				},
				Config: config.Project{
					ProjectName: "mybin",
					Dist:        dist,
					Dockers: []config.Docker{
						docker.docker,
					},
				},
				Env: map[string]string{"FOO": "123"},
			}
			for _, os := range []string{"linux", "darwin"} {
				for _, arch := range []string{"amd64", "386"} {
					ctx.Artifacts.Add(artifact.Artifact{
						Name:   "mybin",
						Path:   binPath,
						Goarch: arch,
						Goos:   os,
						Type:   artifact.Binary,
						Extra: map[string]string{
							"Binary": "mybin",
						},
					})
				}
			}
			if docker.err == "" {
				assert.NoError(tt, Pipe{}.Run(ctx))
			} else {
				assert.EqualError(tt, Pipe{}.Run(ctx), docker.err)
			}
		})
	}

	// this might should not fail as the image should have been created when
	// the step ran
	for _, img := range images {
		assert.NoError(t, exec.Command("docker", "rmi", img).Run())
	}
	// the test_run_pipe_nope image should not have been created, so deleting
	// it should fail
	assert.Error(t,
		exec.Command(
			"docker", "rmi", "localhost:5000/goreleaser/test_run_pipe_nope:1.0.0",
		).Run(),
	)
}

func TestDescription(t *testing.T) {
	assert.NotEmpty(t, Pipe{}.String())
}

func TestNoDockers(t *testing.T) {
	assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{}))))
}

func TestNoDockerWithoutImageName(t *testing.T) {
	assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{
		Dockers: []config.Docker{
			{
				Goos: "linux",
			},
		},
	}))))
}

func TestDockerNotInPath(t *testing.T) {
	var path = os.Getenv("PATH")
	defer func() {
		assert.NoError(t, os.Setenv("PATH", path))
	}()
	assert.NoError(t, os.Setenv("PATH", ""))
	var ctx = &context.Context{
		Version: "1.0.0",
		Config: config.Project{
			Dockers: []config.Docker{
				{
					Image: "a/b",
				},
			},
		},
	}
	assert.EqualError(t, Pipe{}.Run(ctx), ErrNoDocker.Error())
}

func TestDefault(t *testing.T) {
	var ctx = &context.Context{
		Config: config.Project{
			Builds: []config.Build{
				{
					Binary: "foo",
				},
			},
			Dockers: []config.Docker{
				{
					Latest: true,
				},
			},
		},
	}
	assert.NoError(t, Pipe{}.Default(ctx))
	assert.Len(t, ctx.Config.Dockers, 1)
	var docker = ctx.Config.Dockers[0]
	assert.Equal(t, "linux", docker.Goos)
	assert.Equal(t, "amd64", docker.Goarch)
	assert.Equal(t, ctx.Config.Builds[0].Binary, docker.Binary)
	assert.Equal(t, "Dockerfile", docker.Dockerfile)
	assert.Equal(t, "{{ .Version }}", docker.TagTemplate)
}

func TestDefaultNoDockers(t *testing.T) {
	var ctx = &context.Context{
		Config: config.Project{
			Dockers: []config.Docker{},
		},
	}
	assert.NoError(t, Pipe{}.Default(ctx))
	assert.Empty(t, ctx.Config.Dockers)
}

func TestDefaultSet(t *testing.T) {
	var ctx = &context.Context{
		Config: config.Project{
			Dockers: []config.Docker{
				{
					Goos:       "windows",
					Goarch:     "i386",
					Binary:     "bar",
					Dockerfile: "Dockerfile.foo",
				},
			},
		},
	}
	assert.NoError(t, Pipe{}.Default(ctx))
	assert.Len(t, ctx.Config.Dockers, 1)
	var docker = ctx.Config.Dockers[0]
	assert.Equal(t, "windows", docker.Goos)
	assert.Equal(t, "i386", docker.Goarch)
	assert.Equal(t, "bar", docker.Binary)
	assert.Equal(t, "{{ .Version }}", docker.TagTemplate)
	assert.Equal(t, "Dockerfile.foo", docker.Dockerfile)
}

func TestLinkFile(t *testing.T) {
	const srcFile = "/tmp/test"
	const dstFile = "/tmp/linked"
	err := ioutil.WriteFile(srcFile, []byte("foo"), 0644)
	if err != nil {
		t.Log("Cannot setup test file")
		t.Fail()
	}
	err = link(srcFile, dstFile)
	if err != nil {
		t.Log("Failed to link: ", err)
		t.Fail()
	}
	if inode(srcFile) != inode(dstFile) {
		t.Log("Inodes do not match, destination file is not a link")
		t.Fail()
	}
	// cleanup
	os.Remove(srcFile)
	os.Remove(dstFile)
}

func TestLinkDirectory(t *testing.T) {
	const srcDir = "/tmp/testdir"
	const testFile = "test"
	const dstDir = "/tmp/linkedDir"

	os.Mkdir(srcDir, 0755)
	err := ioutil.WriteFile(srcDir+"/"+testFile, []byte("foo"), 0644)
	if err != nil {
		t.Log("Cannot setup test file")
		t.Fail()
	}
	err = directoryLink(srcDir, dstDir, nil)
	if err != nil {
		t.Log("Failed to link: ", err)
		t.Fail()
	}
	if inode(srcDir+"/"+testFile) != inode(dstDir+"/"+testFile) {
		t.Log("Inodes do not match, destination file is not a link")
		t.Fail()
	}

	// cleanup
	os.RemoveAll(srcDir)
	os.RemoveAll(dstDir)
}

func TestLinkTwoLevelDirectory(t *testing.T) {
	const srcDir = "/tmp/testdir"
	const srcLevel2 = srcDir+"/level2"
	const testFile = "test"
	const dstDir = "/tmp/linkedDir"

	os.Mkdir(srcDir, 0755)
	os.Mkdir(srcLevel2, 0755)
	err := ioutil.WriteFile(srcDir+"/"+testFile, []byte("foo"), 0644)
	if err != nil {
		t.Log("Cannot setup test file")
		t.Fail()
	}
	err = ioutil.WriteFile(srcLevel2+"/"+testFile, []byte("foo"), 0644)
	if err != nil {
		t.Log("Cannot setup test file")
		t.Fail()
	}
	err = directoryLink(srcDir, dstDir, nil)
	if err != nil {
		t.Log("Failed to link: ", err)
		t.Fail()
	}
	if inode(srcDir+"/"+testFile) != inode(dstDir+"/"+testFile) {
		t.Log("Inodes do not match")
		t.Fail()
	}
	if inode(srcLevel2+"/"+testFile) != inode(dstDir+"/level2/"+testFile) {
		t.Log("Inodes do not match")
		t.Fail()
	}
	// cleanup
	os.RemoveAll(srcDir)
	os.RemoveAll(dstDir)
}

func inode(file string) uint64 {
	fileInfo, err := os.Stat(file)
	if err != nil {
		return 0
	}
	stat := fileInfo.Sys().(*syscall.Stat_t)
	return stat.Ino
}
<|endoftext|>


<commit_before>// +build linux

/*
   Copyright The containerd Authors.

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

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

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

package apparmor

import (
	"io/ioutil"
	"os"
	"sync"
)

var (
	appArmorSupported bool
	checkAppArmor     sync.Once
)

// hostSupports returns true if apparmor is enabled for the host, if
// apparmor_parser is enabled, and if we are not running docker-in-docker.
//
// It is a modified version of libcontainer/apparmor.IsEnabled(), which does not
// check for apparmor_parser to be present, or if we're running docker-in-docker.
func hostSupports() bool {
	checkAppArmor.Do(func() {
		// see https://github.com/docker/docker/commit/de191e86321f7d3136ff42ff75826b8107399497
		if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" {
			buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
			appArmorSupported = err == nil && len(buf) > 1 && buf[0] == 'Y'
		}
	})
	return appArmorSupported
}
<commit_msg>update the link<commit_after>// +build linux

/*
   Copyright The containerd Authors.

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

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

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

package apparmor

import (
	"io/ioutil"
	"os"
	"sync"
)

var (
	appArmorSupported bool
	checkAppArmor     sync.Once
)

// hostSupports returns true if apparmor is enabled for the host, if
// apparmor_parser is enabled, and if we are not running docker-in-docker.
//
// It is a modified version of libcontainer/apparmor.IsEnabled(), which does not
// check for apparmor_parser to be present, or if we're running docker-in-docker.
func hostSupports() bool {
	checkAppArmor.Do(func() {
		// see https://github.com/opencontainers/runc/blob/0d49470392206f40eaab3b2190a57fe7bb3df458/libcontainer/apparmor/apparmor_linux.go
		if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" {
			buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
			appArmorSupported = err == nil && len(buf) > 1 && buf[0] == 'Y'
		}
	})
	return appArmorSupported
}
<|endoftext|>


<commit_before>package sso

import "strings"

// Scope parameter allows the application to express the desired scope of the access request.
type Scope []string

// Options parameter allows additional options for getting auth url
type Options map[string]interface{}

// UXMode indicates how the URL is used
type UXMode int

const (
	// Undefined for undefined uxmode
	Undefined UXMode = iota
	// WebRedirect for web url redirect
	WebRedirect
	// WebPopup for web popup window
	WebPopup
	// IOS for device iOS
	IOS
	// Android for device Android
	Android
)

func (m UXMode) String() string {
	names := [...]string{
		"undefined",
		"web_redirect",
		"web_popup",
		"ios",
		"android",
	}

	if m < Undefined || m > Android {
		return "undefined"
	}

	return names[m]
}

// GetURLParams structs parameters for GetLoginAuthURL
type GetURLParams struct {
	Scope       Scope
	Options     Options
	CallbackURL string
	UXMode      UXMode
	UserID      string
	Action      string
}

// Config is the base config of a SSO provider
type Config struct {
	Name         string
	Enabled      bool
	ClientID     string
	ClientSecret string
	Scope        Scope
}

// Provider defines SSO interface
type Provider interface {
	GetAuthURL(params GetURLParams) (url string, err error)
}

// NewProvider is the provider factory
func NewProvider(
	name string,
	enabled bool,
	clientID string,
	clientSecret string,
	scopeStr string,
) Provider {
	config := Config{
		Name:         name,
		Enabled:      enabled,
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Scope:        strings.Split(scopeStr, ","),
	}
	switch name {
	case "google":
		return &GoogleImpl{
			Config: config,
		}
	case "facebook":
		return &FacebookImpl{
			Config: config,
		}
	case "instagram":
		return &InstagramImpl{
			Config: config,
		}
	case "linkedin":
		return &LinkedInImpl{
			Config: config,
		}
	}
	return nil
}
<commit_msg>Should only return enabled provider<commit_after>package sso

import "strings"

// Scope parameter allows the application to express the desired scope of the access request.
type Scope []string

// Options parameter allows additional options for getting auth url
type Options map[string]interface{}

// UXMode indicates how the URL is used
type UXMode int

const (
	// Undefined for undefined uxmode
	Undefined UXMode = iota
	// WebRedirect for web url redirect
	WebRedirect
	// WebPopup for web popup window
	WebPopup
	// IOS for device iOS
	IOS
	// Android for device Android
	Android
)

func (m UXMode) String() string {
	names := [...]string{
		"undefined",
		"web_redirect",
		"web_popup",
		"ios",
		"android",
	}

	if m < Undefined || m > Android {
		return "undefined"
	}

	return names[m]
}

// GetURLParams structs parameters for GetLoginAuthURL
type GetURLParams struct {
	Scope       Scope
	Options     Options
	CallbackURL string
	UXMode      UXMode
	UserID      string
	Action      string
}

// Config is the base config of a SSO provider
type Config struct {
	Name         string
	Enabled      bool
	ClientID     string
	ClientSecret string
	Scope        Scope
}

// Provider defines SSO interface
type Provider interface {
	GetAuthURL(params GetURLParams) (url string, err error)
}

// NewProvider is the provider factory
func NewProvider(
	name string,
	enabled bool,
	clientID string,
	clientSecret string,
	scopeStr string,
) Provider {
	if !enabled {
		return nil
	}
	config := Config{
		Name:         name,
		Enabled:      enabled,
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Scope:        strings.Split(scopeStr, ","),
	}
	switch name {
	case "google":
		return &GoogleImpl{
			Config: config,
		}
	case "facebook":
		return &FacebookImpl{
			Config: config,
		}
	case "instagram":
		return &InstagramImpl{
			Config: config,
		}
	case "linkedin":
		return &LinkedInImpl{
			Config: config,
		}
	}
	return nil
}
<|endoftext|>