<commit_before>//go:build !nautilus && !octopus
// +build !nautilus,!octopus

package admin

import (
	"errors"
	"os"
	pth "path"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/ceph/go-ceph/cephfs"
	"github.com/ceph/go-ceph/common/admin/manager"
)

func mirrorConfig() string {
	return os.Getenv("MIRROR_CONF")
}

const (
	noForce      = false
	mirrorClient = "client.mirror_remote"
)

func waitForMirroring(t *testing.T, fsa *FSAdmin) {
	mgradmin := manager.NewFromConn(fsa.conn)
	for i := 0; i < 20; i++ {
		modinfo, err := mgradmin.ListModules()
		require.NoError(t, err)
		for _, emod := range modinfo.EnabledModules {
			if emod == "mirroring" {
				return
			}
		}
		time.Sleep(100 * time.Millisecond)
	}
	t.Fatalf("timed out waiting for mirroring module")
}

func TestMirroring(t *testing.T) {
	if mirrorConfig() == "" {
		t.Skip("no mirror config available")
	}

	fsa1 := getFSAdmin(t)
	fsname := "cephfs"

	require.NotNil(t, fsa1.conn)
	err := fsa1.EnableMirroringModule(noForce)
	assert.NoError(t, err)
	defer func() {
		err := fsa1.DisableMirroringModule()
		assert.NoError(t, err)
	}()
	require.NoError(t, err)
	waitForMirroring(t, fsa1)

	smadmin1 := fsa1.SnapshotMirror()
	err = smadmin1.Enable(fsname)
	require.NoError(t, err)
	defer func() {
		err := smadmin1.Disable(fsname)
		require.NoError(t, err)
	}()

	fsa2 := newFSAdmin(t, mirrorConfig())
	err = fsa2.EnableMirroringModule(noForce)
	require.NoError(t, err)
	defer func() {
		err := fsa2.DisableMirroringModule()
		assert.NoError(t, err)
	}()
	waitForMirroring(t, fsa2)

	smadmin2 := fsa2.SnapshotMirror()
	err = smadmin2.Enable(fsname)
	require.NoError(t, err)
	defer func() {
		err := smadmin2.Disable(fsname)
		require.NoError(t, err)
	}()

	// from https://docs.ceph.com/en/pacific/dev/cephfs-mirroring/
	//  "Peer bootstrap involves creating a bootstrap token on the peer cluster"
	// and "Import the bootstrap token in the primary cluster"
	token, err := smadmin2.CreatePeerBootstrapToken(fsname, mirrorClient, "ceph_b")
	require.NoError(t, err)
	err = smadmin1.ImportPeerBoostrapToken(fsname, token)
	require.NoError(t, err)

	// we need a path to mirror
	path := "/wonderland"

	mount1 := fsConnect(t, "")
	defer func(mount *cephfs.MountInfo) {
		assert.NoError(t, mount.Unmount())
		assert.NoError(t, mount.Release())
	}(mount1)

	mount2 := fsConnect(t, mirrorConfig())
	defer func(mount *cephfs.MountInfo) {
		assert.NoError(t, mount.Unmount())
		assert.NoError(t, mount.Release())
	}(mount2)

	err = mount1.MakeDir(path, 0770)
	require.NoError(t, err)
	defer func() {
		err = mount2.ChangeDir("/")
		assert.NoError(t, err)
		err = mount1.RemoveDir(path)
		assert.NoError(t, err)
	}()
	err = mount2.MakeDir(path, 0770)
	require.NoError(t, err)
	defer func() {
		err = mount2.ChangeDir("/")
		assert.NoError(t, err)
		err = mount2.RemoveDir(path)
		assert.NoError(t, err)
	}()

	err = smadmin1.Add(fsname, path)
	require.NoError(t, err)

	err = mount1.ChangeDir(path)
	require.NoError(t, err)

	// write some dirs & files
	err = mount1.MakeDir("drink_me", 0770)
	require.NoError(t, err)
	err = mount1.MakeDir("eat_me", 0770)
	require.NoError(t, err)
	writeFile(t, mount1, "drink_me/bottle1.txt",
		[]byte("magic potions #1\n"))

	snapname1 := "alice"
	err = mount1.MakeDir(pth.Join(snapDir, snapname1), 0700)
	require.NoError(t, err)
	defer func() {
		err := mount1.RemoveDir(pth.Join(snapDir, snapname1))
		assert.NoError(t, err)
		err = mount2.RemoveDir(pth.Join(snapDir, snapname1))
		assert.NoError(t, err)
	}()

	err = mount2.ChangeDir(path)
	require.NoError(t, err)

	// wait a bit for the snapshot to propagate and the dirs to be created on
	// the remote fs.
	for i := 0; i < 60; i++ {
		time.Sleep(500 * time.Millisecond)
		_, err1 := mount2.Statx("drink_me", cephfs.StatxBasicStats, 0)
		_, err2 := mount2.Statx("eat_me", cephfs.StatxBasicStats, 0)
		if err1 == nil && err2 == nil {
			break
		}
	}

waitforpeers:
	for i := 0; i < 60; i++ {
		time.Sleep(500 * time.Millisecond)
		dstatus, err := smadmin1.DaemonStatus(fsname)
		assert.NoError(t, err)
		for _, dsinfo := range dstatus {
			for _, fsinfo := range dsinfo.FileSystems {
				if len(fsinfo.Peers) > 0 {
					break waitforpeers
				}
			}
		}
	}

	p, err := smadmin1.PeerList(fsname)
	assert.NoError(t, err)
	assert.Len(t, p, 1)
	for _, peer := range p {
		assert.Equal(t, "cephfs", peer.FSName)
	}

	stx, err := mount2.Statx("drink_me", cephfs.StatxBasicStats, 0)
	if assert.NoError(t, err) {
		assert.Equal(t, uint16(0040000), stx.Mode&0040000) // is dir?
	}

	stx, err = mount2.Statx("eat_me", cephfs.StatxBasicStats, 0)
	if assert.NoError(t, err) {
		assert.Equal(t, uint16(0040000), stx.Mode&0040000) // is dir?
	}

	stx, err = mount2.Statx("drink_me/bottle1.txt", cephfs.StatxBasicStats, 0)
	if assert.NoError(t, err) {
		assert.Equal(t, uint16(0100000), stx.Mode&0100000) // is reg?
		assert.Equal(t, uint64(17), stx.Size)
	}
	data := readFile(t, mount2, "drink_me/bottle1.txt")
	assert.Equal(t, "magic potions #1\n", string(data))

	err = mount1.Unlink("drink_me/bottle1.txt")
	require.NoError(t, err)
	err = mount1.RemoveDir("drink_me")
	require.NoError(t, err)
	err = mount1.RemoveDir("eat_me")
	require.NoError(t, err)

	snapname2 := "rabbit"
	err = mount1.MakeDir(pth.Join(snapDir, snapname2), 0700)
	require.NoError(t, err)
	defer func() {
		err := mount1.RemoveDir(pth.Join(snapDir, snapname2))
		assert.NoError(t, err)
		err = mount2.RemoveDir(pth.Join(snapDir, snapname2))
		assert.NoError(t, err)
	}()

	// wait a bit for the snapshot to propagate and the dirs to be removed on
	// the remote fs.
	for i := 0; i < 60; i++ {
		time.Sleep(500 * time.Millisecond)
		_, err1 := mount2.Statx("drink_me", cephfs.StatxBasicStats, 0)
		_, err2 := mount2.Statx("eat_me", cephfs.StatxBasicStats, 0)
		if err1 != nil && err2 != nil {
			break
		}

	}
	_, err = mount2.Statx("drink_me", cephfs.StatxBasicStats, 0)
	if assert.Error(t, err) {
		var ec errorWithCode
		if assert.True(t, errors.As(err, &ec)) {
			assert.Equal(t, -2, ec.ErrorCode())
		}
	}
	_, err = mount2.Statx("eat_me", cephfs.StatxBasicStats, 0)
	if assert.Error(t, err) {
		var ec errorWithCode
		if assert.True(t, errors.As(err, &ec)) {
			assert.Equal(t, -2, ec.ErrorCode())
		}
	}

	err = smadmin1.Remove(fsname, path)
	assert.NoError(t, err)
}

type errorWithCode interface {
	ErrorCode() int
}
<commit_msg>cephfs admin: increase timeout waiting for mirroring module<commit_after>//go:build !nautilus && !octopus
// +build !nautilus,!octopus

package admin

import (
	"errors"
	"os"
	pth "path"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/ceph/go-ceph/cephfs"
	"github.com/ceph/go-ceph/common/admin/manager"
)

func mirrorConfig() string {
	return os.Getenv("MIRROR_CONF")
}

const (
	noForce      = false
	mirrorClient = "client.mirror_remote"
)

func waitForMirroring(t *testing.T, fsa *FSAdmin) {
	mgradmin := manager.NewFromConn(fsa.conn)
	for i := 0; i < 30; i++ {
		modinfo, err := mgradmin.ListModules()
		require.NoError(t, err)
		for _, emod := range modinfo.EnabledModules {
			if emod == "mirroring" {
				return
			}
		}
		time.Sleep(100 * time.Millisecond)
	}
	t.Fatalf("timed out waiting for mirroring module")
}

func TestMirroring(t *testing.T) {
	if mirrorConfig() == "" {
		t.Skip("no mirror config available")
	}

	fsa1 := getFSAdmin(t)
	fsname := "cephfs"

	require.NotNil(t, fsa1.conn)
	err := fsa1.EnableMirroringModule(noForce)
	assert.NoError(t, err)
	defer func() {
		err := fsa1.DisableMirroringModule()
		assert.NoError(t, err)
	}()
	require.NoError(t, err)
	waitForMirroring(t, fsa1)

	smadmin1 := fsa1.SnapshotMirror()
	err = smadmin1.Enable(fsname)
	require.NoError(t, err)
	defer func() {
		err := smadmin1.Disable(fsname)
		require.NoError(t, err)
	}()

	fsa2 := newFSAdmin(t, mirrorConfig())
	err = fsa2.EnableMirroringModule(noForce)
	require.NoError(t, err)
	defer func() {
		err := fsa2.DisableMirroringModule()
		assert.NoError(t, err)
	}()
	waitForMirroring(t, fsa2)

	smadmin2 := fsa2.SnapshotMirror()
	err = smadmin2.Enable(fsname)
	require.NoError(t, err)
	defer func() {
		err := smadmin2.Disable(fsname)
		require.NoError(t, err)
	}()

	// from https://docs.ceph.com/en/pacific/dev/cephfs-mirroring/
	//  "Peer bootstrap involves creating a bootstrap token on the peer cluster"
	// and "Import the bootstrap token in the primary cluster"
	token, err := smadmin2.CreatePeerBootstrapToken(fsname, mirrorClient, "ceph_b")
	require.NoError(t, err)
	err = smadmin1.ImportPeerBoostrapToken(fsname, token)
	require.NoError(t, err)

	// we need a path to mirror
	path := "/wonderland"

	mount1 := fsConnect(t, "")
	defer func(mount *cephfs.MountInfo) {
		assert.NoError(t, mount.Unmount())
		assert.NoError(t, mount.Release())
	}(mount1)

	mount2 := fsConnect(t, mirrorConfig())
	defer func(mount *cephfs.MountInfo) {
		assert.NoError(t, mount.Unmount())
		assert.NoError(t, mount.Release())
	}(mount2)

	err = mount1.MakeDir(path, 0770)
	require.NoError(t, err)
	defer func() {
		err = mount2.ChangeDir("/")
		assert.NoError(t, err)
		err = mount1.RemoveDir(path)
		assert.NoError(t, err)
	}()
	err = mount2.MakeDir(path, 0770)
	require.NoError(t, err)
	defer func() {
		err = mount2.ChangeDir("/")
		assert.NoError(t, err)
		err = mount2.RemoveDir(path)
		assert.NoError(t, err)
	}()

	err = smadmin1.Add(fsname, path)
	require.NoError(t, err)

	err = mount1.ChangeDir(path)
	require.NoError(t, err)

	// write some dirs & files
	err = mount1.MakeDir("drink_me", 0770)
	require.NoError(t, err)
	err = mount1.MakeDir("eat_me", 0770)
	require.NoError(t, err)
	writeFile(t, mount1, "drink_me/bottle1.txt",
		[]byte("magic potions #1\n"))

	snapname1 := "alice"
	err = mount1.MakeDir(pth.Join(snapDir, snapname1), 0700)
	require.NoError(t, err)
	defer func() {
		err := mount1.RemoveDir(pth.Join(snapDir, snapname1))
		assert.NoError(t, err)
		err = mount2.RemoveDir(pth.Join(snapDir, snapname1))
		assert.NoError(t, err)
	}()

	err = mount2.ChangeDir(path)
	require.NoError(t, err)

	// wait a bit for the snapshot to propagate and the dirs to be created on
	// the remote fs.
	for i := 0; i < 60; i++ {
		time.Sleep(500 * time.Millisecond)
		_, err1 := mount2.Statx("drink_me", cephfs.StatxBasicStats, 0)
		_, err2 := mount2.Statx("eat_me", cephfs.StatxBasicStats, 0)
		if err1 == nil && err2 == nil {
			break
		}
	}

waitforpeers:
	for i := 0; i < 60; i++ {
		time.Sleep(500 * time.Millisecond)
		dstatus, err := smadmin1.DaemonStatus(fsname)
		assert.NoError(t, err)
		for _, dsinfo := range dstatus {
			for _, fsinfo := range dsinfo.FileSystems {
				if len(fsinfo.Peers) > 0 {
					break waitforpeers
				}
			}
		}
	}

	p, err := smadmin1.PeerList(fsname)
	assert.NoError(t, err)
	assert.Len(t, p, 1)
	for _, peer := range p {
		assert.Equal(t, "cephfs", peer.FSName)
	}

	stx, err := mount2.Statx("drink_me", cephfs.StatxBasicStats, 0)
	if assert.NoError(t, err) {
		assert.Equal(t, uint16(0040000), stx.Mode&0040000) // is dir?
	}

	stx, err = mount2.Statx("eat_me", cephfs.StatxBasicStats, 0)
	if assert.NoError(t, err) {
		assert.Equal(t, uint16(0040000), stx.Mode&0040000) // is dir?
	}

	stx, err = mount2.Statx("drink_me/bottle1.txt", cephfs.StatxBasicStats, 0)
	if assert.NoError(t, err) {
		assert.Equal(t, uint16(0100000), stx.Mode&0100000) // is reg?
		assert.Equal(t, uint64(17), stx.Size)
	}
	data := readFile(t, mount2, "drink_me/bottle1.txt")
	assert.Equal(t, "magic potions #1\n", string(data))

	err = mount1.Unlink("drink_me/bottle1.txt")
	require.NoError(t, err)
	err = mount1.RemoveDir("drink_me")
	require.NoError(t, err)
	err = mount1.RemoveDir("eat_me")
	require.NoError(t, err)

	snapname2 := "rabbit"
	err = mount1.MakeDir(pth.Join(snapDir, snapname2), 0700)
	require.NoError(t, err)
	defer func() {
		err := mount1.RemoveDir(pth.Join(snapDir, snapname2))
		assert.NoError(t, err)
		err = mount2.RemoveDir(pth.Join(snapDir, snapname2))
		assert.NoError(t, err)
	}()

	// wait a bit for the snapshot to propagate and the dirs to be removed on
	// the remote fs.
	for i := 0; i < 60; i++ {
		time.Sleep(500 * time.Millisecond)
		_, err1 := mount2.Statx("drink_me", cephfs.StatxBasicStats, 0)
		_, err2 := mount2.Statx("eat_me", cephfs.StatxBasicStats, 0)
		if err1 != nil && err2 != nil {
			break
		}

	}
	_, err = mount2.Statx("drink_me", cephfs.StatxBasicStats, 0)
	if assert.Error(t, err) {
		var ec errorWithCode
		if assert.True(t, errors.As(err, &ec)) {
			assert.Equal(t, -2, ec.ErrorCode())
		}
	}
	_, err = mount2.Statx("eat_me", cephfs.StatxBasicStats, 0)
	if assert.Error(t, err) {
		var ec errorWithCode
		if assert.True(t, errors.As(err, &ec)) {
			assert.Equal(t, -2, ec.ErrorCode())
		}
	}

	err = smadmin1.Remove(fsname, path)
	assert.NoError(t, err)
}

type errorWithCode interface {
	ErrorCode() int
}
<|endoftext|>


<commit_before>package organization_test

import (
	"os"

	"github.com/cloudfoundry/cli/cf/commandregistry"
	"github.com/cloudfoundry/cli/cf/configuration/coreconfig"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/trace/tracefakes"
	"github.com/cloudfoundry/cli/plugin/models"
	testcmd "github.com/cloudfoundry/cli/testhelpers/commands"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testreq "github.com/cloudfoundry/cli/testhelpers/requirements"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"

	. "github.com/cloudfoundry/cli/testhelpers/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("org command", func() {
	var (
		ui                  *testterm.FakeUI
		configRepo          coreconfig.Repository
		requirementsFactory *testreq.FakeReqFactory
		deps                commandregistry.Dependency
	)

	updateCommandDependency := func(pluginCall bool) {
		deps.UI = ui
		deps.Config = configRepo
		commandregistry.Commands.SetCommand(commandregistry.Commands.FindCommand("org").SetDependency(deps, pluginCall))
	}

	BeforeEach(func() {
		ui = &testterm.FakeUI{}
		requirementsFactory = &testreq.FakeReqFactory{}
		configRepo = testconfig.NewRepositoryWithDefaults()

		deps = commandregistry.NewDependency(os.Stdout, new(tracefakes.FakePrinter))
	})

	runCommand := func(args ...string) bool {
		return testcmd.RunCLICommand("org", args, requirementsFactory, updateCommandDependency, false, ui)
	}

	Describe("requirements", func() {
		It("fails when not logged in", func() {
			Expect(runCommand("whoops")).To(BeFalse())
		})

		It("fails with usage when not provided exactly one arg", func() {
			requirementsFactory.LoginSuccess = true
			runCommand("too", "much")
			Expect(ui.Outputs).To(ContainSubstrings(
				[]string{"Incorrect Usage", "Requires an argument"},
			))
		})
	})

	Describe("execute", func() {
		Context("when logged in, and provided the name of an org", func() {
			var org *models.Organization

			BeforeEach(func() {
				developmentSpaceFields := models.SpaceFields{}
				developmentSpaceFields.Name = "development"
				developmentSpaceFields.GUID = "dev-space-guid-1"
				stagingSpaceFields := models.SpaceFields{}
				stagingSpaceFields.Name = "staging"
				stagingSpaceFields.GUID = "staging-space-guid-1"
				domainFields := models.DomainFields{}
				domainFields.Name = "cfapps.io"
				domainFields.GUID = "1111"
				domainFields.OwningOrganizationGUID = "my-org-guid"
				domainFields.Shared = true
				cfAppDomainFields := models.DomainFields{}
				cfAppDomainFields.Name = "cf-app.com"
				cfAppDomainFields.GUID = "2222"
				cfAppDomainFields.OwningOrganizationGUID = "my-org-guid"
				cfAppDomainFields.Shared = false

				org = &models.Organization{}
				org.Name = "my-org"
				org.GUID = "my-org-guid"
				org.QuotaDefinition = models.QuotaFields{
					Name:                    "cantina-quota",
					MemoryLimit:             512,
					InstanceMemoryLimit:     256,
					RoutesLimit:             2,
					ServicesLimit:           5,
					NonBasicServicesAllowed: true,
					AppInstanceLimit:        7,
					ReservedRoutePorts:      "7",
				}
				org.Spaces = []models.SpaceFields{developmentSpaceFields, stagingSpaceFields}
				org.Domains = []models.DomainFields{domainFields, cfAppDomainFields}
				org.SpaceQuotas = []models.SpaceQuota{
					{Name: "space-quota-1", GUID: "space-quota-1-guid", MemoryLimit: 512, InstanceMemoryLimit: -1},
					{Name: "space-quota-2", GUID: "space-quota-2-guid", MemoryLimit: 256, InstanceMemoryLimit: 128},
				}

				requirementsFactory.LoginSuccess = true
				requirementsFactory.Organization = *org
			})

			It("shows the org with the given name", func() {
				runCommand("my-org")

				Expect(requirementsFactory.OrganizationName).To(Equal("my-org"))
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Getting info for org", "my-org", "my-user"},
					[]string{"OK"},
					[]string{"my-org"},
					[]string{"domains:", "cfapps.io", "cf-app.com"},
					[]string{"quota: ", "cantina-quota", "512M", "256M instance memory limit", "2 routes", "5 services", "paid services allowed", "7 app instance limit", "7 route ports"},
					[]string{"spaces:", "development", "staging"},
					[]string{"space quotas:", "space-quota-1", "space-quota-2"},
				))
			})

			It("shows unlimited route ports when a limit is not set (-1)", func() {
				org.QuotaDefinition.ReservedRoutePorts = "-1"
				requirementsFactory.Organization = *org

				runCommand("my-org")

				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"unlimited route ports"},
				))
			})

			It("should not display route ports if the CC API does not provide it", func() {
				org.QuotaDefinition.ReservedRoutePorts = ""
				requirementsFactory.Organization = *org

				success := runCommand("my-org")
				Expect(success).To(BeTrue())

				Expect(ui.Outputs).NotTo(ContainSubstrings([]string{"route ports"}))
			})

			Context("when the guid flag is provided", func() {
				It("shows only the org guid", func() {
					runCommand("--guid", "my-org")

					Expect(ui.Outputs).To(ContainSubstrings(
						[]string{"my-org-guid"},
					))

					Expect(ui.Outputs).ToNot(ContainSubstrings(
						[]string{"Getting info for org", "my-org", "my-user"},
					))
				})
			})

			Context("when invoked by a plugin", func() {
				var (
					pluginModel plugin_models.GetOrg_Model
				)
				BeforeEach(func() {
					pluginModel = plugin_models.GetOrg_Model{}
					deps.PluginModels.Organization = &pluginModel
				})

				It("populates the plugin model", func() {
					testcmd.RunCLICommand("org", []string{"my-org"}, requirementsFactory, updateCommandDependency, true, ui)

					Expect(pluginModel.Name).To(Equal("my-org"))
					Expect(pluginModel.Guid).To(Equal("my-org-guid"))
					// quota
					Expect(pluginModel.QuotaDefinition.Name).To(Equal("cantina-quota"))
					Expect(pluginModel.QuotaDefinition.MemoryLimit).To(Equal(int64(512)))
					Expect(pluginModel.QuotaDefinition.InstanceMemoryLimit).To(Equal(int64(256)))
					Expect(pluginModel.QuotaDefinition.RoutesLimit).To(Equal(2))
					Expect(pluginModel.QuotaDefinition.ServicesLimit).To(Equal(5))
					Expect(pluginModel.QuotaDefinition.NonBasicServicesAllowed).To(BeTrue())

					// domains
					Expect(pluginModel.Domains).To(HaveLen(2))
					Expect(pluginModel.Domains[0].Name).To(Equal("cfapps.io"))
					Expect(pluginModel.Domains[0].Guid).To(Equal("1111"))
					Expect(pluginModel.Domains[0].OwningOrganizationGuid).To(Equal("my-org-guid"))
					Expect(pluginModel.Domains[0].Shared).To(BeTrue())
					Expect(pluginModel.Domains[1].Name).To(Equal("cf-app.com"))
					Expect(pluginModel.Domains[1].Guid).To(Equal("2222"))
					Expect(pluginModel.Domains[1].OwningOrganizationGuid).To(Equal("my-org-guid"))
					Expect(pluginModel.Domains[1].Shared).To(BeFalse())

					// spaces
					Expect(pluginModel.Spaces).To(HaveLen(2))
					Expect(pluginModel.Spaces[0].Name).To(Equal("development"))
					Expect(pluginModel.Spaces[0].Guid).To(Equal("dev-space-guid-1"))
					Expect(pluginModel.Spaces[1].Name).To(Equal("staging"))
					Expect(pluginModel.Spaces[1].Guid).To(Equal("staging-space-guid-1"))

					// space quotas
					Expect(pluginModel.SpaceQuotas).To(HaveLen(2))
					Expect(pluginModel.SpaceQuotas[0].Name).To(Equal("space-quota-1"))
					Expect(pluginModel.SpaceQuotas[0].Guid).To(Equal("space-quota-1-guid"))
					Expect(pluginModel.SpaceQuotas[0].MemoryLimit).To(Equal(int64(512)))
					Expect(pluginModel.SpaceQuotas[0].InstanceMemoryLimit).To(Equal(int64(-1)))
					Expect(pluginModel.SpaceQuotas[1].Name).To(Equal("space-quota-2"))
					Expect(pluginModel.SpaceQuotas[1].Guid).To(Equal("space-quota-2-guid"))
					Expect(pluginModel.SpaceQuotas[1].MemoryLimit).To(Equal(int64(256)))
					Expect(pluginModel.SpaceQuotas[1].InstanceMemoryLimit).To(Equal(int64(128)))
				})

			})
		})
	})
})
<commit_msg>Refactor organization command tests to not use runCLICommand<commit_after>package organization_test

import (
	"github.com/cloudfoundry/cli/cf/commandregistry"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/flags"
	"github.com/cloudfoundry/cli/plugin/models"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"

	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/commands/organization"
	"github.com/cloudfoundry/cli/cf/requirements/requirementsfakes"
	. "github.com/cloudfoundry/cli/testhelpers/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("org command", func() {
	var (
		ui             *testterm.FakeUI
		getOrgModel    *plugin_models.GetOrg_Model
		deps           commandregistry.Dependency
		reqFactory     *requirementsfakes.FakeFactory
		loginReq       *requirementsfakes.FakeRequirement
		orgRequirement *requirementsfakes.FakeOrganizationRequirement
		cmd            organization.ShowOrg
		flagContext    flags.FlagContext
	)

	BeforeEach(func() {
		ui = new(testterm.FakeUI)
		getOrgModel = new(plugin_models.GetOrg_Model)

		deps = commandregistry.Dependency{
			UI:          ui,
			Config:      testconfig.NewRepositoryWithDefaults(),
			RepoLocator: api.RepositoryLocator{},
			PluginModels: &commandregistry.PluginModels{
				Organization: getOrgModel,
			},
		}

		reqFactory = new(requirementsfakes.FakeFactory)

		loginReq = new(requirementsfakes.FakeRequirement)
		loginReq.ExecuteReturns(nil)
		reqFactory.NewLoginRequirementReturns(loginReq)

		orgRequirement = new(requirementsfakes.FakeOrganizationRequirement)
		orgRequirement.ExecuteReturns(nil)
		reqFactory.NewOrganizationRequirementReturns(orgRequirement)

		cmd = organization.ShowOrg{}
		flagContext = flags.NewFlagContext(cmd.MetaData().Flags)
		cmd.SetDependency(deps, false)
	})

	Describe("Requirements", func() {
		Context("when the wrong number of args are provided", func() {
			BeforeEach(func() {
				err := flagContext.Parse()
				Expect(err).NotTo(HaveOccurred())
			})

			It("fails with no args", func() {
				Expect(func() { cmd.Requirements(reqFactory, flagContext) }).To(Panic())
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"FAILED"},
					[]string{"Incorrect Usage. Requires an argument"},
				))
			})
		})

		Context("when provided exactly one arg", func() {
			var actualRequirements []requirements.Requirement

			BeforeEach(func() {
				err := flagContext.Parse("my-org")
				Expect(err).NotTo(HaveOccurred())
				actualRequirements = cmd.Requirements(reqFactory, flagContext)
			})

			Context("when no flags are provided", func() {
				It("returns a login requirement", func() {
					Expect(reqFactory.NewLoginRequirementCallCount()).To(Equal(1))
					Expect(actualRequirements).To(ContainElement(loginReq))
				})

				It("returns an organization requirement", func() {
					Expect(reqFactory.NewOrganizationRequirementCallCount()).To(Equal(1))
					Expect(actualRequirements).To(ContainElement(orgRequirement))
				})
			})
		})
	})

	Describe("Execute", func() {
		var (
			org        models.Organization
			executeErr error
		)

		BeforeEach(func() {
			org = models.Organization{
				OrganizationFields: models.OrganizationFields{
					Name: "my-org",
					GUID: "my-org-guid",
					QuotaDefinition: models.QuotaFields{
						Name:                    "cantina-quota",
						MemoryLimit:             512,
						InstanceMemoryLimit:     256,
						RoutesLimit:             2,
						ServicesLimit:           5,
						NonBasicServicesAllowed: true,
						AppInstanceLimit:        7,
						ReservedRoutePorts:      "7",
					},
				},
				Spaces: []models.SpaceFields{
					models.SpaceFields{
						Name: "development",
						GUID: "dev-space-guid-1",
					},
					models.SpaceFields{
						Name: "staging",
						GUID: "staging-space-guid-1",
					},
				},
				Domains: []models.DomainFields{
					models.DomainFields{
						Name: "cfapps.io",
						GUID: "1111",
						OwningOrganizationGUID: "my-org-guid",
						Shared:                 true,
					},
					models.DomainFields{
						Name: "cf-app.com",
						GUID: "2222",
						OwningOrganizationGUID: "my-org-guid",
						Shared:                 false,
					},
				},
				SpaceQuotas: []models.SpaceQuota{
					{Name: "space-quota-1", GUID: "space-quota-1-guid", MemoryLimit: 512, InstanceMemoryLimit: -1},
					{Name: "space-quota-2", GUID: "space-quota-2-guid", MemoryLimit: 256, InstanceMemoryLimit: 128},
				},
			}

			orgRequirement.GetOrganizationReturns(org)
		})

		JustBeforeEach(func() {
			executeErr = cmd.Execute(flagContext)
		})

		Context("when logged in, and provided the name of an org", func() {
			BeforeEach(func() {
				err := flagContext.Parse("my-org")
				Expect(err).NotTo(HaveOccurred())
				cmd.Requirements(reqFactory, flagContext)
			})

			It("shows the org with the given name", func() {
				Expect(executeErr).NotTo(HaveOccurred())

				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Getting info for org", "my-org", "my-user"},
					[]string{"OK"},
					[]string{"my-org"},
					[]string{"domains:", "cfapps.io", "cf-app.com"},
					[]string{"quota: ", "cantina-quota", "512M", "256M instance memory limit", "2 routes", "5 services", "paid services allowed", "7 app instance limit", "7 route ports"},
					[]string{"spaces:", "development", "staging"},
					[]string{"space quotas:", "space-quota-1", "space-quota-2"},
				))
			})

			Context("when ReservedRoutePorts is set to -1", func() {
				BeforeEach(func() {
					org.QuotaDefinition.ReservedRoutePorts = "-1"
					orgRequirement.GetOrganizationReturns(org)
				})

				It("shows unlimited route ports", func() {
					Expect(executeErr).NotTo(HaveOccurred())

					Expect(ui.Outputs).To(ContainSubstrings(
						[]string{"unlimited route ports"},
					))
				})
			})

			Context("when the reserved route ports field is not provided by the CC API", func() {
				BeforeEach(func() {
					org.QuotaDefinition.ReservedRoutePorts = ""
					orgRequirement.GetOrganizationReturns(org)
				})

				It("should not display route ports", func() {
					Expect(executeErr).NotTo(HaveOccurred())

					Expect(ui.Outputs).NotTo(ContainSubstrings(
						[]string{"route ports"},
					))
				})
			})

			Context("when the guid flag is provided", func() {
				BeforeEach(func() {
					err := flagContext.Parse("my-org", "--guid")
					Expect(err).NotTo(HaveOccurred())
				})

				It("shows only the org guid", func() {
					Expect(executeErr).NotTo(HaveOccurred())

					Expect(ui.Outputs).To(ContainSubstrings(
						[]string{"my-org-guid"},
					))
					Expect(ui.Outputs).ToNot(ContainSubstrings(
						[]string{"Getting info for org", "my-org", "my-user"},
					))
				})
			})

			Context("when invoked by a plugin", func() {
				BeforeEach(func() {
					cmd.SetDependency(deps, true)
				})

				It("populates the plugin model", func() {
					Expect(executeErr).NotTo(HaveOccurred())

					Expect(getOrgModel.Guid).To(Equal("my-org-guid"))
					Expect(getOrgModel.Name).To(Equal("my-org"))
					// quota
					Expect(getOrgModel.QuotaDefinition.Name).To(Equal("cantina-quota"))
					Expect(getOrgModel.QuotaDefinition.MemoryLimit).To(Equal(int64(512)))
					Expect(getOrgModel.QuotaDefinition.InstanceMemoryLimit).To(Equal(int64(256)))
					Expect(getOrgModel.QuotaDefinition.RoutesLimit).To(Equal(2))
					Expect(getOrgModel.QuotaDefinition.ServicesLimit).To(Equal(5))
					Expect(getOrgModel.QuotaDefinition.NonBasicServicesAllowed).To(BeTrue())

					// domains
					Expect(getOrgModel.Domains).To(HaveLen(2))
					Expect(getOrgModel.Domains[0].Name).To(Equal("cfapps.io"))
					Expect(getOrgModel.Domains[0].Guid).To(Equal("1111"))
					Expect(getOrgModel.Domains[0].OwningOrganizationGuid).To(Equal("my-org-guid"))
					Expect(getOrgModel.Domains[0].Shared).To(BeTrue())
					Expect(getOrgModel.Domains[1].Name).To(Equal("cf-app.com"))
					Expect(getOrgModel.Domains[1].Guid).To(Equal("2222"))
					Expect(getOrgModel.Domains[1].OwningOrganizationGuid).To(Equal("my-org-guid"))
					Expect(getOrgModel.Domains[1].Shared).To(BeFalse())

					// spaces
					Expect(getOrgModel.Spaces).To(HaveLen(2))
					Expect(getOrgModel.Spaces[0].Name).To(Equal("development"))
					Expect(getOrgModel.Spaces[0].Guid).To(Equal("dev-space-guid-1"))
					Expect(getOrgModel.Spaces[1].Name).To(Equal("staging"))
					Expect(getOrgModel.Spaces[1].Guid).To(Equal("staging-space-guid-1"))

					// space quotas
					Expect(getOrgModel.SpaceQuotas).To(HaveLen(2))
					Expect(getOrgModel.SpaceQuotas[0].Name).To(Equal("space-quota-1"))
					Expect(getOrgModel.SpaceQuotas[0].Guid).To(Equal("space-quota-1-guid"))
					Expect(getOrgModel.SpaceQuotas[0].MemoryLimit).To(Equal(int64(512)))
					Expect(getOrgModel.SpaceQuotas[0].InstanceMemoryLimit).To(Equal(int64(-1)))
					Expect(getOrgModel.SpaceQuotas[1].Name).To(Equal("space-quota-2"))
					Expect(getOrgModel.SpaceQuotas[1].Guid).To(Equal("space-quota-2-guid"))
					Expect(getOrgModel.SpaceQuotas[1].MemoryLimit).To(Equal(int64(256)))
					Expect(getOrgModel.SpaceQuotas[1].InstanceMemoryLimit).To(Equal(int64(128)))
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>// +build cit

package metadata

import (
	"io/ioutil"
	"strings"
	"testing"

	"github.com/GoogleCloudPlatform/guest-test-infra/imagetest/utils"
)

const shutdownTime = 110 // about 2 minutes

// TestShutdownScript test the standard metadata script.
func TestShutdownScript(t *testing.T) {
	bytes, err := ioutil.ReadFile(shutdownOutputPath)
	if err != nil {
		t.Fatalf("failed to read shutdown output %v", err)
	}
	output := strings.TrimSpace(string(bytes))
	if output != shutdownContent {
		t.Fatalf(`shutdown script output expect "%s", but actually "%s"`, shutdownContent, output)
	}
}

// TestShutdownScriptFailed test that a script failed execute doesn't crash the vm.
func TestShutdownScriptFailed(t *testing.T) {
	if _, err := utils.GetMetadataAttribute("shutdown-script"); err != nil {
		t.Fatalf("couldn't get shutdown-script from metadata")
	}
}

// TestShutdownUrlScript test that URL scripts work correctly.
func TestShutdownUrlScript(t *testing.T) {
	bytes, err := ioutil.ReadFile(shutdownOutputPath)
	if err != nil {
		t.Fatalf("failed to read shutdown output %v", err)
	}
	output := strings.TrimSpace(string(bytes))
	if output != shutdownContent {
		t.Fatalf(`shutdown script output expect "%s", but actually "%s"`, shutdownContent, output)
	}
}

// TestShutdownScriptTime test that shutdown scripts can run for around two minutes
func TestShutdownScriptTime(t *testing.T) {
	bytes, err := ioutil.ReadFile("/shutdown.txt")
	if err != nil {
		t.Fatalf("error reading file: %v", err)
	}
	lines := strings.Split(strings.TrimSpace(string(bytes)), "\n")
	if len(lines) < shutdownTime {
		t.Fatalf("shut down time is %d which is less than %d seconds.", len(lines), shutdownTime)
	}
	t.Logf("shut down time is %d", len(lines))
}
<commit_msg>[guest-agent image test] fix: verify that shut down script executed no less than 80s (#474)<commit_after>// +build cit

package metadata

import (
	"io/ioutil"
	"strings"
	"testing"

	"github.com/GoogleCloudPlatform/guest-test-infra/imagetest/utils"
)

// The designed shutdown limit is 90s. Let's verify it's executed no less than 80s.
const shutdownTime = 80

// TestShutdownScript test the standard metadata script.
func TestShutdownScript(t *testing.T) {
	bytes, err := ioutil.ReadFile(shutdownOutputPath)
	if err != nil {
		t.Fatalf("failed to read shutdown output %v", err)
	}
	output := strings.TrimSpace(string(bytes))
	if output != shutdownContent {
		t.Fatalf(`shutdown script output expect "%s", but actually "%s"`, shutdownContent, output)
	}
}

// TestShutdownScriptFailed test that a script failed execute doesn't crash the vm.
func TestShutdownScriptFailed(t *testing.T) {
	if _, err := utils.GetMetadataAttribute("shutdown-script"); err != nil {
		t.Fatalf("couldn't get shutdown-script from metadata")
	}
}

// TestShutdownUrlScript test that URL scripts work correctly.
func TestShutdownUrlScript(t *testing.T) {
	bytes, err := ioutil.ReadFile(shutdownOutputPath)
	if err != nil {
		t.Fatalf("failed to read shutdown output %v", err)
	}
	output := strings.TrimSpace(string(bytes))
	if output != shutdownContent {
		t.Fatalf(`shutdown script output expect "%s", but actually "%s"`, shutdownContent, output)
	}
}

// TestShutdownScriptTime test that shutdown scripts can run for around two minutes
func TestShutdownScriptTime(t *testing.T) {
	bytes, err := ioutil.ReadFile("/shutdown.txt")
	if err != nil {
		t.Fatalf("error reading file: %v", err)
	}
	lines := strings.Split(strings.TrimSpace(string(bytes)), "\n")
	if len(lines) < shutdownTime {
		t.Fatalf("shut down time is %d which is less than %d seconds.", len(lines), shutdownTime)
	}
	t.Logf("shut down time is %d", len(lines))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/codegangsta/cli"
	"github.com/docker/libcontainer"
)

var statsCommand = cli.Command{
	Name:   "stats",
	Usage:  "display statistics for the container",
	Action: statsAction,
}

func statsAction(context *cli.Context) {
	container, err := loadContainer()
	if err != nil {
		log.Fatal(err)
	}

	runtimeCkpt, err := libcontainer.GetState(dataPath)
	if err != nil {
		log.Fatal(err)
	}

	stats, err := getStats(container, runtimeCkpt)
	if err != nil {
		log.Fatalf("Failed to get stats - %v\n", err)
	}

	fmt.Printf("Stats:\n%v\n", stats)
}

// returns the container stats in json format.
func getStats(container *libcontainer.Config, state *libcontainer.State) (string, error) {
	stats, err := libcontainer.GetStats(container, state)
	if err != nil {
		return "", err
	}

	out, err := json.MarshalIndent(stats, "", "\t")
	if err != nil {
		return "", err
	}

	return string(out), nil
}
<commit_msg>Just output raw stats json Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@docker.com> (github: crosbymichael)<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/codegangsta/cli"
	"github.com/docker/libcontainer"
)

var statsCommand = cli.Command{
	Name:   "stats",
	Usage:  "display statistics for the container",
	Action: statsAction,
}

func statsAction(context *cli.Context) {
	container, err := loadContainer()
	if err != nil {
		log.Fatal(err)
	}

	state, err := libcontainer.GetState(dataPath)
	if err != nil {
		log.Fatal(err)
	}

	stats, err := libcontainer.GetStats(container, state)
	if err != nil {
		log.Fatal(err)
	}
	data, err := json.MarshalIndent(stats, "", "\t")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s", data)
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"

	ab "github.com/hyperledger/fabric/orderer/atomicbroadcast"
	"github.com/hyperledger/fabric/orderer/common/bootstrap"
	"github.com/hyperledger/fabric/orderer/common/bootstrap/static"
	"github.com/hyperledger/fabric/orderer/common/broadcastfilter"
	"github.com/hyperledger/fabric/orderer/common/broadcastfilter/configfilter"
	"github.com/hyperledger/fabric/orderer/common/configtx"
	"github.com/hyperledger/fabric/orderer/common/policies"
	"github.com/hyperledger/fabric/orderer/config"
	"github.com/hyperledger/fabric/orderer/kafka"
	"github.com/hyperledger/fabric/orderer/rawledger"
	"github.com/hyperledger/fabric/orderer/rawledger/fileledger"
	"github.com/hyperledger/fabric/orderer/rawledger/ramledger"
	"github.com/hyperledger/fabric/orderer/solo"

	"github.com/Shopify/sarama"
	"github.com/golang/protobuf/proto"
	"github.com/op/go-logging"
	"google.golang.org/grpc"
)

var logger = logging.MustGetLogger("orderer/main")

func main() {
	conf := config.Load()

	// Start the profiling service if enabled. The ListenAndServe()
	// call does not return unless an error occurs.
	if conf.General.Profile.Enabled {
		go func() {
			logger.Infof("Starting Go pprof profiling service on %s", conf.General.Profile.Address)
			panic(fmt.Errorf("Go pprof service failed: %s", http.ListenAndServe(conf.General.Profile.Address, nil)))
		}()
	}

	switch conf.General.OrdererType {
	case "solo":
		launchSolo(conf)
	case "kafka":
		launchKafka(conf)
	default:
		panic("Invalid orderer type specified in config")
	}
}

// XXX This crypto helper is a stand in until we have a real crypto handler
// it considers all signatures to be valid
type xxxCryptoHelper struct{}

func (xxx xxxCryptoHelper) VerifySignature(msg []byte, ids []byte, sigs []byte) bool {
	return true
}

func init() {
	logging.SetLevel(logging.DEBUG, "")
}

func retrieveConfiguration(rl rawledger.Reader) *ab.ConfigurationEnvelope {
	var lastConfigTx *ab.ConfigurationEnvelope

	it, _ := rl.Iterator(ab.SeekInfo_OLDEST, 0)
	// Iterate over the blockchain, looking for config transactions, track the most recent one encountered
	// this will be the transaction which is returned
	for {
		select {
		case <-it.ReadyChan():
			block, status := it.Next()
			if status != ab.Status_SUCCESS {
				panic(fmt.Errorf("Error parsing blockchain at startup: %v", status))
			}
			// ConfigTxs should always be by themselves
			if len(block.Data.Data) != 1 {
				continue
			}

			maybeConfigTx := &ab.ConfigurationEnvelope{}

			err := proto.Unmarshal(block.Data.Data[0], maybeConfigTx)

			if err == nil {
				lastConfigTx = maybeConfigTx
			}
		default:
			return lastConfigTx
		}
	}
}

func bootstrapConfigManager(lastConfigTx *ab.ConfigurationEnvelope) configtx.Manager {
	policyManager := policies.NewManagerImpl(xxxCryptoHelper{})
	configHandlerMap := make(map[ab.Configuration_ConfigurationType]configtx.Handler)
	for ctype := range ab.Configuration_ConfigurationType_name {
		rtype := ab.Configuration_ConfigurationType(ctype)
		switch rtype {
		case ab.Configuration_Policy:
			configHandlerMap[rtype] = policyManager
		default:
			configHandlerMap[rtype] = configtx.NewBytesHandler()
		}
	}

	configManager, err := configtx.NewConfigurationManager(lastConfigTx, policyManager, configHandlerMap)
	if err != nil {
		panic(err)
	}
	return configManager
}

func createBroadcastRuleset(configManager configtx.Manager) *broadcastfilter.RuleSet {
	return broadcastfilter.NewRuleSet([]broadcastfilter.Rule{
		broadcastfilter.EmptyRejectRule,
		configfilter.New(configManager),
		broadcastfilter.AcceptRule,
	})
}

func launchSolo(conf *config.TopLevel) {
	grpcServer := grpc.NewServer()

	lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", conf.General.ListenAddress, conf.General.ListenPort))
	if err != nil {
		fmt.Println("Failed to listen:", err)
		return
	}

	var bootstrapper bootstrap.Helper

	// Select the bootstrapping mechanism
	switch conf.General.GenesisMethod {
	case "static":
		bootstrapper = static.New()
	default:
		panic(fmt.Errorf("Unknown genesis method %s", conf.General.GenesisMethod))
	}

	genesisBlock, err := bootstrapper.GenesisBlock()

	if err != nil {
		panic(fmt.Errorf("Error retrieving the genesis block %s", err))
	}

	// Stand in until real config
	ledgerType := os.Getenv("ORDERER_LEDGER_TYPE")
	var rawledger rawledger.ReadWriter
	switch ledgerType {
	case "file":
		location := conf.FileLedger.Location
		if location == "" {
			var err error
			location, err = ioutil.TempDir("", conf.FileLedger.Prefix)
			if err != nil {
				panic(fmt.Errorf("Error creating temp dir: %s", err))
			}
		}

		rawledger = fileledger.New(location, genesisBlock)
	case "ram":
		fallthrough
	default:
		rawledger = ramledger.New(int(conf.RAMLedger.HistorySize), genesisBlock)
	}

	lastConfigTx := retrieveConfiguration(rawledger)
	if lastConfigTx == nil {
		panic("No chain configuration found")
	}

	configManager := bootstrapConfigManager(lastConfigTx)

	// XXX actually use the config manager in the future
	_ = configManager

	solo.New(int(conf.General.QueueSize),
		int(conf.General.BatchSize),
		int(conf.General.MaxWindowSize),
		conf.General.BatchTimeout,
		rawledger,
		grpcServer,
		createBroadcastRuleset(configManager),
		configManager,
	)
	grpcServer.Serve(lis)
}

func launchKafka(conf *config.TopLevel) {
	var kafkaVersion = sarama.V0_9_0_1 // TODO Ideally we'd set this in the YAML file but its type makes this impossible
	conf.Kafka.Version = kafkaVersion

	var loglevel string
	var verbose bool

	flag.StringVar(&loglevel, "loglevel", "info",
		"Set the logging level for the orderer. (Suggested values: info, debug)")
	flag.BoolVar(&verbose, "verbose", false,
		"Turn on logging for the Kafka library. (Default: \"false\")")
	flag.Parse()

	kafka.SetLogLevel(loglevel)
	if verbose {
		sarama.Logger = log.New(os.Stdout, "[sarama] ", log.Lshortfile)
	}

	ordererSrv := kafka.New(conf)
	defer ordererSrv.Teardown()

	lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", conf.General.ListenAddress, conf.General.ListenPort))
	if err != nil {
		panic(err)
	}
	rpcSrv := grpc.NewServer() // TODO Add TLS support
	ab.RegisterAtomicBroadcastServer(rpcSrv, ordererSrv)
	go rpcSrv.Serve(lis)

	// Trap SIGINT to trigger a shutdown
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	for range signalChan {
		fmt.Println("Server shutting down")
		return
	}
}
<commit_msg>FAB-939 temp hack for orderer to allow Transaction2<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"

	ab "github.com/hyperledger/fabric/orderer/atomicbroadcast"
	"github.com/hyperledger/fabric/orderer/common/bootstrap"
	"github.com/hyperledger/fabric/orderer/common/bootstrap/static"
	"github.com/hyperledger/fabric/orderer/common/broadcastfilter"
	// "github.com/hyperledger/fabric/orderer/common/broadcastfilter/configfilter"
	"github.com/hyperledger/fabric/orderer/common/configtx"
	"github.com/hyperledger/fabric/orderer/common/policies"
	"github.com/hyperledger/fabric/orderer/config"
	"github.com/hyperledger/fabric/orderer/kafka"
	"github.com/hyperledger/fabric/orderer/rawledger"
	"github.com/hyperledger/fabric/orderer/rawledger/fileledger"
	"github.com/hyperledger/fabric/orderer/rawledger/ramledger"
	"github.com/hyperledger/fabric/orderer/solo"

	"github.com/Shopify/sarama"
	"github.com/golang/protobuf/proto"
	"github.com/op/go-logging"
	"google.golang.org/grpc"
)

var logger = logging.MustGetLogger("orderer/main")

func main() {
	conf := config.Load()

	// Start the profiling service if enabled. The ListenAndServe()
	// call does not return unless an error occurs.
	if conf.General.Profile.Enabled {
		go func() {
			logger.Infof("Starting Go pprof profiling service on %s", conf.General.Profile.Address)
			panic(fmt.Errorf("Go pprof service failed: %s", http.ListenAndServe(conf.General.Profile.Address, nil)))
		}()
	}

	switch conf.General.OrdererType {
	case "solo":
		launchSolo(conf)
	case "kafka":
		launchKafka(conf)
	default:
		panic("Invalid orderer type specified in config")
	}
}

// XXX This crypto helper is a stand in until we have a real crypto handler
// it considers all signatures to be valid
type xxxCryptoHelper struct{}

func (xxx xxxCryptoHelper) VerifySignature(msg []byte, ids []byte, sigs []byte) bool {
	return true
}

func init() {
	logging.SetLevel(logging.DEBUG, "")
}

func retrieveConfiguration(rl rawledger.Reader) *ab.ConfigurationEnvelope {
	var lastConfigTx *ab.ConfigurationEnvelope

	it, _ := rl.Iterator(ab.SeekInfo_OLDEST, 0)
	// Iterate over the blockchain, looking for config transactions, track the most recent one encountered
	// this will be the transaction which is returned
	for {
		select {
		case <-it.ReadyChan():
			block, status := it.Next()
			if status != ab.Status_SUCCESS {
				panic(fmt.Errorf("Error parsing blockchain at startup: %v", status))
			}
			// ConfigTxs should always be by themselves
			if len(block.Data.Data) != 1 {
				continue
			}

			maybeConfigTx := &ab.ConfigurationEnvelope{}

			err := proto.Unmarshal(block.Data.Data[0], maybeConfigTx)

			if err == nil {
				lastConfigTx = maybeConfigTx
			}
		default:
			return lastConfigTx
		}
	}
}

func bootstrapConfigManager(lastConfigTx *ab.ConfigurationEnvelope) configtx.Manager {
	policyManager := policies.NewManagerImpl(xxxCryptoHelper{})
	configHandlerMap := make(map[ab.Configuration_ConfigurationType]configtx.Handler)
	for ctype := range ab.Configuration_ConfigurationType_name {
		rtype := ab.Configuration_ConfigurationType(ctype)
		switch rtype {
		case ab.Configuration_Policy:
			configHandlerMap[rtype] = policyManager
		default:
			configHandlerMap[rtype] = configtx.NewBytesHandler()
		}
	}

	configManager, err := configtx.NewConfigurationManager(lastConfigTx, policyManager, configHandlerMap)
	if err != nil {
		panic(err)
	}
	return configManager
}

func createBroadcastRuleset(configManager configtx.Manager) *broadcastfilter.RuleSet {
	return broadcastfilter.NewRuleSet([]broadcastfilter.Rule{
		broadcastfilter.EmptyRejectRule,
		// configfilter.New(configManager),
		broadcastfilter.AcceptRule,
	})
}

func launchSolo(conf *config.TopLevel) {
	grpcServer := grpc.NewServer()

	lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", conf.General.ListenAddress, conf.General.ListenPort))
	if err != nil {
		fmt.Println("Failed to listen:", err)
		return
	}

	var bootstrapper bootstrap.Helper

	// Select the bootstrapping mechanism
	switch conf.General.GenesisMethod {
	case "static":
		bootstrapper = static.New()
	default:
		panic(fmt.Errorf("Unknown genesis method %s", conf.General.GenesisMethod))
	}

	genesisBlock, err := bootstrapper.GenesisBlock()

	if err != nil {
		panic(fmt.Errorf("Error retrieving the genesis block %s", err))
	}

	// Stand in until real config
	ledgerType := os.Getenv("ORDERER_LEDGER_TYPE")
	var rawledger rawledger.ReadWriter
	switch ledgerType {
	case "file":
		location := conf.FileLedger.Location
		if location == "" {
			var err error
			location, err = ioutil.TempDir("", conf.FileLedger.Prefix)
			if err != nil {
				panic(fmt.Errorf("Error creating temp dir: %s", err))
			}
		}

		rawledger = fileledger.New(location, genesisBlock)
	case "ram":
		fallthrough
	default:
		rawledger = ramledger.New(int(conf.RAMLedger.HistorySize), genesisBlock)
	}

	lastConfigTx := retrieveConfiguration(rawledger)
	if lastConfigTx == nil {
		panic("No chain configuration found")
	}

	configManager := bootstrapConfigManager(lastConfigTx)

	// XXX actually use the config manager in the future
	_ = configManager

	solo.New(int(conf.General.QueueSize),
		int(conf.General.BatchSize),
		int(conf.General.MaxWindowSize),
		conf.General.BatchTimeout,
		rawledger,
		grpcServer,
		createBroadcastRuleset(configManager),
		configManager,
	)
	grpcServer.Serve(lis)
}

func launchKafka(conf *config.TopLevel) {
	var kafkaVersion = sarama.V0_9_0_1 // TODO Ideally we'd set this in the YAML file but its type makes this impossible
	conf.Kafka.Version = kafkaVersion

	var loglevel string
	var verbose bool

	flag.StringVar(&loglevel, "loglevel", "info",
		"Set the logging level for the orderer. (Suggested values: info, debug)")
	flag.BoolVar(&verbose, "verbose", false,
		"Turn on logging for the Kafka library. (Default: \"false\")")
	flag.Parse()

	kafka.SetLogLevel(loglevel)
	if verbose {
		sarama.Logger = log.New(os.Stdout, "[sarama] ", log.Lshortfile)
	}

	ordererSrv := kafka.New(conf)
	defer ordererSrv.Teardown()

	lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", conf.General.ListenAddress, conf.General.ListenPort))
	if err != nil {
		panic(err)
	}
	rpcSrv := grpc.NewServer() // TODO Add TLS support
	ab.RegisterAtomicBroadcastServer(rpcSrv, ordererSrv)
	go rpcSrv.Serve(lis)

	// Trap SIGINT to trigger a shutdown
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	for range signalChan {
		fmt.Println("Server shutting down")
		return
	}
}
<|endoftext|>


<commit_before>// Copyright © 2016 Aaron Longwell
//
// Use of this source code is governed by an MIT licese.
// Details in the LICENSE file.

package trello

import (
	"fmt"
)

type Organization struct {
	client      *Client
	ID          string   `json:"id"`
	Name        string   `json:"name"`
	DisplayName string   `json:"displayName"`
	Desc        string   `json:"desc"`
	URL         string   `json:"url"`
	Website     string   `json:"website"`
	Products    []string `json:"products"`
	PowerUps    []string `json:"powerUps"`
}

func (c *Client) GetOrganization(orgID string, args Arguments) (organization *Organization, err error) {
	path := fmt.Sprintf("organizations/%s", orgID)
	err = c.Get(path, args, &organization)
	if organization != nil {
		organization.client = c
	}
	return
}
<commit_msg>Add comments to public members of organization (golint)<commit_after>// Copyright © 2016 Aaron Longwell
//
// Use of this source code is governed by an MIT licese.
// Details in the LICENSE file.

package trello

import (
	"fmt"
)

// Organization represents a Trello organization or team, i.e. a collection of members and boards.
// https://developers.trello.com/reference/#organizations
type Organization struct {
	client      *Client
	ID          string   `json:"id"`
	Name        string   `json:"name"`
	DisplayName string   `json:"displayName"`
	Desc        string   `json:"desc"`
	URL         string   `json:"url"`
	Website     string   `json:"website"`
	Products    []string `json:"products"`
	PowerUps    []string `json:"powerUps"`
}

// GetOrganization takes an organization id and Arguments and either
// GETs returns an Organization, or an error.
func (c *Client) GetOrganization(orgID string, args Arguments) (organization *Organization, err error) {
	path := fmt.Sprintf("organizations/%s", orgID)
	err = c.Get(path, args, &organization)
	if organization != nil {
		organization.client = c
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"

	"bytes"
	"encoding/json"
	"github.com/couchbaselabs/consolio/types"
)

type handler func(consolio.ChangeEvent, string) error

var (
	cbgbUrlFlag     = flag.String("cbgb", "", "CBGB base URL")
	sgwUrlFlag      = flag.String("sgw", "", "URL to sync gateway")
	sgwAdminUrlFlag = flag.String("sgwadmin", "", "URL to sync gateway admin")

	cbgbUrl        string
	cbgbDB         string
	sgwDB          string
	sgwAdmin       string
	handlers       []handler
	cancelRedirect = fmt.Errorf("redirected")
)

func mustParseURL(ustr string) *url.URL {
	u, err := url.Parse(ustr)
	if err != nil {
		log.Fatalf("Error parsing URL %q: %v", ustr, err)
	}
	return u
}

func initHandlers() {
	handlers = append(handlers, logHandler)

	if *cbgbUrlFlag != "" {
		u := mustParseURL(*cbgbUrlFlag)
		u.Path = "/_api/buckets"
		cbgbUrl = u.String()
		u.Path = "/"
		cbgbDB = u.String()

		handlers = append(handlers, cbgbHandler)
	}

	if *sgwUrlFlag != "" && *sgwAdminUrlFlag != "" {
		u := mustParseURL(*sgwUrlFlag)
		u.Path = "/"
		sgwDB = u.String()

		u = mustParseURL(*sgwAdminUrlFlag)
		u.Path = "/"
		sgwAdmin = u.String()

		handlers = append(handlers, sgwHandler)
	}
}

func logHandler(e consolio.ChangeEvent, pw string) error {
	log.Printf("Found %v -> %v %v - %q",
		e.ID, e.Type, e.Item.Name, pw)
	return nil
}

func isRedirected(e error) bool {
	if x, ok := e.(*url.Error); ok {
		return x.Err == cancelRedirect
	}
	return false
}

func cbgbHandler(e consolio.ChangeEvent, pw string) error {
	if e.Item.Type != "database" {
		log.Printf("Ignoring non-database type: %v (%v)",
			e.Item.Name, e.Item.Type)
		return nil
	}
	switch e.Type {
	case "create":
		return cbgbCreate(e.Item.Name, pw)
	case "delete":
		return cbgbDelete(e.Item.Name)
	}
	return fmt.Errorf("Unhandled event type: %v", e.Type)
}

func cbgbDelete(dbname string) error {
	u := cbgbUrl + "/" + dbname
	req, err := http.NewRequest("DELETE", u, nil)
	if err != nil {
		return err
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode == 404 {
		log.Printf("Missing while deleting DB %q, must already be gone", dbname)
		return nil
	}
	if res.StatusCode != 204 {
		return fmt.Errorf("Unexpected HTTP status from cbgb for DELETE %q: %v",
			dbname, res.Status)
	}

	return nil
}

func cbgbCreate(dbname, pw string) error {
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return cancelRedirect
		},
	}

	vals := url.Values{}
	vals.Set("name", dbname)
	vals.Set("password", pw)
	vals.Set("quotaBytes", fmt.Sprintf("%d", 256*1024*1024))
	vals.Set("memoryOnly", "0")
	req, err := http.NewRequest("POST", cbgbUrl,
		strings.NewReader(vals.Encode()))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)
	if !isRedirected(err) {
		if err != nil {
			return err
		}
	}
	defer resp.Body.Close()
	if resp.StatusCode != 303 {
		bodyText, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 512))
		return fmt.Errorf("HTTP error creating bucket: %v\n%s",
			resp.Status, bodyText)
	}

	return updateItem("db", dbname, cbgbDB+dbname)
}

func sgwHandler(e consolio.ChangeEvent, pw string) error {
	if e.Item.Type != "sync_gateway" {
		log.Printf("Ignoring non-sgw type: %v (%v)",
			e.Item.Name, e.Item.Type)
		return nil
	}
	switch e.Type {
	case "create":
		return sgwCreate(e, pw)
	case "delete":
		return sgwDelete(e, pw)
	}
	return fmt.Errorf("Unhandled sgw event type: %v", e.Type)
}

func sgwCreate(e consolio.ChangeEvent, pw string) error {
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return cancelRedirect
		},
	}

	conf := map[string]interface{}{}
	for k, v := range e.Item.ExtraInfo {
		conf[k] = v
	}
	conf["server"] = cbgbDB
	conf["bucket"] = conf["dbname"]
	delete(conf, "dbname")

	b, err := json.Marshal(conf)
	if err != nil {
		return err
	}

	log.Printf("Provisioning with %s", b)

	req, err := http.NewRequest("PUT", sgwAdmin+e.Item.Name+"/",
		bytes.NewReader(b))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if !isRedirected(err) {
		if err != nil {
			return err
		}
	}
	defer resp.Body.Close()
	if resp.StatusCode == 412 {
		log.Printf("%q seems to already exist", e.Item.Name)
		return nil
	}
	if resp.StatusCode != 201 {
		bodyText, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 512))
		return fmt.Errorf("HTTP error creating bucket: %v\n%s",
			resp.Status, bodyText)
	}

	return updateItem("sgw", e.Item.Name, sgwDB+e.Item.Name)
}

func sgwDelete(e consolio.ChangeEvent, pw string) error {
	u := sgwAdmin + e.Item.Name + "/"
	req, err := http.NewRequest("DELETE", u, nil)
	if err != nil {
		return err
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode == 404 {
		log.Printf("Didn't find DB.  Must already be gone.")
		return nil
	}
	if res.StatusCode != 200 {
		return fmt.Errorf("Unexpected HTTP status from sgw: %v",
			res.Status)
	}

	return updateItem("sgw", e.Item.Name, sgwDB+e.Item.Name)
}
<commit_msg>import reorg<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"

	"github.com/couchbaselabs/consolio/types"
)

type handler func(consolio.ChangeEvent, string) error

var (
	cbgbUrlFlag     = flag.String("cbgb", "", "CBGB base URL")
	sgwUrlFlag      = flag.String("sgw", "", "URL to sync gateway")
	sgwAdminUrlFlag = flag.String("sgwadmin", "", "URL to sync gateway admin")

	cbgbUrl        string
	cbgbDB         string
	sgwDB          string
	sgwAdmin       string
	handlers       []handler
	cancelRedirect = fmt.Errorf("redirected")
)

func mustParseURL(ustr string) *url.URL {
	u, err := url.Parse(ustr)
	if err != nil {
		log.Fatalf("Error parsing URL %q: %v", ustr, err)
	}
	return u
}

func initHandlers() {
	handlers = append(handlers, logHandler)

	if *cbgbUrlFlag != "" {
		u := mustParseURL(*cbgbUrlFlag)
		u.Path = "/_api/buckets"
		cbgbUrl = u.String()
		u.Path = "/"
		cbgbDB = u.String()

		handlers = append(handlers, cbgbHandler)
	}

	if *sgwUrlFlag != "" && *sgwAdminUrlFlag != "" {
		u := mustParseURL(*sgwUrlFlag)
		u.Path = "/"
		sgwDB = u.String()

		u = mustParseURL(*sgwAdminUrlFlag)
		u.Path = "/"
		sgwAdmin = u.String()

		handlers = append(handlers, sgwHandler)
	}
}

func logHandler(e consolio.ChangeEvent, pw string) error {
	log.Printf("Found %v -> %v %v - %q",
		e.ID, e.Type, e.Item.Name, pw)
	return nil
}

func isRedirected(e error) bool {
	if x, ok := e.(*url.Error); ok {
		return x.Err == cancelRedirect
	}
	return false
}

func cbgbHandler(e consolio.ChangeEvent, pw string) error {
	if e.Item.Type != "database" {
		log.Printf("Ignoring non-database type: %v (%v)",
			e.Item.Name, e.Item.Type)
		return nil
	}
	switch e.Type {
	case "create":
		return cbgbCreate(e.Item.Name, pw)
	case "delete":
		return cbgbDelete(e.Item.Name)
	}
	return fmt.Errorf("Unhandled event type: %v", e.Type)
}

func cbgbDelete(dbname string) error {
	u := cbgbUrl + "/" + dbname
	req, err := http.NewRequest("DELETE", u, nil)
	if err != nil {
		return err
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode == 404 {
		log.Printf("Missing while deleting DB %q, must already be gone", dbname)
		return nil
	}
	if res.StatusCode != 204 {
		return fmt.Errorf("Unexpected HTTP status from cbgb for DELETE %q: %v",
			dbname, res.Status)
	}

	return nil
}

func cbgbCreate(dbname, pw string) error {
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return cancelRedirect
		},
	}

	vals := url.Values{}
	vals.Set("name", dbname)
	vals.Set("password", pw)
	vals.Set("quotaBytes", fmt.Sprintf("%d", 256*1024*1024))
	vals.Set("memoryOnly", "0")
	req, err := http.NewRequest("POST", cbgbUrl,
		strings.NewReader(vals.Encode()))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)
	if !isRedirected(err) {
		if err != nil {
			return err
		}
	}
	defer resp.Body.Close()
	if resp.StatusCode != 303 {
		bodyText, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 512))
		return fmt.Errorf("HTTP error creating bucket: %v\n%s",
			resp.Status, bodyText)
	}

	return updateItem("db", dbname, cbgbDB+dbname)
}

func sgwHandler(e consolio.ChangeEvent, pw string) error {
	if e.Item.Type != "sync_gateway" {
		log.Printf("Ignoring non-sgw type: %v (%v)",
			e.Item.Name, e.Item.Type)
		return nil
	}
	switch e.Type {
	case "create":
		return sgwCreate(e, pw)
	case "delete":
		return sgwDelete(e, pw)
	}
	return fmt.Errorf("Unhandled sgw event type: %v", e.Type)
}

func sgwCreate(e consolio.ChangeEvent, pw string) error {
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return cancelRedirect
		},
	}

	conf := map[string]interface{}{}
	for k, v := range e.Item.ExtraInfo {
		conf[k] = v
	}
	conf["server"] = cbgbDB
	conf["bucket"] = conf["dbname"]
	delete(conf, "dbname")

	b, err := json.Marshal(conf)
	if err != nil {
		return err
	}

	log.Printf("Provisioning with %s", b)

	req, err := http.NewRequest("PUT", sgwAdmin+e.Item.Name+"/",
		bytes.NewReader(b))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if !isRedirected(err) {
		if err != nil {
			return err
		}
	}
	defer resp.Body.Close()
	if resp.StatusCode == 412 {
		log.Printf("%q seems to already exist", e.Item.Name)
		return nil
	}
	if resp.StatusCode != 201 {
		bodyText, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 512))
		return fmt.Errorf("HTTP error creating bucket: %v\n%s",
			resp.Status, bodyText)
	}

	return updateItem("sgw", e.Item.Name, sgwDB+e.Item.Name)
}

func sgwDelete(e consolio.ChangeEvent, pw string) error {
	u := sgwAdmin + e.Item.Name + "/"
	req, err := http.NewRequest("DELETE", u, nil)
	if err != nil {
		return err
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode == 404 {
		log.Printf("Didn't find DB.  Must already be gone.")
		return nil
	}
	if res.StatusCode != 200 {
		return fmt.Errorf("Unexpected HTTP status from sgw: %v",
			res.Status)
	}

	return updateItem("sgw", e.Item.Name, sgwDB+e.Item.Name)
}
<|endoftext|>


<commit_before>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// execprog executes a single program or a set of programs
// and optionally prints information about execution.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"sync"
	"time"

	"github.com/google/syzkaller/pkg/cover"
	"github.com/google/syzkaller/pkg/ipc"
	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/prog"
	_ "github.com/google/syzkaller/sys"
)

var (
	flagOS        = flag.String("os", runtime.GOOS, "target os")
	flagArch      = flag.String("arch", runtime.GOARCH, "target arch")
	flagCoverFile = flag.String("coverfile", "", "write coverage to the file")
	flagRepeat    = flag.Int("repeat", 1, "repeat execution that many times (0 for infinite loop)")
	flagProcs     = flag.Int("procs", 1, "number of parallel processes to execute programs")
	flagOutput    = flag.String("output", "none", "write programs to none/stdout")
	flagFaultCall = flag.Int("fault_call", -1, "inject fault into this call (0-based)")
	flagFaultNth  = flag.Int("fault_nth", 0, "inject fault on n-th operation (0-based)")
	flagHints     = flag.Bool("hints", false, "do a hints-generation run")
)

func main() {
	flag.Parse()
	if len(flag.Args()) == 0 {
		fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs+\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

	target, err := prog.GetTarget(*flagOS, *flagArch)
	if err != nil {
		log.Fatalf("%v", err)
	}

	var entries []*prog.LogEntry
	for _, fn := range flag.Args() {
		data, err := ioutil.ReadFile(fn)
		if err != nil {
			log.Fatalf("failed to read log file: %v", err)
		}
		entries = append(entries, target.ParseLog(data)...)
	}
	log.Logf(0, "parsed %v programs", len(entries))
	if len(entries) == 0 {
		return
	}

	config, execOpts, err := ipc.DefaultConfig()
	if err != nil {
		log.Fatalf("%v", err)
	}
	if config.Flags&ipc.FlagSignal != 0 {
		execOpts.Flags |= ipc.FlagCollectCover
	}
	if *flagCoverFile != "" {
		config.Flags |= ipc.FlagSignal
		execOpts.Flags |= ipc.FlagCollectCover
		execOpts.Flags &^= ipc.FlagDedupCover
	}
	if *flagHints {
		if execOpts.Flags&ipc.FlagCollectCover != 0 {
			execOpts.Flags ^= ipc.FlagCollectCover
		}
		execOpts.Flags |= ipc.FlagCollectComps
	}

	if *flagFaultCall >= 0 {
		config.Flags |= ipc.FlagEnableFault
		execOpts.Flags |= ipc.FlagInjectFault
		execOpts.FaultCall = *flagFaultCall
		execOpts.FaultNth = *flagFaultNth
	}

	handled := make(map[string]bool)
	for _, entry := range entries {
		for _, call := range entry.P.Calls {
			handled[call.Meta.CallName] = true
		}
	}
	if handled["syz_emit_ethernet"] || handled["syz_extract_tcp_res"] {
		config.Flags |= ipc.FlagEnableTun
	}

	var wg sync.WaitGroup
	wg.Add(*flagProcs)
	var posMu, logMu sync.Mutex
	gate := ipc.NewGate(2**flagProcs, nil)
	var pos int
	var lastPrint time.Time
	shutdown := make(chan struct{})
	for p := 0; p < *flagProcs; p++ {
		pid := p
		go func() {
			defer wg.Done()
			env, err := ipc.MakeEnv(config, pid)
			if err != nil {
				log.Fatalf("failed to create ipc env: %v", err)
			}
			defer env.Close()
			for {
				if !func() bool {
					// Limit concurrency window.
					ticket := gate.Enter()
					defer gate.Leave(ticket)

					posMu.Lock()
					idx := pos
					pos++
					if idx%len(entries) == 0 && time.Since(lastPrint) > 5*time.Second {
						log.Logf(0, "executed programs: %v", idx)
						lastPrint = time.Now()
					}
					posMu.Unlock()
					if *flagRepeat > 0 && idx >= len(entries)**flagRepeat {
						return false
					}
					entry := entries[idx%len(entries)]
					callOpts := execOpts
					if *flagFaultCall == -1 && entry.Fault {
						newOpts := *execOpts
						newOpts.Flags |= ipc.FlagInjectFault
						newOpts.FaultCall = entry.FaultCall
						newOpts.FaultNth = entry.FaultNth
						callOpts = &newOpts
					}
					switch *flagOutput {
					case "stdout":
						strOpts := ""
						if callOpts.Flags&ipc.FlagInjectFault != 0 {
							strOpts = fmt.Sprintf(" (fault-call:%v fault-nth:%v)", callOpts.FaultCall, callOpts.FaultNth)
						}
						data := entry.P.Serialize()
						logMu.Lock()
						log.Logf(0, "executing program %v%v:\n%s", pid, strOpts, data)
						logMu.Unlock()
					}
					output, info, failed, hanged, err := env.Exec(callOpts, entry.P)
					select {
					case <-shutdown:
						return false
					default:
					}
					if failed {
						log.Logf(0, "BUG: executor-detected bug:\n%s", output)
					}
					if config.Flags&ipc.FlagDebug != 0 || err != nil {
						log.Logf(0, "result: failed=%v hanged=%v err=%v\n\n%s",
							failed, hanged, err, output)
					}
					if len(info) != 0 {
						log.Logf(1, "RESULT: signal %v, coverage %v errno %v",
							len(info[0].Signal), len(info[0].Cover), info[0].Errno)
					} else {
						log.Logf(1, "RESULT: no calls executed")
					}
					if *flagCoverFile != "" {
						for i, inf := range info {
							log.Logf(0, "call #%v: signal %v, coverage %v",
								i, len(inf.Signal), len(inf.Cover))
							if len(inf.Cover) == 0 {
								continue
							}
							buf := new(bytes.Buffer)
							for _, pc := range inf.Cover {
								fmt.Fprintf(buf, "0x%x\n", cover.RestorePC(pc, 0xffffffff))
							}
							err := osutil.WriteFile(fmt.Sprintf("%v.%v", *flagCoverFile, i), buf.Bytes())
							if err != nil {
								log.Fatalf("failed to write coverage file: %v", err)
							}
						}
					}
					if *flagHints {
						ncomps, ncandidates := 0, 0
						for i := range entry.P.Calls {
							if *flagOutput == "stdout" {
								fmt.Printf("call %v:\n", i)
							}
							comps := info[i].Comps
							for v, args := range comps {
								ncomps += len(args)
								if *flagOutput == "stdout" {
									fmt.Printf("comp 0x%x:", v)
									for arg := range args {
										fmt.Printf(" 0x%x", arg)
									}
									fmt.Printf("\n")
								}
							}
							entry.P.MutateWithHints(i, comps, func(p *prog.Prog) {
								ncandidates++
								if *flagOutput == "stdout" {
									log.Logf(1, "PROGRAM:\n%s", p.Serialize())
								}
							})
						}
						log.Logf(0, "ncomps=%v ncandidates=%v", ncomps, ncandidates)
					}
					return true
				}() {
					return
				}
			}
		}()
	}

	osutil.HandleInterrupts(shutdown)
	wg.Wait()
}
<commit_msg>tools/syz-execprog: split overly large function<commit_after>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// execprog executes a single program or a set of programs
// and optionally prints information about execution.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"sync"
	"time"

	"github.com/google/syzkaller/pkg/cover"
	"github.com/google/syzkaller/pkg/ipc"
	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/prog"
	_ "github.com/google/syzkaller/sys"
)

var (
	flagOS        = flag.String("os", runtime.GOOS, "target os")
	flagArch      = flag.String("arch", runtime.GOARCH, "target arch")
	flagCoverFile = flag.String("coverfile", "", "write coverage to the file")
	flagRepeat    = flag.Int("repeat", 1, "repeat execution that many times (0 for infinite loop)")
	flagProcs     = flag.Int("procs", 1, "number of parallel processes to execute programs")
	flagOutput    = flag.String("output", "none", "write programs to none/stdout")
	flagFaultCall = flag.Int("fault_call", -1, "inject fault into this call (0-based)")
	flagFaultNth  = flag.Int("fault_nth", 0, "inject fault on n-th operation (0-based)")
	flagHints     = flag.Bool("hints", false, "do a hints-generation run")
)

func main() {
	flag.Parse()
	if len(flag.Args()) == 0 {
		fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs+\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

	target, err := prog.GetTarget(*flagOS, *flagArch)
	if err != nil {
		log.Fatalf("%v", err)
	}

	entries := loadPrograms(target, flag.Args())
	if len(entries) == 0 {
		return
	}

	config, execOpts := createConfig(entries)

	var wg sync.WaitGroup
	wg.Add(*flagProcs)
	var posMu, logMu sync.Mutex
	gate := ipc.NewGate(2**flagProcs, nil)
	var pos int
	var lastPrint time.Time
	shutdown := make(chan struct{})
	for p := 0; p < *flagProcs; p++ {
		pid := p
		go func() {
			defer wg.Done()
			env, err := ipc.MakeEnv(config, pid)
			if err != nil {
				log.Fatalf("failed to create ipc env: %v", err)
			}
			defer env.Close()
			for {
				if !func() bool {
					// Limit concurrency window.
					ticket := gate.Enter()
					defer gate.Leave(ticket)

					posMu.Lock()
					idx := pos
					pos++
					if idx%len(entries) == 0 && time.Since(lastPrint) > 5*time.Second {
						log.Logf(0, "executed programs: %v", idx)
						lastPrint = time.Now()
					}
					posMu.Unlock()
					if *flagRepeat > 0 && idx >= len(entries)**flagRepeat {
						return false
					}
					entry := entries[idx%len(entries)]
					callOpts := execOpts
					if *flagFaultCall == -1 && entry.Fault {
						newOpts := *execOpts
						newOpts.Flags |= ipc.FlagInjectFault
						newOpts.FaultCall = entry.FaultCall
						newOpts.FaultNth = entry.FaultNth
						callOpts = &newOpts
					}
					switch *flagOutput {
					case "stdout":
						strOpts := ""
						if callOpts.Flags&ipc.FlagInjectFault != 0 {
							strOpts = fmt.Sprintf(" (fault-call:%v fault-nth:%v)", callOpts.FaultCall, callOpts.FaultNth)
						}
						data := entry.P.Serialize()
						logMu.Lock()
						log.Logf(0, "executing program %v%v:\n%s", pid, strOpts, data)
						logMu.Unlock()
					}
					output, info, failed, hanged, err := env.Exec(callOpts, entry.P)
					select {
					case <-shutdown:
						return false
					default:
					}
					if failed {
						log.Logf(0, "BUG: executor-detected bug:\n%s", output)
					}
					if config.Flags&ipc.FlagDebug != 0 || err != nil {
						log.Logf(0, "result: failed=%v hanged=%v err=%v\n\n%s",
							failed, hanged, err, output)
					}
					if len(info) != 0 {
						log.Logf(1, "RESULT: signal %v, coverage %v errno %v",
							len(info[0].Signal), len(info[0].Cover), info[0].Errno)
					} else {
						log.Logf(1, "RESULT: no calls executed")
					}
					if *flagCoverFile != "" {
						for i, inf := range info {
							log.Logf(0, "call #%v: signal %v, coverage %v",
								i, len(inf.Signal), len(inf.Cover))
							if len(inf.Cover) == 0 {
								continue
							}
							buf := new(bytes.Buffer)
							for _, pc := range inf.Cover {
								fmt.Fprintf(buf, "0x%x\n", cover.RestorePC(pc, 0xffffffff))
							}
							err := osutil.WriteFile(fmt.Sprintf("%v.%v", *flagCoverFile, i), buf.Bytes())
							if err != nil {
								log.Fatalf("failed to write coverage file: %v", err)
							}
						}
					}
					if *flagHints {
						ncomps, ncandidates := 0, 0
						for i := range entry.P.Calls {
							if *flagOutput == "stdout" {
								fmt.Printf("call %v:\n", i)
							}
							comps := info[i].Comps
							for v, args := range comps {
								ncomps += len(args)
								if *flagOutput == "stdout" {
									fmt.Printf("comp 0x%x:", v)
									for arg := range args {
										fmt.Printf(" 0x%x", arg)
									}
									fmt.Printf("\n")
								}
							}
							entry.P.MutateWithHints(i, comps, func(p *prog.Prog) {
								ncandidates++
								if *flagOutput == "stdout" {
									log.Logf(1, "PROGRAM:\n%s", p.Serialize())
								}
							})
						}
						log.Logf(0, "ncomps=%v ncandidates=%v", ncomps, ncandidates)
					}
					return true
				}() {
					return
				}
			}
		}()
	}

	osutil.HandleInterrupts(shutdown)
	wg.Wait()
}

func loadPrograms(target *prog.Target, files []string) []*prog.LogEntry {
	var entries []*prog.LogEntry
	for _, fn := range files {
		data, err := ioutil.ReadFile(fn)
		if err != nil {
			log.Fatalf("failed to read log file: %v", err)
		}
		entries = append(entries, target.ParseLog(data)...)
	}
	log.Logf(0, "parsed %v programs", len(entries))
	return entries
}

func createConfig(entries []*prog.LogEntry) (*ipc.Config, *ipc.ExecOpts) {
	config, execOpts, err := ipc.DefaultConfig()
	if err != nil {
		log.Fatalf("%v", err)
	}
	if config.Flags&ipc.FlagSignal != 0 {
		execOpts.Flags |= ipc.FlagCollectCover
	}
	if *flagCoverFile != "" {
		config.Flags |= ipc.FlagSignal
		execOpts.Flags |= ipc.FlagCollectCover
		execOpts.Flags &^= ipc.FlagDedupCover
	}
	if *flagHints {
		if execOpts.Flags&ipc.FlagCollectCover != 0 {
			execOpts.Flags ^= ipc.FlagCollectCover
		}
		execOpts.Flags |= ipc.FlagCollectComps
	}
	if *flagFaultCall >= 0 {
		config.Flags |= ipc.FlagEnableFault
		execOpts.Flags |= ipc.FlagInjectFault
		execOpts.FaultCall = *flagFaultCall
		execOpts.FaultNth = *flagFaultNth
	}
	handled := make(map[string]bool)
	for _, entry := range entries {
		for _, call := range entry.P.Calls {
			handled[call.Meta.CallName] = true
		}
	}
	if handled["syz_emit_ethernet"] || handled["syz_extract_tcp_res"] {
		config.Flags |= ipc.FlagEnableTun
	}
	return config, execOpts
}
<|endoftext|>


<commit_before>package jamon

import (
	"bufio"
	"os"
	"strings"
)

// A configuration type may hold multiple categories of settings
type Config map[string]Category

// A category holds key-value pairs of settings
type Category map[string]string

// Loads a configuration file
func Load(filename string) (Config, error) {
	file, err := os.Open(filename)
	if err != nil {
		return Config{}, err
	}

	fr := bufio.NewReader(file)

	config := Config{}
	currentCategory := "JAMON.NO_CATEGORY"

	for {
		line_bytes, _, err := fr.ReadLine()
		if err != nil {
			break
		}

		isCategory, value, key, skip := parseLine(string(line_bytes))

		switch {
		case skip:
			continue

		case isCategory:
			currentCategory = value
			continue

		case config[currentCategory] == nil:
			config[currentCategory] = make(Category)
		}

		config[currentCategory][key] = value
	}

	return config, nil
}

// Attempts to parse an entry in the config file. The first return value specifies
// whether 'value' is the name of a category or the value of a key.
func parseLine(line string) (isCategory bool, value, key string, skip bool) {
	line = strings.Trim(strings.SplitN(line, "#", 2)[0], " \t\r\n")

	// Is comment?
	if strings.HasPrefix(line, "#") || len(line) == 0 {
		skip = true
		return
	}

	// Is category?
	if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
		isCategory = true
		value = strings.Trim(line, "[]")
		return
	}

	// Attempt to parse key/value pair
	parts := strings.SplitN(line, "=", 2)
	if len(parts) < 2 {
		skip = true
		return
	}

	// Trim end-of-line comments
	key = parts[0]
	value = strings.TrimRight(parts[1], " ")

	return
}

// Returns the value of a key that is not in any category. These keys should
// be placed at the top of the file with no title if desired.
func (c Config) Get(key string) string {
	category, ok := c["JAMON.NO_CATEGORY"]
	if !ok {
		return ""
	}

	return category.Get(key)
}

// Returns a category by name. If the category does not exist, an empty category
// is returned. Errors are not returned here in order to allow chaining.
func (c Config) Category(name string) Category { return c[name] }

// Returns a key from a category
func (c Category) Get(key string) string { return c[key] }
<commit_msg>For switch lets switch<commit_after>package jamon

import (
	"bufio"
	"os"
	"strings"
)

// A configuration type may hold multiple categories of settings
type Config map[string]Category

// A category holds key-value pairs of settings
type Category map[string]string

// Loads a configuration file
func Load(filename string) (Config, error) {
	file, err := os.Open(filename)
	if err != nil {
		return Config{}, err
	}

	fr := bufio.NewReader(file)

	config := Config{}
	currentCategory := "JAMON.NO_CATEGORY"

	for {
		line_bytes, _, err := fr.ReadLine()
		if err != nil {
			break
		}

		isCategory, value, key, skip := parseLine(string(line_bytes))

		switch {
		case skip:
			continue

		case isCategory:
			currentCategory = value
			continue

		case config[currentCategory] == nil:
			config[currentCategory] = make(Category)
			fallthrough
		default:
			config[currentCategory][key] = value
		}
	}

	return config, nil
}

// Attempts to parse an entry in the config file. The first return value specifies
// whether 'value' is the name of a category or the value of a key.
func parseLine(line string) (isCategory bool, value, key string, skip bool) {
	line = strings.Trim(strings.SplitN(line, "#", 2)[0], " \t\r\n")

	// Is comment?
	if strings.HasPrefix(line, "#") || len(line) == 0 {
		skip = true
		return
	}

	// Is category?
	if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
		isCategory = true
		value = strings.Trim(line, "[]")
		return
	}

	// Attempt to parse key/value pair
	parts := strings.SplitN(line, "=", 2)
	if len(parts) < 2 {
		skip = true
		return
	}

	// Trim end-of-line comments
	key = parts[0]
	value = strings.TrimRight(parts[1], " ")

	return
}

// Returns the value of a key that is not in any category. These keys should
// be placed at the top of the file with no title if desired.
func (c Config) Get(key string) string {
	category, ok := c["JAMON.NO_CATEGORY"]
	if !ok {
		return ""
	}

	return category.Get(key)
}

// Returns a category by name. If the category does not exist, an empty category
// is returned. Errors are not returned here in order to allow chaining.
func (c Config) Category(name string) Category { return c[name] }

// Returns a key from a category
func (c Category) Get(key string) string { return c[key] }
<|endoftext|>


<commit_before>package jcapi

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

const (
	responseSize = 256 * 1024
	stdUrlBase   = "https://console.jumpcloud.com/api"
)

type JCOp uint8

const (
	Read   = 1
	Insert = 2
	Update = 3
	Delete = 4
	List   = 5
)

type JCAPI struct {
	ApiKey  string
	UrlBase string
}

const (
	searchLimit        int = 1000
	searchSkipInterval int = 1000
)

type JCError interface {
	Error() string
}

type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}

func NewJCAPI(apiKey string, urlBase string) JCAPI {
	return JCAPI{
		ApiKey:  apiKey,
		UrlBase: urlBase,
	}
}

func buildJSONStringArray(field string, s []string) string {
	returnVal := "["

	if s != nil {
		afterFirst := false

		for _, val := range s {
			if afterFirst {
				returnVal += ","
			}

			returnVal += "\"" + val + "\""

			afterFirst = true
		}
	}
	returnVal += "]"

	return "\"" + field + "\":" + returnVal
}

func buildJSONKeyValuePair(key, value string) string {
	return "\"" + key + "\":\"" + value + "\""
}

func buildJSONKeyValueBoolPair(key string, value bool) string {
	if value == true {
		return "\"" + key + "\":\"true\""
	} else {
		return "\"" + key + "\":\"false\""
	}

}

func getTimeString() string {
	t := time.Now()

	return t.Format(time.RFC3339)
}

func (jc JCAPI) emailFilter(email string) []byte {

	//
	// Ideally, this would be generalized to take a map[string]string
	// but, that doesn't elicit the correct JSON output for the JumpCloud
	// filters in json.Marshal()
	//
	return []byte(fmt.Sprintf("{\"filter\": [{\"email\" : \"%s\"}]}", email))
}

func (jc JCAPI) setHeader(req *http.Request) {
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("x-api-key", jc.ApiKey)
}

func (jc JCAPI) Post(url string, data []byte) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(Insert), url, data)
}

func (jc JCAPI) Put(url string, data []byte) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(Update), url, data)
}

func (jc JCAPI) Delete(url string) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(Delete), url, nil)
}

func (jc JCAPI) Get(url string) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(Read), url, nil)
}

func (jc JCAPI) List(url string) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(List), url, nil)
}

func (jc JCAPI) Do(op, url string, data []byte) (interface{}, JCError) {
	var returnVal interface{}

	fullUrl := jc.UrlBase + url

	client := &http.Client{}

	req, err := http.NewRequest(op, fullUrl, bytes.NewReader(data))
	if err != nil {
		return returnVal, fmt.Errorf("ERROR: Could not build search request: '%s'", err)
	}

	jc.setHeader(req)

	resp, err := client.Do(req)
	if err != nil {
		return returnVal, fmt.Errorf("ERROR: client.Do() failed, err='%s'", err)
	}

	defer resp.Body.Close()

	if resp.Status != "200 OK" {
		return returnVal, fmt.Errorf("JumpCloud HTTP response status='%s'", resp.Status)
	}

	buffer, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return returnVal, fmt.Errorf("ERROR: Could not read the response body, err='%s'", err)
	}

	err = json.Unmarshal(buffer, &returnVal)
	if err != nil {
		return returnVal, fmt.Errorf("ERROR: Could not Unmarshal JSON response, err='%s'", err)
	}

	return returnVal, err
}

// Add all the tags of which the user is a part to the JCUser object
func (user *JCUser) AddJCTags(tags []JCTag) {
	for _, tag := range tags {
		for _, systemUser := range tag.SystemUsers {
			if systemUser == user.Id {
				user.Tags = append(user.Tags, tag)
			}
		}
	}
}

func MapJCOpToHTTP(op JCOp) string {
	var returnVal string

	switch op {
	case Read:
		returnVal = "GET"
	case Insert:
		returnVal = "POST"
	case Update:
		returnVal = "PUT"
	case Delete:
		returnVal = "DELETE"
	case List:
		returnVal = "LIST"
	}

	return returnVal
}

//
// Interface Conversion Helper Functions
//
func (jc JCAPI) extractStringArray(input []interface{}) []string {
	var returnVal []string

	for _, str := range input {
		returnVal = append(returnVal, str.(string))
	}

	return returnVal
}

func getStringOrNil(input interface{}) string {
	returnVal := ""

	switch input.(type) {
	case string:
		returnVal = input.(string)
	}

	return returnVal
}

func getUint16OrNil(input interface{}) uint16 {
	var returnVal uint16

	switch input.(type) {
	case uint16:
		returnVal = input.(uint16)
	}

	return returnVal
}
<commit_msg>Changed JCOp definitions to vars to expose them to external packages<commit_after>package jcapi

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

const (
	responseSize = 256 * 1024
	stdUrlBase   = "https://console.jumpcloud.com/api"
)

type JCOp uint8

var (
	Read   JCOp = 1
	Insert JCOp = 2
	Update JCOp = 3
	Delete JCOp = 4
	List   JCOp = 5
)

type JCAPI struct {
	ApiKey  string
	UrlBase string
}

const (
	searchLimit        int = 1000
	searchSkipInterval int = 1000
)

type JCError interface {
	Error() string
}

type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}

func NewJCAPI(apiKey string, urlBase string) JCAPI {
	return JCAPI{
		ApiKey:  apiKey,
		UrlBase: urlBase,
	}
}

func buildJSONStringArray(field string, s []string) string {
	returnVal := "["

	if s != nil {
		afterFirst := false

		for _, val := range s {
			if afterFirst {
				returnVal += ","
			}

			returnVal += "\"" + val + "\""

			afterFirst = true
		}
	}
	returnVal += "]"

	return "\"" + field + "\":" + returnVal
}

func buildJSONKeyValuePair(key, value string) string {
	return "\"" + key + "\":\"" + value + "\""
}

func buildJSONKeyValueBoolPair(key string, value bool) string {
	if value == true {
		return "\"" + key + "\":\"true\""
	} else {
		return "\"" + key + "\":\"false\""
	}

}

func getTimeString() string {
	t := time.Now()

	return t.Format(time.RFC3339)
}

func (jc JCAPI) emailFilter(email string) []byte {

	//
	// Ideally, this would be generalized to take a map[string]string
	// but, that doesn't elicit the correct JSON output for the JumpCloud
	// filters in json.Marshal()
	//
	return []byte(fmt.Sprintf("{\"filter\": [{\"email\" : \"%s\"}]}", email))
}

func (jc JCAPI) setHeader(req *http.Request) {
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("x-api-key", jc.ApiKey)
}

func (jc JCAPI) Post(url string, data []byte) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(Insert), url, data)
}

func (jc JCAPI) Put(url string, data []byte) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(Update), url, data)
}

func (jc JCAPI) Delete(url string) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(Delete), url, nil)
}

func (jc JCAPI) Get(url string) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(Read), url, nil)
}

func (jc JCAPI) List(url string) (interface{}, JCError) {
	return jc.Do(MapJCOpToHTTP(List), url, nil)
}

func (jc JCAPI) Do(op, url string, data []byte) (interface{}, JCError) {
	var returnVal interface{}

	fullUrl := jc.UrlBase + url

	client := &http.Client{}

	req, err := http.NewRequest(op, fullUrl, bytes.NewReader(data))
	if err != nil {
		return returnVal, fmt.Errorf("ERROR: Could not build search request: '%s'", err)
	}

	jc.setHeader(req)

	resp, err := client.Do(req)
	if err != nil {
		return returnVal, fmt.Errorf("ERROR: client.Do() failed, err='%s'", err)
	}

	defer resp.Body.Close()

	if resp.Status != "200 OK" {
		return returnVal, fmt.Errorf("JumpCloud HTTP response status='%s'", resp.Status)
	}

	buffer, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return returnVal, fmt.Errorf("ERROR: Could not read the response body, err='%s'", err)
	}

	err = json.Unmarshal(buffer, &returnVal)
	if err != nil {
		return returnVal, fmt.Errorf("ERROR: Could not Unmarshal JSON response, err='%s'", err)
	}

	return returnVal, err
}

// Add all the tags of which the user is a part to the JCUser object
func (user *JCUser) AddJCTags(tags []JCTag) {
	for _, tag := range tags {
		for _, systemUser := range tag.SystemUsers {
			if systemUser == user.Id {
				user.Tags = append(user.Tags, tag)
			}
		}
	}
}

func MapJCOpToHTTP(op JCOp) string {
	var returnVal string

	switch op {
	case Read:
		returnVal = "GET"
	case Insert:
		returnVal = "POST"
	case Update:
		returnVal = "PUT"
	case Delete:
		returnVal = "DELETE"
	case List:
		returnVal = "LIST"
	}

	return returnVal
}

//
// Interface Conversion Helper Functions
//
func (jc JCAPI) extractStringArray(input []interface{}) []string {
	var returnVal []string

	for _, str := range input {
		returnVal = append(returnVal, str.(string))
	}

	return returnVal
}

func getStringOrNil(input interface{}) string {
	returnVal := ""

	switch input.(type) {
	case string:
		returnVal = input.(string)
	}

	return returnVal
}

func getUint16OrNil(input interface{}) uint16 {
	var returnVal uint16

	switch input.(type) {
	case uint16:
		returnVal = input.(uint16)
	}

	return returnVal
}
<|endoftext|>