<commit_before>package tests

import (
	"math/rand"
	"socialapi/models"
	"socialapi/rest"
	"socialapi/workers/common/tests"
	"strconv"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
	"labix.org/v2/mgo/bson"
)

func TestTrollModeSetting(t *testing.T) {
	var AccountOldId = bson.NewObjectId()

	Convey("while testing troll mode", t, func() {
		Convey("First Create User", func() {
			account := models.NewAccount()
			account.OldId = AccountOldId.Hex()
			account, err := rest.CreateAccount(account)
			tests.ResultedWithNoErrorCheck(account, err)

			Convey("then we should be able to mark as troll", func() {
				res := rest.MarkAsTroll(account)
				So(res, ShouldBeNil)
				Convey("sholdnt be able to mark as troll twice", func() {
					res := rest.MarkAsTroll(account)
					So(res, ShouldNotBeNil)
				})
			})

			Convey("should be able to unmark as troll", func() {
				res := rest.UnMarkAsTroll(account)
				So(res, ShouldBeNil)
				Convey("should not be able to unmark as troll twice", func() {
					res := rest.UnMarkAsTroll(account)
					So(res, ShouldNotBeNil)
				})
			})
		})
	})
}

func TestTrollModeActivityFeed(t *testing.T) {
	Convey("while testing troll mode activity listing", t, func() {
		var adminUserOldId = bson.NewObjectId()
		var normalUserOldId1 = bson.NewObjectId()
		var normalUserOldId2 = bson.NewObjectId()
		var trollUserOldId = bson.NewObjectId()

		adminUser := models.NewAccount()
		adminUser.OldId = adminUserOldId.Hex()
		adminUser, err := rest.CreateAccount(adminUser)
		tests.ResultedWithNoErrorCheck(adminUser, err)

		normalUser1 := models.NewAccount()
		normalUser1.OldId = normalUserOldId1.Hex()
		normalUser1, err = rest.CreateAccount(normalUser1)
		tests.ResultedWithNoErrorCheck(normalUser1, err)

		normalUser2 := models.NewAccount()
		normalUser2.OldId = normalUserOldId2.Hex()
		normalUser2, err = rest.CreateAccount(normalUser2)
		tests.ResultedWithNoErrorCheck(normalUser2, err)

		trollUser := models.NewAccount()
		trollUser.OldId = trollUserOldId.Hex()
		trollUser, err = rest.CreateAccount(trollUser)
		tests.ResultedWithNoErrorCheck(trollUser, err)

		So(rest.MarkAsTroll(trollUser), ShouldBeNil)

		rand.Seed(time.Now().UnixNano())
		groupName := "testgroup" + strconv.FormatInt(rand.Int63(), 10)
		groupChannel, err := rest.CreateChannelByGroupNameAndType(
			adminUser.Id,
			groupName,
			models.Channel_TYPE_GROUP,
		)

		tests.ResultedWithNoErrorCheck(groupChannel, err)

		Convey("troll users should be able to post status update", func() {
			Convey("troll users should be able to see his status update", func() {
				// create post
				post, err := rest.CreatePost(groupChannel.Id, trollUser.Id)
				tests.ResultedWithNoErrorCheck(post, err)

				history, err := rest.GetHistory(groupChannel.Id, trollUser.Id)
				tests.ResultedWithNoErrorCheck(history, err)
				So(len(history.MessageList), ShouldEqual, 1)
			})
			Convey("normal user should not be able to see troll's status update", func() {
				// create post
				post, err := rest.CreatePost(groupChannel.Id, trollUser.Id)
				tests.ResultedWithNoErrorCheck(post, err)

				history, err := rest.GetHistory(groupChannel.Id, normalUser1.Id)
				tests.ResultedWithNoErrorCheck(history, err)
				// to-do remove this check
				So(len(history.MessageList), ShouldEqual, 2)
				// So(len(history.MessageList), ShouldEqual, 0)
			})
		})

		Convey("should be able to unmark as troll", func() {})
	})
}
<commit_msg>social; style fixes<commit_after>package tests

import (
	"math/rand"
	"socialapi/models"
	"socialapi/rest"
	"socialapi/workers/common/tests"
	"strconv"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
	"labix.org/v2/mgo/bson"
)

func TestTrollModeSetting(t *testing.T) {
	var AccountOldId = bson.NewObjectId()
	Convey("while testing troll mode", t, func() {
		Convey("First Create User", func() {
			account := models.NewAccount()
			account.OldId = AccountOldId.Hex()
			account, err := rest.CreateAccount(account)
			tests.ResultedWithNoErrorCheck(account, err)

			Convey("then we should be able to mark as troll", func() {
				res := rest.MarkAsTroll(account)
				So(res, ShouldBeNil)
				Convey("sholdnt be able to mark as troll twice", func() {
					res := rest.MarkAsTroll(account)
					So(res, ShouldNotBeNil)
				})
			})

			Convey("should be able to unmark as troll", func() {
				res := rest.UnMarkAsTroll(account)
				So(res, ShouldBeNil)
				Convey("should not be able to unmark as troll twice", func() {
					res := rest.UnMarkAsTroll(account)
					So(res, ShouldNotBeNil)
				})
			})
		})
	})
}

func TestTrollModeActivityFeed(t *testing.T) {
	Convey("while testing troll mode activity listing", t, func() {
		var adminUserOldId = bson.NewObjectId()
		var normalUserOldId1 = bson.NewObjectId()
		var normalUserOldId2 = bson.NewObjectId()
		var trollUserOldId = bson.NewObjectId()

		adminUser := models.NewAccount()
		adminUser.OldId = adminUserOldId.Hex()
		adminUser, err := rest.CreateAccount(adminUser)
		tests.ResultedWithNoErrorCheck(adminUser, err)

		normalUser1 := models.NewAccount()
		normalUser1.OldId = normalUserOldId1.Hex()
		normalUser1, err = rest.CreateAccount(normalUser1)
		tests.ResultedWithNoErrorCheck(normalUser1, err)

		normalUser2 := models.NewAccount()
		normalUser2.OldId = normalUserOldId2.Hex()
		normalUser2, err = rest.CreateAccount(normalUser2)
		tests.ResultedWithNoErrorCheck(normalUser2, err)

		trollUser := models.NewAccount()
		trollUser.OldId = trollUserOldId.Hex()
		trollUser, err = rest.CreateAccount(trollUser)
		tests.ResultedWithNoErrorCheck(trollUser, err)

		So(rest.MarkAsTroll(trollUser), ShouldBeNil)

		rand.Seed(time.Now().UnixNano())
		groupName := "testgroup" + strconv.FormatInt(rand.Int63(), 10)
		groupChannel, err := rest.CreateChannelByGroupNameAndType(
			adminUser.Id,
			groupName,
			models.Channel_TYPE_GROUP,
		)

		tests.ResultedWithNoErrorCheck(groupChannel, err)

		Convey("troll users should be able to post status update", func() {
			Convey("troll users should be able to see his status update", func() {
				// create post
				post, err := rest.CreatePost(groupChannel.Id, trollUser.Id)
				tests.ResultedWithNoErrorCheck(post, err)

				history, err := rest.GetHistory(groupChannel.Id, trollUser.Id)
				tests.ResultedWithNoErrorCheck(history, err)
				So(len(history.MessageList), ShouldEqual, 1)
			})
			Convey("normal user should not be able to see troll's status update", func() {
				// create post
				post, err := rest.CreatePost(groupChannel.Id, trollUser.Id)
				tests.ResultedWithNoErrorCheck(post, err)

				history, err := rest.GetHistory(groupChannel.Id, normalUser1.Id)
				tests.ResultedWithNoErrorCheck(history, err)
				// to-do remove this check
				So(len(history.MessageList), ShouldEqual, 2)
				// So(len(history.MessageList), ShouldEqual, 0)
			})
		})

		Convey("should be able to unmark as troll", func() {})
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

package cloudup

import (
	"fmt"
	"net/url"

	"github.com/blang/semver/v4"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/assets"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/util/pkg/architectures"
	"k8s.io/kops/util/pkg/hashing"
)

const (
	// containerd packages URLs for v1.4.x+
	containerdVersionUrlAmd64 = "https://github.com/containerd/containerd/releases/download/v%s/cri-containerd-cni-%s-linux-amd64.tar.gz"
	// containerd packages URLs for v1.6.x (ARM64)+
	containerdVersionUrlArm64 = "https://github.com/containerd/containerd/releases/download/v%s/cri-containerd-cni-%s-linux-arm64.tar.gz"
	// containerd legacy packages URLs for v1.2.x and v1.3.x
	containerdLegacyUrlAmd64 = "https://storage.googleapis.com/cri-containerd-release/cri-containerd-%s.linux-amd64.tar.gz"
	// containerd version that is available for both AMD64 and ARM64, used in case the selected version is not available for ARM64
	containerdFallbackVersion = "1.4.11"
)

func findContainerdAsset(c *kops.Cluster, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*url.URL, *hashing.Hash, error) {
	if c.Spec.Containerd == nil {
		return nil, nil, fmt.Errorf("unable to find containerd config")
	}
	containerd := c.Spec.Containerd

	if containerd.Packages != nil {
		if arch == architectures.ArchitectureAmd64 && containerd.Packages.UrlAmd64 != nil && containerd.Packages.HashAmd64 != nil {
			assetUrl := fi.StringValue(containerd.Packages.UrlAmd64)
			assetHash := fi.StringValue(containerd.Packages.HashAmd64)
			return findAssetsUrlHash(assetBuilder, assetUrl, assetHash)
		}
		if arch == architectures.ArchitectureArm64 && containerd.Packages.UrlArm64 != nil && containerd.Packages.HashArm64 != nil {
			assetUrl := fi.StringValue(containerd.Packages.UrlArm64)
			assetHash := fi.StringValue(containerd.Packages.HashArm64)
			return findAssetsUrlHash(assetBuilder, assetUrl, assetHash)
		}
	}

	version := fi.StringValue(containerd.Version)
	if version == "" {
		return nil, nil, fmt.Errorf("unable to find containerd version")
	}
	assetUrl, assetHash, err := findContainerdVersionUrlHash(arch, version)
	if err != nil {
		return nil, nil, err
	}

	return findAssetsUrlHash(assetBuilder, assetUrl, assetHash)
}

func findContainerdVersionUrlHash(arch architectures.Architecture, version string) (u string, h string, e error) {
	var containerdAssetUrl, containerdAssetHash string

	if findAllContainerdHashesAmd64()[version] != "" {
		var err error
		containerdAssetUrl, err = findContainerdVersionUrl(arch, version)
		if err != nil {
			return "", "", err
		}
		containerdAssetHash, err = findContainerdVersionHash(arch, version)
		if err != nil {
			return "", "", err
		}
	} else {
		// Fall back to Docker packages
		dv := findAllContainerdDockerMappings()[version]
		if dv != "" {
			var err error
			containerdAssetUrl, err = findDockerVersionUrl(arch, dv)
			if err != nil {
				return "", "", err
			}
			containerdAssetHash, err = findDockerVersionHash(arch, dv)
			if err != nil {
				return "", "", err
			}
			println(dv)
		} else {
			return "", "", fmt.Errorf("unknown url and hash for containerd version: %s - %s", arch, version)
		}
	}

	return containerdAssetUrl, containerdAssetHash, nil
}

func findContainerdVersionUrl(arch architectures.Architecture, version string) (string, error) {
	sv, err := semver.ParseTolerant(version)
	if err != nil {
		return "", fmt.Errorf("unable to parse version string: %q", version)
	}
	if sv.LT(semver.MustParse("1.3.4")) {
		return "", fmt.Errorf("unsupported legacy containerd version: %q", version)
	}

	var u string
	switch arch {
	case architectures.ArchitectureAmd64:
		if sv.GTE(semver.MustParse("1.3.8")) {
			u = fmt.Sprintf(containerdVersionUrlAmd64, version, version)
		} else {
			u = fmt.Sprintf(containerdLegacyUrlAmd64, version)
		}
	case architectures.ArchitectureArm64:
		if sv.GTE(semver.MustParse("1.6.0-beta.2")) {
			u = fmt.Sprintf(containerdVersionUrlArm64, version, version)
		} else if findAllContainerdHashesAmd64()[version] != "" {
			if findAllContainerdDockerMappings()[version] != "" {
				u = fmt.Sprintf(dockerVersionUrlArm64, findAllContainerdDockerMappings()[version])
			} else {
				u = fmt.Sprintf(dockerVersionUrlArm64, findAllContainerdDockerMappings()[containerdFallbackVersion])
			}
		}
	default:
		return "", fmt.Errorf("unknown arch: %q", arch)
	}

	if u == "" {
		return "", fmt.Errorf("unknown url for containerd version: %s - %s", arch, version)
	}

	return u, nil
}

func findContainerdVersionHash(arch architectures.Architecture, version string) (string, error) {
	sv, err := semver.ParseTolerant(version)
	if err != nil {
		return "", fmt.Errorf("unable to parse version string: %q", version)
	}
	if sv.LT(semver.MustParse("1.3.4")) {
		return "", fmt.Errorf("unsupported legacy containerd version: %q", version)
	}

	var h string
	switch arch {
	case architectures.ArchitectureAmd64:
		h = findAllContainerdHashesAmd64()[version]
	case architectures.ArchitectureArm64:
		if sv.GTE(semver.MustParse("1.6.0-beta.2")) {
			h = findAllContainerdHashesArm64()[version]
		} else if findAllContainerdHashesAmd64()[version] != "" {
			if findAllContainerdDockerMappings()[version] != "" {
				h = findAllDockerHashesArm64()[findAllContainerdDockerMappings()[version]]
			} else {
				h = findAllDockerHashesArm64()[findAllContainerdDockerMappings()[containerdFallbackVersion]]
			}
		}
	default:
		return "", fmt.Errorf("unknown arch: %q", arch)
	}

	if h == "" {
		return "", fmt.Errorf("unknown hash for containerd version: %s - %s", arch, version)
	}

	return h, nil
}

func findAllContainerdHashesAmd64() map[string]string {
	hashes := map[string]string{
		"1.3.4":        "4616971c3ad21c24f2f2320fa1c085577a91032a068dd56a41c7c4b71a458087",
		"1.3.9":        "96663699e0f888fbf232ae6629a367aa7421f6b95044e7ee5d4d4e02841fac75",
		"1.3.10":       "69e23e49cdf1232d475a77bf7ecd7145ff4a80295154e190125c4d8a20e241da",
		"1.4.0":        "b379f29417efd583f77e095173d4d0bd6bb001f0081b2a63d152ee7aef653ce1",
		"1.4.1":        "757efb93a4f3161efc447a943317503d8a7ded5cb4cc0cba3f3318d7ce1542ed",
		"1.4.2":        "9d0fd5f4d2bc58b345728432b7daac75fc99c1da91afa4f41e6103f618e74012",
		"1.4.3":        "2697a342e3477c211ab48313e259fd7e32ad1f5ded19320e6a559f50a82bff3d",
		"1.4.4":        "96641849cb78a0a119223a427dfdc1ade88412ef791a14193212c8c8e29d447b",
		"1.4.5":        "f8155278fd256526ca9804219e1ee46f5db11c6ddf455086b04c0887c868822a",
		"1.4.6":        "6ae4763598c9583f8b50605f19d6c7e9ef93c216706465e73dfc84ee6b63a238",
		"1.4.7":        "daa14638344fe0772f645e190e4d8eb9549b52743364cb8000521490f9e410b8",
		"1.4.8":        "96e815c9ab664a02dd5be35e31d15890ea6bef04dfaa39f99f14676c3d6561e8",
		"1.4.9":        "9911479f86012d6eab7e0f532da8f807a8b0f555ee09ef89367d8c31243073bb",
		"1.4.10":       "5b256b372a02fd37c84939c87a6a81cae06058a7881a60d682525c11f6dea7d1",
		"1.4.11":       "a4a4af4776316833cad5996c66d59f8b4a2af4da716b7902b7a2d5f5ac362dcc",
		"1.5.0":        "aee7b553ab88842fdafe43955757abe746b8e9995b2be55c603f0a236186ff9b",
		"1.5.1":        "2fd97916b24396c13849cfcd89805170e1ef0265a2f7fce8e74ae044a6a6a169",
		"1.5.2":        "e7adbb6c6f6e67639460579a8aa991e9ce4de2062ed36d3261e6e4865574d947",
		"1.5.3":        "32a9bf1b7ab2adbd9d2a16b17bf1aa6e61592938655adfb5114c40d527aa9be7",
		"1.5.4":        "591e4e087ea2f5007e6c64deb382df58d419b7b6922eab45a1923d843d57615f",
		"1.5.5":        "45f02cfc65db47cf088c95555906e1dcba7baf5a3fbad3d947dd6b9af476a144",
		"1.5.6":        "afc51718ebe46cb9b985edac816e63fe86c07e37d28cdd21b2c0302dec6fa7ae",
		"1.5.7":        "7fce75bab43a39d6f9efb3c370de2da49723f0e1dbaa9732d68fa7f620d720c8",
		"1.6.0-beta.2": "617044417781ea9a700187955834f712f141b37fe94f2ab173b5f7a5ed2c26a7",
	}

	return hashes
}

func findAllContainerdHashesArm64() map[string]string {
	hashes := map[string]string{
		"1.6.0-beta.2": "8c55169cce0a198265ab9b8cad1691174c5d055f6b2468d159ac8b911fa3c0ec",
	}

	return hashes
}

func findAllContainerdDockerMappings() map[string]string {
	versions := map[string]string{
		"1.3.7":  "19.03.13",
		"1.3.9":  "19.03.14",
		"1.4.3":  "20.10.0",
		"1.4.4":  "20.10.6",
		"1.4.6":  "20.10.7",
		"1.4.9":  "20.10.8",
		"1.4.11": "20.10.9",
	}

	return versions
}
<commit_msg>Add hash for containerd v1.4.12<commit_after>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

package cloudup

import (
	"fmt"
	"net/url"

	"github.com/blang/semver/v4"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/assets"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/util/pkg/architectures"
	"k8s.io/kops/util/pkg/hashing"
)

const (
	// containerd packages URLs for v1.4.x+
	containerdVersionUrlAmd64 = "https://github.com/containerd/containerd/releases/download/v%s/cri-containerd-cni-%s-linux-amd64.tar.gz"
	// containerd packages URLs for v1.6.x (ARM64)+
	containerdVersionUrlArm64 = "https://github.com/containerd/containerd/releases/download/v%s/cri-containerd-cni-%s-linux-arm64.tar.gz"
	// containerd legacy packages URLs for v1.2.x and v1.3.x
	containerdLegacyUrlAmd64 = "https://storage.googleapis.com/cri-containerd-release/cri-containerd-%s.linux-amd64.tar.gz"
	// containerd version that is available for both AMD64 and ARM64, used in case the selected version is not available for ARM64
	containerdFallbackVersion = "1.4.11"
)

func findContainerdAsset(c *kops.Cluster, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*url.URL, *hashing.Hash, error) {
	if c.Spec.Containerd == nil {
		return nil, nil, fmt.Errorf("unable to find containerd config")
	}
	containerd := c.Spec.Containerd

	if containerd.Packages != nil {
		if arch == architectures.ArchitectureAmd64 && containerd.Packages.UrlAmd64 != nil && containerd.Packages.HashAmd64 != nil {
			assetUrl := fi.StringValue(containerd.Packages.UrlAmd64)
			assetHash := fi.StringValue(containerd.Packages.HashAmd64)
			return findAssetsUrlHash(assetBuilder, assetUrl, assetHash)
		}
		if arch == architectures.ArchitectureArm64 && containerd.Packages.UrlArm64 != nil && containerd.Packages.HashArm64 != nil {
			assetUrl := fi.StringValue(containerd.Packages.UrlArm64)
			assetHash := fi.StringValue(containerd.Packages.HashArm64)
			return findAssetsUrlHash(assetBuilder, assetUrl, assetHash)
		}
	}

	version := fi.StringValue(containerd.Version)
	if version == "" {
		return nil, nil, fmt.Errorf("unable to find containerd version")
	}
	assetUrl, assetHash, err := findContainerdVersionUrlHash(arch, version)
	if err != nil {
		return nil, nil, err
	}

	return findAssetsUrlHash(assetBuilder, assetUrl, assetHash)
}

func findContainerdVersionUrlHash(arch architectures.Architecture, version string) (u string, h string, e error) {
	var containerdAssetUrl, containerdAssetHash string

	if findAllContainerdHashesAmd64()[version] != "" {
		var err error
		containerdAssetUrl, err = findContainerdVersionUrl(arch, version)
		if err != nil {
			return "", "", err
		}
		containerdAssetHash, err = findContainerdVersionHash(arch, version)
		if err != nil {
			return "", "", err
		}
	} else {
		// Fall back to Docker packages
		dv := findAllContainerdDockerMappings()[version]
		if dv != "" {
			var err error
			containerdAssetUrl, err = findDockerVersionUrl(arch, dv)
			if err != nil {
				return "", "", err
			}
			containerdAssetHash, err = findDockerVersionHash(arch, dv)
			if err != nil {
				return "", "", err
			}
			println(dv)
		} else {
			return "", "", fmt.Errorf("unknown url and hash for containerd version: %s - %s", arch, version)
		}
	}

	return containerdAssetUrl, containerdAssetHash, nil
}

func findContainerdVersionUrl(arch architectures.Architecture, version string) (string, error) {
	sv, err := semver.ParseTolerant(version)
	if err != nil {
		return "", fmt.Errorf("unable to parse version string: %q", version)
	}
	if sv.LT(semver.MustParse("1.3.4")) {
		return "", fmt.Errorf("unsupported legacy containerd version: %q", version)
	}

	var u string
	switch arch {
	case architectures.ArchitectureAmd64:
		if sv.GTE(semver.MustParse("1.3.8")) {
			u = fmt.Sprintf(containerdVersionUrlAmd64, version, version)
		} else {
			u = fmt.Sprintf(containerdLegacyUrlAmd64, version)
		}
	case architectures.ArchitectureArm64:
		if sv.GTE(semver.MustParse("1.6.0-beta.2")) {
			u = fmt.Sprintf(containerdVersionUrlArm64, version, version)
		} else if findAllContainerdHashesAmd64()[version] != "" {
			if findAllContainerdDockerMappings()[version] != "" {
				u = fmt.Sprintf(dockerVersionUrlArm64, findAllContainerdDockerMappings()[version])
			} else {
				u = fmt.Sprintf(dockerVersionUrlArm64, findAllContainerdDockerMappings()[containerdFallbackVersion])
			}
		}
	default:
		return "", fmt.Errorf("unknown arch: %q", arch)
	}

	if u == "" {
		return "", fmt.Errorf("unknown url for containerd version: %s - %s", arch, version)
	}

	return u, nil
}

func findContainerdVersionHash(arch architectures.Architecture, version string) (string, error) {
	sv, err := semver.ParseTolerant(version)
	if err != nil {
		return "", fmt.Errorf("unable to parse version string: %q", version)
	}
	if sv.LT(semver.MustParse("1.3.4")) {
		return "", fmt.Errorf("unsupported legacy containerd version: %q", version)
	}

	var h string
	switch arch {
	case architectures.ArchitectureAmd64:
		h = findAllContainerdHashesAmd64()[version]
	case architectures.ArchitectureArm64:
		if sv.GTE(semver.MustParse("1.6.0-beta.2")) {
			h = findAllContainerdHashesArm64()[version]
		} else if findAllContainerdHashesAmd64()[version] != "" {
			if findAllContainerdDockerMappings()[version] != "" {
				h = findAllDockerHashesArm64()[findAllContainerdDockerMappings()[version]]
			} else {
				h = findAllDockerHashesArm64()[findAllContainerdDockerMappings()[containerdFallbackVersion]]
			}
		}
	default:
		return "", fmt.Errorf("unknown arch: %q", arch)
	}

	if h == "" {
		return "", fmt.Errorf("unknown hash for containerd version: %s - %s", arch, version)
	}

	return h, nil
}

func findAllContainerdHashesAmd64() map[string]string {
	hashes := map[string]string{
		"1.3.4":        "4616971c3ad21c24f2f2320fa1c085577a91032a068dd56a41c7c4b71a458087",
		"1.3.9":        "96663699e0f888fbf232ae6629a367aa7421f6b95044e7ee5d4d4e02841fac75",
		"1.3.10":       "69e23e49cdf1232d475a77bf7ecd7145ff4a80295154e190125c4d8a20e241da",
		"1.4.0":        "b379f29417efd583f77e095173d4d0bd6bb001f0081b2a63d152ee7aef653ce1",
		"1.4.1":        "757efb93a4f3161efc447a943317503d8a7ded5cb4cc0cba3f3318d7ce1542ed",
		"1.4.2":        "9d0fd5f4d2bc58b345728432b7daac75fc99c1da91afa4f41e6103f618e74012",
		"1.4.3":        "2697a342e3477c211ab48313e259fd7e32ad1f5ded19320e6a559f50a82bff3d",
		"1.4.4":        "96641849cb78a0a119223a427dfdc1ade88412ef791a14193212c8c8e29d447b",
		"1.4.5":        "f8155278fd256526ca9804219e1ee46f5db11c6ddf455086b04c0887c868822a",
		"1.4.6":        "6ae4763598c9583f8b50605f19d6c7e9ef93c216706465e73dfc84ee6b63a238",
		"1.4.7":        "daa14638344fe0772f645e190e4d8eb9549b52743364cb8000521490f9e410b8",
		"1.4.8":        "96e815c9ab664a02dd5be35e31d15890ea6bef04dfaa39f99f14676c3d6561e8",
		"1.4.9":        "9911479f86012d6eab7e0f532da8f807a8b0f555ee09ef89367d8c31243073bb",
		"1.4.10":       "5b256b372a02fd37c84939c87a6a81cae06058a7881a60d682525c11f6dea7d1",
		"1.4.11":       "a4a4af4776316833cad5996c66d59f8b4a2af4da716b7902b7a2d5f5ac362dcc",
		"1.4.12":       "f6120552408175ca332fd3b5d31c5edd115d8426d6731664e4ea3951c5eee3b4",
		"1.5.0":        "aee7b553ab88842fdafe43955757abe746b8e9995b2be55c603f0a236186ff9b",
		"1.5.1":        "2fd97916b24396c13849cfcd89805170e1ef0265a2f7fce8e74ae044a6a6a169",
		"1.5.2":        "e7adbb6c6f6e67639460579a8aa991e9ce4de2062ed36d3261e6e4865574d947",
		"1.5.3":        "32a9bf1b7ab2adbd9d2a16b17bf1aa6e61592938655adfb5114c40d527aa9be7",
		"1.5.4":        "591e4e087ea2f5007e6c64deb382df58d419b7b6922eab45a1923d843d57615f",
		"1.5.5":        "45f02cfc65db47cf088c95555906e1dcba7baf5a3fbad3d947dd6b9af476a144",
		"1.5.6":        "afc51718ebe46cb9b985edac816e63fe86c07e37d28cdd21b2c0302dec6fa7ae",
		"1.5.7":        "7fce75bab43a39d6f9efb3c370de2da49723f0e1dbaa9732d68fa7f620d720c8",
		"1.6.0-beta.2": "617044417781ea9a700187955834f712f141b37fe94f2ab173b5f7a5ed2c26a7",
	}

	return hashes
}

func findAllContainerdHashesArm64() map[string]string {
	hashes := map[string]string{
		"1.6.0-beta.2": "8c55169cce0a198265ab9b8cad1691174c5d055f6b2468d159ac8b911fa3c0ec",
	}

	return hashes
}

func findAllContainerdDockerMappings() map[string]string {
	versions := map[string]string{
		"1.3.7":  "19.03.13",
		"1.3.9":  "19.03.14",
		"1.4.3":  "20.10.0",
		"1.4.4":  "20.10.6",
		"1.4.6":  "20.10.7",
		"1.4.9":  "20.10.8",
		"1.4.11": "20.10.9",
	}

	return versions
}
<|endoftext|>


<commit_before>package actions

import (
	"errors"
	"testing"
	"time"

	"github.com/gaia-docker/tugbot/container"
	"github.com/gaia-docker/tugbot/container/mockclient"
	"github.com/samalba/dockerclient"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

var stateExited = &dockerclient.State{Running: false, Dead: false, StartedAt: time.Now()}

func TestRun_StartEvent(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true", container.LabelEvents: "start"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{c}, nil)
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c.Name(), args.Get(0).(container.Container).Name())
		}).Return(nil)

	err := Run(client, []string{}, &dockerclient.Event{Status: "start"})
	assert.NoError(t, err)
	client.AssertExpectations(t)
}

func TestRun_EventCreatedByTugbot(t *testing.T) {
	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(true, nil)

	err := Run(client, []string{}, &dockerclient.Event{Status: "start"})
	assert.NoError(t, err)
	client.AssertExpectations(t)
}

func TestRun_ImageEvent(t *testing.T) {
	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(true, errors.New("container not found"))

	err := Run(client, []string{}, &dockerclient.Event{Status: "start"})
	assert.Error(t, err)
	assert.EqualError(t, err, "container not found")
	client.AssertExpectations(t)
}

func TestRun_NoCandidates(t *testing.T) {
	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{}, nil)

	Run(client, []string{}, nil)
	client.AssertExpectations(t)
}

func TestRun_ErrorListContainers(t *testing.T) {
	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{}, errors.New("whoops"))

	err := Run(client, []string{}, nil)
	assert.Error(t, err)
	assert.EqualError(t, err, "whoops")
	client.AssertExpectations(t)
}

func TestRun_ErrorStartContainerFrom(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true", container.LabelEvents: "start"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{c}, nil)
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c.Name(), args.Get(0).(container.Container).Name())
		}).Return(errors.New("whoops"))

	err := Run(client, []string{}, &dockerclient.Event{Status: "start"})
	assert.NoError(t, err)
	client.AssertExpectations(t)
}

func TestFilterName_True(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	assert.True(t, containerFilter([]string{"c1", "c", "c2"})(c))
}

func TestFilterNoName_True(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	assert.True(t, containerFilter([]string{})(c))
}

func TestFilterName_False(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	assert.False(t, containerFilter([]string{"blabla"})(c))
}

func TestFilterContainerStateRunning_False(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  &dockerclient.State{Running: true, Dead: false, StartedAt: time.Now()},
		},
		nil,
	)

	assert.False(t, containerFilter([]string{})(c))
}
<commit_msg>Added test for run call by event type;<commit_after>package actions

import (
	"errors"
	"testing"
	"time"

	"fmt"
	"github.com/gaia-docker/tugbot/container"
	"github.com/gaia-docker/tugbot/container/mockclient"
	"github.com/samalba/dockerclient"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

var stateExited = &dockerclient.State{Running: false, Dead: false, StartedAt: time.Now()}

func TestRun_StartEvent(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true", container.LabelEvents: "start"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{c}, nil)
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c.Name(), args.Get(0).(container.Container).Name())
		}).Return(nil)

	err := Run(client, []string{}, &dockerclient.Event{Status: "start"})
	assert.NoError(t, err)
	client.AssertExpectations(t)
}

func TestRun_CallByEventType(t *testing.T) {
	cc1 := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true", container.LabelEvents: "create"},
	}
	c1 := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c1",
			Config: cc1,
			State:  stateExited,
		},
		nil,
	)
	cc2 := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true", container.LabelEvents: "start"},
	}
	c2 := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c2",
			Config: cc2,
			State:  stateExited,
		},
		nil,
	)

	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{c1, c2}, nil)
	var called []string
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			called = append(called, args.Get(0).(container.Container).Name())
		}).Return(nil)

	err := Run(client, []string{c2.Name()}, &dockerclient.Event{Status: "start"})
	fmt.Println("efffi ", called)
	assert.NoError(t, err)
	assert.Equal(t, 1, len(called))
	assert.Equal(t, c2.Name(), called[0])
	client.AssertExpectations(t)
}

func TestRun_EventCreatedByTugbot(t *testing.T) {
	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(true, nil)

	err := Run(client, []string{}, &dockerclient.Event{Status: "start"})
	assert.NoError(t, err)
	client.AssertExpectations(t)
}

func TestRun_ImageEvent(t *testing.T) {
	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(true, errors.New("container not found"))

	err := Run(client, []string{}, &dockerclient.Event{Status: "start"})
	assert.Error(t, err)
	assert.EqualError(t, err, "container not found")
	client.AssertExpectations(t)
}

func TestRun_NoCandidates(t *testing.T) {
	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{}, nil)

	Run(client, []string{}, nil)
	client.AssertExpectations(t)
}

func TestRun_ErrorListContainers(t *testing.T) {
	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{}, errors.New("whoops"))

	err := Run(client, []string{}, nil)
	assert.Error(t, err)
	assert.EqualError(t, err, "whoops")
	client.AssertExpectations(t)
}

func TestRun_ErrorStartContainerFrom(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true", container.LabelEvents: "start"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	client := mockclient.NewMockClient()
	client.On("IsCreatedByTugbot", mock.AnythingOfType("*dockerclient.Event")).Return(false, nil)
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{c}, nil)
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c.Name(), args.Get(0).(container.Container).Name())
		}).Return(errors.New("whoops"))

	err := Run(client, []string{}, &dockerclient.Event{Status: "start"})
	assert.NoError(t, err)
	client.AssertExpectations(t)
}

func TestFilterName_True(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	assert.True(t, containerFilter([]string{"c1", "c", "c2"})(c))
}

func TestFilterNoName_True(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	assert.True(t, containerFilter([]string{})(c))
}

func TestFilterName_False(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	assert.False(t, containerFilter([]string{"blabla"})(c))
}

func TestFilterContainerStateRunning_False(t *testing.T) {
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{container.LabelTest: "true"},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Name:   "c",
			Config: cc,
			State:  &dockerclient.State{Running: true, Dead: false, StartedAt: time.Now()},
		},
		nil,
	)

	assert.False(t, containerFilter([]string{})(c))
}
<|endoftext|>


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

package clevergo

import (
	"fmt"
	"github.com/valyala/fasthttp"
	"os"
	"time"
)

const (
	Version = "1.0.0"
	Logo    = `  ____ _     _______     _______ ____   ____  ___
 / ___| |   | ____\ \   / / ____|  _ \ / ___|/ _ \
| |   | |   |  _|  \ \ / /|  _| | |_) | |  _| | | |
| |___| |___| |___  \ V / | |___|  _ <| |_| | |_| |
 \____|_____|_____|  \_/  |_____|_| \_\\____|\___/ `
)

func Run() {
	fmt.Printf("\x1b[33;1m%s %s\x1b[0m\n\n\x1b[32;1mStarted at %s\x1b[0m\n", Logo, Version, time.Now())
}

func ListenAndServe(addr string, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServe(addr, handler)
}

func ListenAndServeUNIX(addr string, mode os.FileMode, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServeUNIX(addr, mode, handler)
}

func ListenAndServeTLS(addr, certFile, keyFile string, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServeTLS(addr, certFile, keyFile, handler)
}

func ListenAndServeTLSEmbed(addr string, certData, keyData []byte, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServeTLSEmbed(addr, certData, keyData, handler)
}
<commit_msg>Change logo font color<commit_after>// Copyright 2016 HeadwindFly. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package clevergo

import (
	"fmt"
	"github.com/valyala/fasthttp"
	"os"
	"time"
)

const (
	Version = "1.0.0"
	Logo    = `  ____ _     _______     _______ ____   ____  ___
 / ___| |   | ____\ \   / / ____|  _ \ / ___|/ _ \
| |   | |   |  _|  \ \ / /|  _| | |_) | |  _| | | |
| |___| |___| |___  \ V / | |___|  _ <| |_| | |_| |
 \____|_____|_____|  \_/  |_____|_| \_\\____|\___/ `
)

func Run() {
	fmt.Printf("\x1b[36;1m%s %s\x1b[0m\n\n\x1b[32;1mStarted at %s\x1b[0m\n", Logo, Version, time.Now())
}

func ListenAndServe(addr string, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServe(addr, handler)
}

func ListenAndServeUNIX(addr string, mode os.FileMode, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServeUNIX(addr, mode, handler)
}

func ListenAndServeTLS(addr, certFile, keyFile string, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServeTLS(addr, certFile, keyFile, handler)
}

func ListenAndServeTLSEmbed(addr string, certData, keyData []byte, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServeTLSEmbed(addr, certData, keyData, handler)
}
<|endoftext|>


<commit_before>package cli

import (
	"regexp"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/docker/swarm/discovery"
)

func checkAddrFormat(addr string) bool {
	m, _ := regexp.MatchString("^[0-9a-zA-Z._-]+:[0-9]{1,5}$", addr)
	return m
}

func join(c *cli.Context) {
	dflag := getDiscovery(c)
	if dflag == "" {
		log.Fatalf("discovery required to join a cluster. See '%s join --help'.", c.App.Name)
	}

	addr := c.String("advertise")
	if addr == "" {
		log.Fatal("missing mandatory --advertise flag")
	}
	if !checkAddrFormat(addr) {
		log.Fatal("--advertise should be of the form ip:port or hostname:port")
	}

	hb, err := time.ParseDuration(c.String("heartbeat"))
	if err != nil {
		log.Fatalf("invalid --heartbeat: %v", err)
	}
	if hb < 1*time.Second {
		log.Fatal("--heartbeat should be at least one second")
	}
	ttl, err := time.ParseDuration(c.String("ttl"))
	if err != nil {
		log.Fatalf("invalid --ttl: %v", err)
	}
	if ttl <= hb {
		log.Fatal("--ttl must be strictly superior to the heartbeat value")
	}

	d, err := discovery.New(dflag, hb, ttl, getDiscoveryOpt(c))
	if err != nil {
		log.Fatal(err)
	}

	for {
		log.WithFields(log.Fields{"addr": addr, "discovery": dflag}).Infof("Registering on the discovery service every %s...", hb)
		if err := d.Register(addr); err != nil {
			log.Error(err)
		}
		time.Sleep(hb)
	}
}
<commit_msg>Add a random delay to avoid synchronized registration at swarm join.<commit_after>package cli

import (
	"math/rand"
	"regexp"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/docker/swarm/discovery"
)

func checkAddrFormat(addr string) bool {
	m, _ := regexp.MatchString("^[0-9a-zA-Z._-]+:[0-9]{1,5}$", addr)
	return m
}

func join(c *cli.Context) {
	dflag := getDiscovery(c)
	if dflag == "" {
		log.Fatalf("discovery required to join a cluster. See '%s join --help'.", c.App.Name)
	}

	addr := c.String("advertise")
	if addr == "" {
		log.Fatal("missing mandatory --advertise flag")
	}
	if !checkAddrFormat(addr) {
		log.Fatal("--advertise should be of the form ip:port or hostname:port")
	}

	hb, err := time.ParseDuration(c.String("heartbeat"))
	if err != nil {
		log.Fatalf("invalid --heartbeat: %v", err)
	}
	if hb < 1*time.Second {
		log.Fatal("--heartbeat should be at least one second")
	}
	ttl, err := time.ParseDuration(c.String("ttl"))
	if err != nil {
		log.Fatalf("invalid --ttl: %v", err)
	}
	if ttl <= hb {
		log.Fatal("--ttl must be strictly superior to the heartbeat value")
	}

	d, err := discovery.New(dflag, hb, ttl, getDiscoveryOpt(c))
	if err != nil {
		log.Fatal(err)
	}

	// add a random delay [0,hb) at start to avoid synchronized registration
	r := rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
	delay := time.Duration(r.Int63n(int64(hb)))
	log.Infof("Add a random delay %s to avoid synchronized registration", delay)
	time.Sleep(delay)

	for {
		log.WithFields(log.Fields{"addr": addr, "discovery": dflag}).Infof("Registering on the discovery service every %s...", hb)
		if err := d.Register(addr); err != nil {
			log.Error(err)
		}
		time.Sleep(hb)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"strconv"

	"github.com/mitchellh/colorstring"

	"github.com/yuuki1/gokc/log"
	"github.com/yuuki1/gokc/parser"
)

func setDebugOutputLevel() {
	for _, f := range os.Args {
		if f == "-D" || f == "--debug" || f == "-debug" {
			log.IsDebug = true
		}
	}

	debugEnv := os.Getenv("GOKC_DEBUG")
	if debugEnv != "" {
		showDebug, err := strconv.ParseBool(debugEnv)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error parsing boolean value from GRABENI_DEBUG: %s\n", err)
			os.Exit(1)
		}
		log.IsDebug = showDebug
	}
}

func init() {
	setDebugOutputLevel()
}

func main() {
	var filepath string
	var isVersion bool
	flag.StringVar(&filepath, "f", "", "keepalived.conf file path")
	flag.BoolVar(&isVersion, "v", false, "print the version")
	flag.Parse()

	if isVersion {
		log.Infof("gokc version %s", Version)
		os.Exit(0)
	}

	if filepath == "" {
		log.Error("filepath required")
	}

	file, err := os.Open(filepath)
	if err != nil {
		log.Error(err)
	}
	defer file.Close()

	if err := parser.Parse(file, filepath); err != nil {
		if e, ok := err.(*parser.Error); ok {
			msg := colorstring.Color(fmt.Sprintf("[white]%s:%d:%d: [red]%s[reset]", e.Filename, e.Line, e.Column, e.Message))
			log.Error(msg)
		} else {
			log.Error(err)
		}
	}

	log.Infof("gokc: the configuration file %s syntax is ok", filepath)
}
<commit_msg>Set default filepath to '/etc/keepalived/keepalived.conf'<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"strconv"

	"github.com/mitchellh/colorstring"

	"github.com/yuuki1/gokc/log"
	"github.com/yuuki1/gokc/parser"
)

func setDebugOutputLevel() {
	for _, f := range os.Args {
		if f == "-D" || f == "--debug" || f == "-debug" {
			log.IsDebug = true
		}
	}

	debugEnv := os.Getenv("GOKC_DEBUG")
	if debugEnv != "" {
		showDebug, err := strconv.ParseBool(debugEnv)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error parsing boolean value from GRABENI_DEBUG: %s\n", err)
			os.Exit(1)
		}
		log.IsDebug = showDebug
	}
}

func init() {
	setDebugOutputLevel()
}

func main() {
	var filepath string
	var isVersion bool
	flag.StringVar(&filepath, "f", "/etc/keepalived/keepalived.conf", "keepalived.conf file path")
	flag.BoolVar(&isVersion, "v", false, "print the version")
	flag.Parse()

	if isVersion {
		log.Infof("gokc version %s", Version)
		os.Exit(0)
	}

	if filepath == "" {
		log.Error("filepath required")
	}

	file, err := os.Open(filepath)
	if err != nil {
		log.Error(err)
	}
	defer file.Close()

	if err := parser.Parse(file, filepath); err != nil {
		if e, ok := err.(*parser.Error); ok {
			msg := colorstring.Color(fmt.Sprintf("[white]%s:%d:%d: [red]%s[reset]", e.Filename, e.Line, e.Column, e.Message))
			log.Error(msg)
		} else {
			log.Error(err)
		}
	}

	log.Infof("gokc: the configuration file %s syntax is ok", filepath)
}
<|endoftext|>


<commit_before>// Copyright © 2016 Jip J. Dekker <jip@dekker.li>
//
// 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 cmd

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

	log "github.com/Sirupsen/logrus"
	"github.com/jjdekker/ponder/helpers"
	"github.com/spf13/cobra"
)

var (
	settingsFile     = "ponder.json"
	settingsTemplate = []byte(`{
  "Name": "",
  "IgnoreDirs": [".git"],
  "LilypondIncludes": [],
  "OutputDir": "out"
}`)
	gitIgnoreTemplate = []byte(`# Output Folder
out/`)
)

// initCmd represents the init command
var initCmd = &cobra.Command{
	Use:   "init [name]",
	Short: "Initialize a Ponder Library",
	Long: `Initialize (ponder init) will create a new library, with a ponder
	settings file and corresponding git ignore file.

  * If a name is provided, it will be created in the current directory;
  * If no name is provided, the current directory will be assumed;
Init will not use an existing directory with contents.`,
	Run: func(cmd *cobra.Command, args []string) {
		var path string
		var err error
		switch len(args) {
		case 0:
			path, err = helpers.CleanPath("")
		case 1:
			path, err = helpers.CleanPath(args[0])
		default:
			log.Fatal("init command does not support more than 1 parameter")
		}
		helpers.Check(err, "Given path is invalid")

		initializePath(path)
	},
}

func initializePath(path string) {
	if !helpers.Exists(path) {
		err := os.MkdirAll(path, os.ModePerm)
		helpers.Check(err, "Could not create directory")
	}

	createFile(filepath.Join(path, settingsFile), settingsTemplate)
	createFile(filepath.Join(path, ".gitignore"), gitIgnoreTemplate)
}

func createFile(path string, content []byte) {
	b := helpers.Exists(path)

	if !b {
		err := ioutil.WriteFile(path, content, 0644)
		if err != nil {
			log.WithFields(log.Fields{"error": err, "path": path}).
				Fatal("Unable to create settings file")
		}
	}
}

func init() {
	RootCmd.AddCommand(initCmd)
}
<commit_msg>Small update to command description<commit_after>// Copyright © 2016 Jip J. Dekker <jip@dekker.li>
//
// 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 cmd

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

	log "github.com/Sirupsen/logrus"
	"github.com/jjdekker/ponder/helpers"
	"github.com/spf13/cobra"
)

var (
	settingsFile     = "ponder.json"
	settingsTemplate = []byte(`{
  "Name": "",
  "IgnoreDirs": [".git"],
  "LilypondIncludes": [],
  "OutputDir": "out"
}`)
	gitIgnoreTemplate = []byte(`# Output Folder
out/`)
)

// initCmd represents the init command
var initCmd = &cobra.Command{
	Use:   "init [location]",
	Short: "Initialize a Ponder Library",
	Long: `Initialize (ponder init) will create a new library, with a ponder
	settings file and corresponding git ignore file.

  * If a name is provided, it will be created in the current directory;
  * If no name is provided, the current directory will be assumed;
Init will not use an existing directory with contents.`,
	Run: func(cmd *cobra.Command, args []string) {
		var path string
		var err error
		switch len(args) {
		case 0:
			path, err = helpers.CleanPath("")
		case 1:
			path, err = helpers.CleanPath(args[0])
		default:
			log.Fatal("init command does not support more than 1 parameter")
		}
		helpers.Check(err, "Given path is invalid")

		initializePath(path)
	},
}

func initializePath(path string) {
	if !helpers.Exists(path) {
		err := os.MkdirAll(path, os.ModePerm)
		helpers.Check(err, "Could not create directory")
	}

	createFile(filepath.Join(path, settingsFile), settingsTemplate)
	createFile(filepath.Join(path, ".gitignore"), gitIgnoreTemplate)
}

func createFile(path string, content []byte) {
	b := helpers.Exists(path)

	if !b {
		err := ioutil.WriteFile(path, content, 0644)
		if err != nil {
			log.WithFields(log.Fields{"error": err, "path": path}).
				Fatal("Unable to create settings file")
		}
	}
}

func init() {
	RootCmd.AddCommand(initCmd)
}
<|endoftext|>


<commit_before>package main

// sweet.go: network device backups and change alerts for the 21st century - inspired by RANCID.

// TODO: send email on start, new errors

import (
	"errors"
	"github.com/appliedtrust/sweet"
	"github.com/docopt/docopt-go"
	"github.com/vaughan0/go-ini"
	"log/syslog"
	"os"
	"os/exec"
	"strconv"
	"time"
)

const version = "1.1"

var usage = `sweet: network device backups and change alerts for the 21st century.

Usage:
  sweet [options] <config>
  sweet -h --help
  sweet --version

Options:
  -w, --workspace <dir>     Specify workspace directory (default: ./sweet-workspace).
  -i, --interval <secs>     Collection interval in secs (default: 300).
  -c, --concurrency <num>   Concurrent device collections (default: 30).
  -t, --to <email@addr>     Send change notifications to this email.
  -f, --from <email@addr>   Send change notifications from this email.
  -s, --smtp <host:port>    SMTP server connection info (default: localhost:25).
  --insecure                Accept untrusted SSH device keys.
  --push                    Do a "git push" after committing changed configs.
  --syslog                  Send log messages to syslog rather than stdout.
  --timeout <secs>          Device collection timeout in secs (default: 60).
  --web                     Run an HTTP status server.
  --weblisten <host:port>   Host and port to use for HTTP status server (default: localhost:5000).
  --version                 Show version.
  -h, --help                Show this screen.
`

//// here we go...
func main() {
	Opts, err := setupOptions()
	if err != nil {
		Opts.LogFatal(err.Error())
	}

	ec, err := sweet.RunErrorCache()
	if err != nil {
		Opts.LogFatal(err.Error())
	}
	Opts.ErrorCacheUpdates = ec.Updates
	Opts.ErrorCacheRequests = ec.Requests

	go sweet.RunWebserver(&Opts)

	sweet.RunCollectors(&Opts)
}

//// Read CLI flags and config file
func setupOptions() (sweet.SweetOptions, error) {
	Opts := sweet.SweetOptions{}
	arguments, err := docopt.Parse(usage, nil, true, version, false)
	if err != nil {
		return Opts, err
	}

	// check for runtime dependencies
	if _, err := exec.LookPath("git"); err != nil {
		return Opts, errors.New("Couldn't find the git command in your path.")
	}

	Opts.ExecutableDir, err = os.Getwd()
	if err != nil {
		return Opts, err
	}

	// set non-zero-value defaults
	Opts.Workspace = "./sweet-workspace"
	Opts.Concurrency = 30
	Opts.SmtpString = "localhost:25" //TODO BROKEN!?
	Opts.HttpListen = "localhost:5000"
	Opts.Interval = 300 * time.Second
	Opts.Timeout = 60 * time.Second
	Opts.Insecure = false
	Opts.GitPush = false
	Opts.UseSyslog = false
	Opts.HttpEnabled = false

	// read in config file - config file options override defaults if set
	configFile, err := ini.LoadFile(arguments["<config>"].(string))
	if err != nil {
		return Opts, err
	}

	for name, section := range configFile {
		if len(name) == 0 { // global config
			_, ok := section["workspace"]
			if ok {
				Opts.Workspace = section["workspace"]
			}
			_, ok = section["to"]
			if ok {
				Opts.ToEmail = section["to"]
			}
			_, ok = section["from"]
			if ok {
				Opts.FromEmail = section["from"]
			}
			_, ok = section["smtp"]
			if ok {
				Opts.SmtpString = section["smtp"]
			}
			_, ok = section["weblisten"]
			if ok {
				Opts.HttpListen = section["weblisten"]
			}
			_, ok = section["concurrency"]
			if ok {
				Opts.Concurrency, err = strconv.Atoi(section["concurrency"])
				if err != nil {
					return Opts, err
				}
			}

			boolText, ok := section["insecure"]
			if ok {
				if boolText == "true" {
					Opts.Insecure = true
				}
			}
			boolText, ok = section["push"]
			if ok {
				if boolText == "true" {
					Opts.GitPush = true
				}
			}
			boolText, ok = section["syslog"]
			if ok {
				if boolText == "true" {
					Opts.UseSyslog = true
				}
			}
			boolText, ok = section["web"]
			if ok {
				if boolText == "true" {
					Opts.HttpEnabled = true
				}
			}
			intervalText, ok := section["interval"]
			if ok {
				Opts.Interval, err = time.ParseDuration(intervalText + "s")
				if err != nil {
					return Opts, err
				}
			}
			timeoutText, ok := section["timeout"]
			if ok {
				Opts.Timeout, err = time.ParseDuration(timeoutText + "s")
				if err != nil {
					return Opts, err
				}
			}

			defaultUser, ok := section["default-user"]
			if ok {
				Opts.DefaultUser = defaultUser
			}
			defaultPass, ok := section["default-pass"]
			if ok {
				Opts.DefaultPass = defaultPass
			}
			defaultMethod, ok := section["default-method"]
			if ok {
				Opts.DefaultMethod = defaultMethod
			}

		} else { // device-specific config
			device := new(sweet.DeviceAccess)
			device.Hostname = name
			device.Method = section["method"]
			device.Config = section
			Opts.Devices = append(Opts.Devices, *device)
		}
	}

	// CLI flags override config file opts if set
	if arguments["--syslog"].(bool) {
		Opts.UseSyslog = arguments["--syslog"].(bool)
		// setup logging now
		Opts.Syslog, err = syslog.New(syslog.LOG_ALERT|syslog.LOG_USER, "sweet")
		if err != nil {
			return Opts, err
		}
	}
	if arguments["--web"].(bool) {
		Opts.HttpEnabled = true
	}
	if arguments["--push"].(bool) {
		Opts.GitPush = true
	}
	if arguments["--insecure"].(bool) {
		Opts.Insecure = true
	}
	if arguments["--smtp"] != nil {
		Opts.SmtpString = arguments["--smtp"].(string)
	}
	if arguments["--to"] != nil {
		if arguments["--from"] == nil {
			return Opts, errors.New("Both --to and --from arguments required for email to work.")
		}
		Opts.ToEmail = arguments["--to"].(string)
	}
	if arguments["--from"] != nil {
		if arguments["--to"] == nil {
			return Opts, errors.New("Both --to and --from arguments required for email to work.")
		}
		Opts.FromEmail = arguments["--from"].(string)
	}
	if arguments["--weblisten"] != nil {
		Opts.HttpListen = arguments["--weblisten"].(string)
	}

	// concurrent collectors
	if arguments["--concurrency"] != nil {
		Opts.Concurrency, err = strconv.Atoi(arguments["--concurrency"].(string))
		if err != nil {
			return Opts, err
		}
	}

	// collection interval and timeouts
	if arguments["--interval"] != nil {
		Opts.Interval, err = time.ParseDuration(arguments["--interval"].(string) + "s")
		if err != nil {
			return Opts, err
		}
	}
	if arguments["--timeout"] != nil {
		Opts.Timeout, err = time.ParseDuration(arguments["--timeout"].(string) + "s")
		if err != nil {
			return Opts, err
		}
	}

	// configs get saved in workspace directory
	if arguments["--workspace"] != nil {
		Opts.Workspace = arguments["--workspace"].(string)
	}

	if _, err := os.Stat(Opts.Workspace); err != nil {
		if err := os.MkdirAll(Opts.Workspace, 0755); err != nil {
			return Opts, err
		}
	}

	// switch to workspace directory
	err = os.Chdir(Opts.Workspace)
	if err != nil {
		return Opts, err
	}

	// make sure git is ready to go
	if _, err := os.Stat(".git"); err != nil {
		if _, err := exec.Command("git", "init").Output(); err != nil {
			return Opts, err
		}
	}

	return Opts, nil
}

//// EOF
<commit_msg>Bumped version<commit_after>package main

// sweet.go: network device backups and change alerts for the 21st century - inspired by RANCID.

// TODO: send email on start, new errors

import (
	"errors"
	"github.com/appliedtrust/sweet"
	"github.com/docopt/docopt-go"
	"github.com/vaughan0/go-ini"
	"log/syslog"
	"os"
	"os/exec"
	"strconv"
	"time"
)

const version = "1.2"

var usage = `sweet: network device backups and change alerts for the 21st century.

Usage:
  sweet [options] <config>
  sweet -h --help
  sweet --version

Options:
  -w, --workspace <dir>     Specify workspace directory (default: ./sweet-workspace).
  -i, --interval <secs>     Collection interval in secs (default: 300).
  -c, --concurrency <num>   Concurrent device collections (default: 30).
  -t, --to <email@addr>     Send change notifications to this email.
  -f, --from <email@addr>   Send change notifications from this email.
  -s, --smtp <host:port>    SMTP server connection info (default: localhost:25).
  --insecure                Accept untrusted SSH device keys.
  --push                    Do a "git push" after committing changed configs.
  --syslog                  Send log messages to syslog rather than stdout.
  --timeout <secs>          Device collection timeout in secs (default: 60).
  --web                     Run an HTTP status server.
  --weblisten <host:port>   Host and port to use for HTTP status server (default: localhost:5000).
  --version                 Show version.
  -h, --help                Show this screen.
`

//// here we go...
func main() {
	Opts, err := setupOptions()
	if err != nil {
		Opts.LogFatal(err.Error())
	}

	ec, err := sweet.RunErrorCache()
	if err != nil {
		Opts.LogFatal(err.Error())
	}
	Opts.ErrorCacheUpdates = ec.Updates
	Opts.ErrorCacheRequests = ec.Requests

	go sweet.RunWebserver(&Opts)

	sweet.RunCollectors(&Opts)
}

//// Read CLI flags and config file
func setupOptions() (sweet.SweetOptions, error) {
	Opts := sweet.SweetOptions{}
	arguments, err := docopt.Parse(usage, nil, true, version, false)
	if err != nil {
		return Opts, err
	}

	// check for runtime dependencies
	if _, err := exec.LookPath("git"); err != nil {
		return Opts, errors.New("Couldn't find the git command in your path.")
	}

	Opts.ExecutableDir, err = os.Getwd()
	if err != nil {
		return Opts, err
	}

	// set non-zero-value defaults
	Opts.Workspace = "./sweet-workspace"
	Opts.Concurrency = 30
	Opts.SmtpString = "localhost:25" //TODO BROKEN!?
	Opts.HttpListen = "localhost:5000"
	Opts.Interval = 300 * time.Second
	Opts.Timeout = 60 * time.Second
	Opts.Insecure = false
	Opts.GitPush = false
	Opts.UseSyslog = false
	Opts.HttpEnabled = false

	// read in config file - config file options override defaults if set
	configFile, err := ini.LoadFile(arguments["<config>"].(string))
	if err != nil {
		return Opts, err
	}

	for name, section := range configFile {
		if len(name) == 0 { // global config
			_, ok := section["workspace"]
			if ok {
				Opts.Workspace = section["workspace"]
			}
			_, ok = section["to"]
			if ok {
				Opts.ToEmail = section["to"]
			}
			_, ok = section["from"]
			if ok {
				Opts.FromEmail = section["from"]
			}
			_, ok = section["smtp"]
			if ok {
				Opts.SmtpString = section["smtp"]
			}
			_, ok = section["weblisten"]
			if ok {
				Opts.HttpListen = section["weblisten"]
			}
			_, ok = section["concurrency"]
			if ok {
				Opts.Concurrency, err = strconv.Atoi(section["concurrency"])
				if err != nil {
					return Opts, err
				}
			}

			boolText, ok := section["insecure"]
			if ok {
				if boolText == "true" {
					Opts.Insecure = true
				}
			}
			boolText, ok = section["push"]
			if ok {
				if boolText == "true" {
					Opts.GitPush = true
				}
			}
			boolText, ok = section["syslog"]
			if ok {
				if boolText == "true" {
					Opts.UseSyslog = true
				}
			}
			boolText, ok = section["web"]
			if ok {
				if boolText == "true" {
					Opts.HttpEnabled = true
				}
			}
			intervalText, ok := section["interval"]
			if ok {
				Opts.Interval, err = time.ParseDuration(intervalText + "s")
				if err != nil {
					return Opts, err
				}
			}
			timeoutText, ok := section["timeout"]
			if ok {
				Opts.Timeout, err = time.ParseDuration(timeoutText + "s")
				if err != nil {
					return Opts, err
				}
			}

			defaultUser, ok := section["default-user"]
			if ok {
				Opts.DefaultUser = defaultUser
			}
			defaultPass, ok := section["default-pass"]
			if ok {
				Opts.DefaultPass = defaultPass
			}
			defaultMethod, ok := section["default-method"]
			if ok {
				Opts.DefaultMethod = defaultMethod
			}

		} else { // device-specific config
			device := new(sweet.DeviceAccess)
			device.Hostname = name
			device.Method = section["method"]
			device.Config = section
			Opts.Devices = append(Opts.Devices, *device)
		}
	}

	// CLI flags override config file opts if set
	if arguments["--syslog"].(bool) {
		Opts.UseSyslog = arguments["--syslog"].(bool)
		// setup logging now
		Opts.Syslog, err = syslog.New(syslog.LOG_ALERT|syslog.LOG_USER, "sweet")
		if err != nil {
			return Opts, err
		}
	}
	if arguments["--web"].(bool) {
		Opts.HttpEnabled = true
	}
	if arguments["--push"].(bool) {
		Opts.GitPush = true
	}
	if arguments["--insecure"].(bool) {
		Opts.Insecure = true
	}
	if arguments["--smtp"] != nil {
		Opts.SmtpString = arguments["--smtp"].(string)
	}
	if arguments["--to"] != nil {
		if arguments["--from"] == nil {
			return Opts, errors.New("Both --to and --from arguments required for email to work.")
		}
		Opts.ToEmail = arguments["--to"].(string)
	}
	if arguments["--from"] != nil {
		if arguments["--to"] == nil {
			return Opts, errors.New("Both --to and --from arguments required for email to work.")
		}
		Opts.FromEmail = arguments["--from"].(string)
	}
	if arguments["--weblisten"] != nil {
		Opts.HttpListen = arguments["--weblisten"].(string)
	}

	// concurrent collectors
	if arguments["--concurrency"] != nil {
		Opts.Concurrency, err = strconv.Atoi(arguments["--concurrency"].(string))
		if err != nil {
			return Opts, err
		}
	}

	// collection interval and timeouts
	if arguments["--interval"] != nil {
		Opts.Interval, err = time.ParseDuration(arguments["--interval"].(string) + "s")
		if err != nil {
			return Opts, err
		}
	}
	if arguments["--timeout"] != nil {
		Opts.Timeout, err = time.ParseDuration(arguments["--timeout"].(string) + "s")
		if err != nil {
			return Opts, err
		}
	}

	// configs get saved in workspace directory
	if arguments["--workspace"] != nil {
		Opts.Workspace = arguments["--workspace"].(string)
	}

	if _, err := os.Stat(Opts.Workspace); err != nil {
		if err := os.MkdirAll(Opts.Workspace, 0755); err != nil {
			return Opts, err
		}
	}

	// switch to workspace directory
	err = os.Chdir(Opts.Workspace)
	if err != nil {
		return Opts, err
	}

	// make sure git is ready to go
	if _, err := os.Stat(".git"); err != nil {
		if _, err := exec.Command("git", "init").Output(); err != nil {
			return Opts, err
		}
	}

	return Opts, nil
}

//// EOF
<|endoftext|>


<commit_before>// The command flags, their descriptions, and some of the logic for
// merging manifests with flags come from Cloud Foundry's 'cf'
// tool. See the NOTICE file for more information.

package cmd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/ghodss/yaml"
	"github.com/imdario/mergo"
	"github.com/spf13/cobra"
)

const (
	pushCmdLong = `
Create a new application or update an existing one.

This command emulates Cloud Foundry's 'cf push' command but targeting
OpenShift instead. Not all the Cloud Foundry options are supported;
those that are supported are documented in the usage information
below.`

	pushCmdExample = `
  # Create a new application from a local Java artifact
  %[1]s push target/foo.jar

  # Create a new application named my-new-app from the code in the current directory
  %[1]s push my-new-app

  # Create a new application from a manifest.yml
  %[1]s push

  # Update an existing application with a manifest.yml
  %[1]s push`
)

// PushConfig contains all the necessary configuration for the push command
type PushConfig struct {
	Buildpack    string
	Command      string
	ManifestPath string
	Instances    int
	Disk         string
	Memory       string
	Path         string
}

type Manifest struct {
	Applications []Application `json:"applications"`
}

type Application struct {
	Name      string `json:"name"`
	Buildpack string `json:"buildpack"`
	Command   string `json:"command"`
	DiskQuota string `json:"disk_quota"`
	Instances int    `json:"instances"`
	Memory    string `json:"memory"`
	Path      string `json:"path"`
}

func init() {
	RootCmd.AddCommand(newPushCmd("ocf"))
}

func newPushCmd(commandName string) *cobra.Command {
	config := &PushConfig{}
	cmd := &cobra.Command{
		Use:     "push",
		Short:   "Create a new application or update an existing one.",
		Long:    pushCmdLong,
		Example: fmt.Sprintf(pushCmdExample, commandName),
		Run: func(cmd *cobra.Command, args []string) {
			err := config.Run(args)
			if err != nil {
				fmt.Printf("err: %v\n", err)
			}
		},
	}

	// cmd.Flags().StringVarP(&config.Buildpack, "buildpack", "b", "", "Custom buildpack by name (e.g. my-buildpack) or Git URL (e.g. 'https://github.com/cloudfoundry/java-buildpack.git') or Git URL with a branch or tag (e.g. 'https://github.com/cloudfoundry/java-buildpack.git#v3.3.0' for 'v3.3.0' tag). To use built-in buildpacks only, specify 'default' or 'null'")
	// cmd.Flags().StringVarP(&config.Command, "command", "c", "", "Startup command, set to null to reset to default start command")
	cmd.Flags().StringVarP(&config.ManifestPath, "manifest-path", "f", "", "Path to manifest")
	// cmd.Flags().IntVarP(&config.Instances, "instances", "i", 1, "Number of instances")
	// cmd.Flags().StringVarP(&config.Disk, "disk", "k", "", "Disk limit (e.g. 256M, 1024M, 1G)")
	cmd.Flags().StringVarP(&config.Memory, "memory", "m", "", "Memory limit (e.g. 256M, 1024M, 1G)")
	cmd.Flags().StringVarP(&config.Path, "path", "p", "", "Path to app directory or to a zip file of the contents of the app directory")

	return cmd
}

func (config *PushConfig) Run(args []string) error {
	debugf("Config: %+v\n", config)

	manifestApps, err := config.getManifestApps()
	if err != nil {
		return err
	}
	debugf("manifestApps: %+v\n", manifestApps)

	flagsApp, err := config.getFlagsApp(args)
	if err != nil {
		return err
	}
	debugf("flagsApp: %+v\n", flagsApp)

	mergedApps, err := mergeAppsFromManifestAndFlags(manifestApps, flagsApp)
	if err != nil {
		return err
	}
	debugf("mergedApps: %+v\n", mergedApps)
	debugf("\n\n\n")

	for _, app := range mergedApps {
		if app.Name == "" {
			return errors.New("Error: no name found for app")
		}

		app.ensureLoggedIn()
		// TODO: help user select the correct project instead of just
		// assuming they've already done that
		app.displayProject()
		app.ensureBuildExists()
		app.startBuild()
		app.ensureDeploymentExists()
		app.ensureServiceExists()
		app.ensureRouteExists()
		app.displayRoute()
	}

	return nil
}

func (app *Application) ensureLoggedIn() {
	err := ocExec("whoami").Run()
	if err != nil {
		loginCmd := ocExec("login")
		loginCmd.Stdin = os.Stdin
		loginCmd.Stdout = os.Stdout
		loginCmd.Stderr = os.Stderr
		err = loginCmd.Run()
		if err != nil {
			exitWithError(err)
		}
	}
}

func (app *Application) displayProject() {
	output, err := ocExec("project").CombinedOutput()
	fmt.Println(string(output))
	if err != nil {
		exitWithError(err)
	}
}

func (app *Application) ensureBuildExists() {
	output, err := ocExec("get", "bc", app.Name).CombinedOutput()
	if strings.Contains(string(output), "not found") {
		newCmd := ocExec("new-build", "bbrowning/openshift-cloudfoundry-docker19",
			"--binary=true", fmt.Sprint("--name=", app.Name))
		fmt.Printf("==> Creating build with command: %s\n", strings.Join(newCmd.Args, " "))
		// oc new-build sometimes gives a non-zero exit status for ignorable errors
		output, _ = newCmd.CombinedOutput()
		fmt.Println(string(output))
	} else if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Build configuration already exists for %s, skipping creating one\n", app.Name)
	}
}

func (app *Application) startBuild() {
	var pathArg string
	if fi, err := os.Stat(app.Path); err != nil || fi.IsDir() {
		pathArg = fmt.Sprint("--from-dir=", app.Path)
	} else {
		pathArg = fmt.Sprint("--from-file=", app.Path)
	}
	startBuildCmd := ocExec("start-build", app.Name, pathArg, "--follow")
	startBuildCmd.Stdout = os.Stdout
	startBuildCmd.Stderr = os.Stderr
	fmt.Printf("==> Starting build with command: %s\n", strings.Join(startBuildCmd.Args, " "))
	err := startBuildCmd.Run()
	if err != nil {
		exitWithError(err)
	}
}

func (app *Application) ensureDeploymentExists() {
	output, err := ocExec("get", "dc", app.Name).CombinedOutput()
	if strings.Contains(string(output), "not found") {
		var limits string
		if app.Memory != "" {
			limits = fmt.Sprint("--limits=memory=", app.Memory)
		} else {
			limits = ""
		}
		repoAndImage, err := ocExec("get", "is", app.Name, "-o", "template", "--template={{.status.dockerImageRepository}}").CombinedOutput()
		if err != nil {
			exitWithOutputAndError(repoAndImage, err)
		}
		newCmd := ocExec("run", app.Name, fmt.Sprint("--image=", string(repoAndImage)), limits)
		fmt.Printf("==> Creating deployment config with command: %s\n", strings.Join(newCmd.Args, " "))
		output, err = newCmd.CombinedOutput()
		fmt.Println(string(output))
		if err != nil {
			exitWithError(err)
		}
	} else if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Deployment config already exists for %s, skipping creating one\n", app.Name)
	}
}

func (app *Application) ensureServiceExists() {
	output, err := ocExec("get", "svc", app.Name).CombinedOutput()
	if strings.Contains(string(output), "not found") {
		newCmd := ocExec("expose", "dc", app.Name, "--port=8080")
		fmt.Printf("==> Creating service with command: %s\n", strings.Join(newCmd.Args, " "))
		output, err = newCmd.CombinedOutput()
		fmt.Println(string(output))
		if err != nil {
			exitWithError(err)
		}
	} else if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Service already exists for %s, skipping creating one\n", app.Name)
	}
}

func (app *Application) ensureRouteExists() {
	output, err := ocExec("get", "route", app.Name).CombinedOutput()
	if strings.Contains(string(output), "not found") {
		newCmd := ocExec("expose", "svc", app.Name)
		fmt.Printf("==> Creating route with command: %s\n", strings.Join(newCmd.Args, " "))
		output, err = newCmd.CombinedOutput()
		fmt.Println(string(output))
		if err != nil {
			exitWithError(err)
		}
	} else if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Route already exists for %s, skipping creating one\n", app.Name)
	}
}

func (app *Application) displayRoute() {
	output, err := ocExec("get", "route", app.Name, "-o", "template",
		"--template={{.spec.host}}").CombinedOutput()
	if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Your application is available at %s\n", output)
	}
}

func (config *PushConfig) getManifestApps() ([]Application, error) {
	var path string
	var err error
	if config.ManifestPath != "" {
		path = config.ManifestPath
	} else {
		path, err = os.Getwd()
		if err != nil {
			return nil, err
		}
	}

	if info, err := os.Stat(path); err == nil && info.IsDir() {
		path = filepath.Join(path, "manifest.yml")
	}
	y, err := ioutil.ReadFile(path)
	if err != nil {
		if os.IsNotExist(err) {
			return []Application{}, nil
		} else {
			return nil, err
		}
	}

	var m Manifest
	err = yaml.Unmarshal(y, &m)
	if err != nil {
		return nil, err
	}
	debugf("manifest: %+v\n", m)

	return m.Applications, nil
}

func (config *PushConfig) getFlagsApp(args []string) (Application, error) {
	app := Application{}

	if len(args) > 0 {
		app.Name = args[0]
	}

	if config.Buildpack != "" && config.Buildpack != "null" && config.Buildpack != "default" {
		app.Buildpack = config.Buildpack
	}

	if config.Command != "" && config.Command != "null" && config.Command != "default" {
		app.Command = config.Command
	}

	if config.Instances > 0 {
		app.Instances = config.Instances
	}

	if config.Memory != "" {
		mem := strings.TrimSuffix(strings.ToUpper(config.Memory), "B")
		matched, err := regexp.MatchString("^\\d+[EPTGMK]?$", mem)
		if err != nil {
			return app, err
		}
		if !matched {
			return app, errors.New("Memory string must be in the format of 8690K, 256M, 256MB, 1G, 1GB, etc")
		}
		app.Memory = mem
	}

	if config.Path != "" {
		app.Path = config.Path
	}

	return app, nil
}

func mergeAppsFromManifestAndFlags(manifestApps []Application, flagsApp Application) ([]Application, error) {
	var err error
	var apps []Application

	switch len(manifestApps) {
	case 0:
		if flagsApp.Name == "" {
			return nil, errors.New("Manifest file is not found in the current directory, please provide either an app name or manifest")
		}
		err = addApp(&apps, flagsApp)
	case 1:
		mergo.MergeWithOverwrite(&manifestApps[0], flagsApp)
		err = addApp(&apps, manifestApps[0])
	default:
		selectedAppName := flagsApp.Name

		// TODO: Check for flags and multiple apps error condition

		if selectedAppName != "" {
			var foundApp bool
			for _, currentApp := range manifestApps {
				if currentApp.Name == selectedAppName {
					foundApp = true
					err = addApp(&apps, currentApp)
				}
			}
			if !foundApp {
				err = errors.New(fmt.Sprintf("Could not find app named %s in manifest", selectedAppName))
			}
		} else {
			for _, manifestApp := range manifestApps {
				err = addApp(&apps, manifestApp)
			}
		}
	}

	if err != nil {
		return nil, err
	}

	return apps, nil
}

func addApp(apps *[]Application, app Application) error {
	if app.Name == "" {
		return errors.New("App name is a required field")
	}

	if app.Path == "" {
		cwd, err := os.Getwd()
		if err != nil {
			return err
		}
		app.Path = cwd
	}

	*apps = append(*apps, app)
	return nil
}

func ocExec(args ...string) *exec.Cmd {
	return exec.Command("oc", args...)
}

func exitWithError(err error) {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}

func exitWithOutputAndError(output []byte, err error) {
	fmt.Println(string(output))
	exitWithError(err)
}

func debugf(format string, v ...interface{}) {
	if Debug {
		fmt.Printf(format, v...)
	}
}
<commit_msg>Make sure memory limits make their way to $MEMORY_LIMIT env var<commit_after>// The command flags, their descriptions, and some of the logic for
// merging manifests with flags come from Cloud Foundry's 'cf'
// tool. See the NOTICE file for more information.

package cmd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/ghodss/yaml"
	"github.com/imdario/mergo"
	"github.com/spf13/cobra"
)

const (
	pushCmdLong = `
Create a new application or update an existing one.

This command emulates Cloud Foundry's 'cf push' command but targeting
OpenShift instead. Not all the Cloud Foundry options are supported;
those that are supported are documented in the usage information
below.`

	pushCmdExample = `
  # Create a new application from a local Java artifact
  %[1]s push target/foo.jar

  # Create a new application named my-new-app from the code in the current directory
  %[1]s push my-new-app

  # Create a new application from a manifest.yml
  %[1]s push

  # Update an existing application with a manifest.yml
  %[1]s push`
)

// PushConfig contains all the necessary configuration for the push command
type PushConfig struct {
	Buildpack    string
	Command      string
	ManifestPath string
	Instances    int
	Disk         string
	Memory       string
	Path         string
}

type Manifest struct {
	Applications []Application `json:"applications"`
}

type Application struct {
	Name      string `json:"name"`
	Buildpack string `json:"buildpack"`
	Command   string `json:"command"`
	DiskQuota string `json:"disk_quota"`
	Instances int    `json:"instances"`
	Memory    string `json:"memory"`
	Path      string `json:"path"`
}

func init() {
	RootCmd.AddCommand(newPushCmd("ocf"))
}

func newPushCmd(commandName string) *cobra.Command {
	config := &PushConfig{}
	cmd := &cobra.Command{
		Use:     "push",
		Short:   "Create a new application or update an existing one.",
		Long:    pushCmdLong,
		Example: fmt.Sprintf(pushCmdExample, commandName),
		Run: func(cmd *cobra.Command, args []string) {
			err := config.Run(args)
			if err != nil {
				fmt.Printf("err: %v\n", err)
			}
		},
	}

	// cmd.Flags().StringVarP(&config.Buildpack, "buildpack", "b", "", "Custom buildpack by name (e.g. my-buildpack) or Git URL (e.g. 'https://github.com/cloudfoundry/java-buildpack.git') or Git URL with a branch or tag (e.g. 'https://github.com/cloudfoundry/java-buildpack.git#v3.3.0' for 'v3.3.0' tag). To use built-in buildpacks only, specify 'default' or 'null'")
	// cmd.Flags().StringVarP(&config.Command, "command", "c", "", "Startup command, set to null to reset to default start command")
	cmd.Flags().StringVarP(&config.ManifestPath, "manifest-path", "f", "", "Path to manifest")
	// cmd.Flags().IntVarP(&config.Instances, "instances", "i", 1, "Number of instances")
	// cmd.Flags().StringVarP(&config.Disk, "disk", "k", "", "Disk limit (e.g. 256M, 1024M, 1G)")
	cmd.Flags().StringVarP(&config.Memory, "memory", "m", "", "Memory limit (e.g. 256M, 1024M, 1G)")
	cmd.Flags().StringVarP(&config.Path, "path", "p", "", "Path to app directory or to a zip file of the contents of the app directory")

	return cmd
}

func (config *PushConfig) Run(args []string) error {
	debugf("Config: %+v\n", config)

	manifestApps, err := config.getManifestApps()
	if err != nil {
		return err
	}
	debugf("manifestApps: %+v\n", manifestApps)

	flagsApp, err := config.getFlagsApp(args)
	if err != nil {
		return err
	}
	debugf("flagsApp: %+v\n", flagsApp)

	mergedApps, err := mergeAppsFromManifestAndFlags(manifestApps, flagsApp)
	if err != nil {
		return err
	}
	debugf("mergedApps: %+v\n", mergedApps)
	debugf("\n\n\n")

	for _, app := range mergedApps {
		if app.Name == "" {
			return errors.New("Error: no name found for app")
		}

		app.ensureLoggedIn()
		// TODO: help user select the correct project instead of just
		// assuming they've already done that
		app.displayProject()
		app.ensureBuildExists()
		app.startBuild()
		app.ensureDeploymentExists()
		app.ensureServiceExists()
		app.ensureRouteExists()
		app.displayRoute()
	}

	return nil
}

func (app *Application) ensureLoggedIn() {
	err := ocExec("whoami").Run()
	if err != nil {
		loginCmd := ocExec("login")
		loginCmd.Stdin = os.Stdin
		loginCmd.Stdout = os.Stdout
		loginCmd.Stderr = os.Stderr
		err = loginCmd.Run()
		if err != nil {
			exitWithError(err)
		}
	}
}

func (app *Application) displayProject() {
	output, err := ocExec("project").CombinedOutput()
	fmt.Println(string(output))
	if err != nil {
		exitWithError(err)
	}
}

func (app *Application) ensureBuildExists() {
	output, err := ocExec("get", "bc", app.Name).CombinedOutput()
	if strings.Contains(string(output), "not found") {
		newCmd := ocExec("new-build", "bbrowning/openshift-cloudfoundry-docker19",
			"--binary=true", fmt.Sprint("--name=", app.Name))
		fmt.Printf("==> Creating build with command: %s\n", strings.Join(newCmd.Args, " "))
		// oc new-build sometimes gives a non-zero exit status for ignorable errors
		output, _ = newCmd.CombinedOutput()
		fmt.Println(string(output))
	} else if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Build configuration already exists for %s, skipping creating one\n", app.Name)
	}
}

func (app *Application) startBuild() {
	var pathArg string
	if fi, err := os.Stat(app.Path); err != nil || fi.IsDir() {
		pathArg = fmt.Sprint("--from-dir=", app.Path)
	} else {
		pathArg = fmt.Sprint("--from-file=", app.Path)
	}
	startBuildCmd := ocExec("start-build", app.Name, pathArg, "--follow")
	startBuildCmd.Stdout = os.Stdout
	startBuildCmd.Stderr = os.Stderr
	fmt.Printf("==> Starting build with command: %s\n", strings.Join(startBuildCmd.Args, " "))
	err := startBuildCmd.Run()
	if err != nil {
		exitWithError(err)
	}
}

func (app *Application) ensureDeploymentExists() {
	output, err := ocExec("get", "dc", app.Name).CombinedOutput()
	if strings.Contains(string(output), "not found") {
		var limits string
		var env string
		if app.Memory != "" {
			limits = fmt.Sprint("--limits=memory=", app.Memory)
			env = fmt.Sprint("--env=MEMORY_LIMIT=", app.Memory)
		} else {
			limits = ""
			env = ""
		}
		repoAndImage, err := ocExec("get", "is", app.Name, "-o", "template", "--template={{.status.dockerImageRepository}}").CombinedOutput()
		if err != nil {
			exitWithOutputAndError(repoAndImage, err)
		}
		newCmd := ocExec("run", app.Name, fmt.Sprint("--image=", string(repoAndImage)), limits, env)
		fmt.Printf("==> Creating deployment config with command: %s\n", strings.Join(newCmd.Args, " "))
		output, err = newCmd.CombinedOutput()
		fmt.Println(string(output))
		if err != nil {
			exitWithError(err)
		}
	} else if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Deployment config already exists for %s, skipping creating one\n", app.Name)
	}
}

func (app *Application) ensureServiceExists() {
	output, err := ocExec("get", "svc", app.Name).CombinedOutput()
	if strings.Contains(string(output), "not found") {
		newCmd := ocExec("expose", "dc", app.Name, "--port=8080")
		fmt.Printf("==> Creating service with command: %s\n", strings.Join(newCmd.Args, " "))
		output, err = newCmd.CombinedOutput()
		fmt.Println(string(output))
		if err != nil {
			exitWithError(err)
		}
	} else if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Service already exists for %s, skipping creating one\n", app.Name)
	}
}

func (app *Application) ensureRouteExists() {
	output, err := ocExec("get", "route", app.Name).CombinedOutput()
	if strings.Contains(string(output), "not found") {
		newCmd := ocExec("expose", "svc", app.Name)
		fmt.Printf("==> Creating route with command: %s\n", strings.Join(newCmd.Args, " "))
		output, err = newCmd.CombinedOutput()
		fmt.Println(string(output))
		if err != nil {
			exitWithError(err)
		}
	} else if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Route already exists for %s, skipping creating one\n", app.Name)
	}
}

func (app *Application) displayRoute() {
	output, err := ocExec("get", "route", app.Name, "-o", "template",
		"--template={{.spec.host}}").CombinedOutput()
	if err != nil {
		exitWithOutputAndError(output, err)
	} else {
		fmt.Printf("==> Your application is available at %s\n", output)
	}
}

func (config *PushConfig) getManifestApps() ([]Application, error) {
	var path string
	var err error
	if config.ManifestPath != "" {
		path = config.ManifestPath
	} else {
		path, err = os.Getwd()
		if err != nil {
			return nil, err
		}
	}

	if info, err := os.Stat(path); err == nil && info.IsDir() {
		path = filepath.Join(path, "manifest.yml")
	}
	y, err := ioutil.ReadFile(path)
	if err != nil {
		if os.IsNotExist(err) {
			return []Application{}, nil
		} else {
			return nil, err
		}
	}

	var m Manifest
	err = yaml.Unmarshal(y, &m)
	if err != nil {
		return nil, err
	}
	debugf("manifest: %+v\n", m)

	return m.Applications, nil
}

func (config *PushConfig) getFlagsApp(args []string) (Application, error) {
	app := Application{}

	if len(args) > 0 {
		app.Name = args[0]
	}

	if config.Buildpack != "" && config.Buildpack != "null" && config.Buildpack != "default" {
		app.Buildpack = config.Buildpack
	}

	if config.Command != "" && config.Command != "null" && config.Command != "default" {
		app.Command = config.Command
	}

	if config.Instances > 0 {
		app.Instances = config.Instances
	}

	if config.Memory != "" {
		mem := strings.TrimSuffix(strings.ToUpper(config.Memory), "B")
		matched, err := regexp.MatchString("^\\d+[EPTGMK]?$", mem)
		if err != nil {
			return app, err
		}
		if !matched {
			return app, errors.New("Memory string must be in the format of 8690K, 256M, 256MB, 1G, 1GB, etc")
		}
		app.Memory = mem
	}

	if config.Path != "" {
		app.Path = config.Path
	}

	return app, nil
}

func mergeAppsFromManifestAndFlags(manifestApps []Application, flagsApp Application) ([]Application, error) {
	var err error
	var apps []Application

	switch len(manifestApps) {
	case 0:
		if flagsApp.Name == "" {
			return nil, errors.New("Manifest file is not found in the current directory, please provide either an app name or manifest")
		}
		err = addApp(&apps, flagsApp)
	case 1:
		mergo.MergeWithOverwrite(&manifestApps[0], flagsApp)
		err = addApp(&apps, manifestApps[0])
	default:
		selectedAppName := flagsApp.Name

		// TODO: Check for flags and multiple apps error condition

		if selectedAppName != "" {
			var foundApp bool
			for _, currentApp := range manifestApps {
				if currentApp.Name == selectedAppName {
					foundApp = true
					err = addApp(&apps, currentApp)
				}
			}
			if !foundApp {
				err = errors.New(fmt.Sprintf("Could not find app named %s in manifest", selectedAppName))
			}
		} else {
			for _, manifestApp := range manifestApps {
				err = addApp(&apps, manifestApp)
			}
		}
	}

	if err != nil {
		return nil, err
	}

	return apps, nil
}

func addApp(apps *[]Application, app Application) error {
	if app.Name == "" {
		return errors.New("App name is a required field")
	}

	if app.Path == "" {
		cwd, err := os.Getwd()
		if err != nil {
			return err
		}
		app.Path = cwd
	}

	*apps = append(*apps, app)
	return nil
}

func ocExec(args ...string) *exec.Cmd {
	return exec.Command("oc", args...)
}

func exitWithError(err error) {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}

func exitWithOutputAndError(output []byte, err error) {
	fmt.Println(string(output))
	exitWithError(err)
}

func debugf(format string, v ...interface{}) {
	if Debug {
		fmt.Printf(format, v...)
	}
}
<|endoftext|>


<commit_before>// Copyright © 2016 Valere JEANTET <valere.jeantet@gmail.com>
//
// 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 cmd

import (
	"fmt"
	"os"
	"runtime"

	"github.com/spf13/cobra"
)

var configPath, configString, logPath string
var filterworkers int
var verbose, debug, version, configtest bool

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "logstack",
	Short: "a logstash fork in go",
	Long: `Logstack is a logstash fork.

Process Any Data, From Any Source
Centralize data processing of all types
Normalize varying schema and formats
Quickly extend to custom log formats`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	Run: func(cmd *cobra.Command, args []string) {
		if version {
			printVersion()
		} else if configtest {
			testConfig(configPath, configString, args)
		} else if configString != "" {
			startLogstack("", configString, args)
		} else {
			startLogstack(configPath, "", args)
		}
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	// cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.Flags().StringVarP(&configPath, "config", "f", "", "Load the Logstash config from a file or directory")
	RootCmd.Flags().StringVarP(&configString, "eval", "e", "", "Use the given string as the configuration data.")
	RootCmd.Flags().IntVarP(&filterworkers, "filterworkers", "w", runtime.NumCPU(), "number of workers")

	RootCmd.Flags().StringVarP(&logPath, "log", "l", "", "Log to a given path. Default is to log to stdout.")
	RootCmd.Flags().BoolVarP(&verbose, "verbose", "", false, "Increase verbosity to the first level (info), less verbose.")
	RootCmd.Flags().BoolVarP(&debug, "debug", "", false, "Increase verbosity to the last level (trace), more verbose.")

	RootCmd.Flags().BoolVarP(&version, "version", "V", false, "Display the version of Logstash.")
	RootCmd.Flags().BoolVarP(&configtest, "configtest", "t", false, "Test config file or directory")

}

// initConfig reads in config file and ENV variables if set.
// func initConfig() {
// 	if cfgFile != "" { // enable ability to specify config file via flag
// 		viper.SetConfigFile(cfgFile)
// 	}

// 	viper.SetConfigName(".logstack") // name of config file (without extension)
// 	viper.AddConfigPath("$HOME")     // adding home directory as first search path
// 	viper.AutomaticEnv()             // read in environment variables that match

// 	// If a config file is found, read it in.
// 	if err := viper.ReadInConfig(); err == nil {
// 		fmt.Println("Using config file:", viper.ConfigFileUsed())
// 	}
// }
<commit_msg>show help when no config file provided<commit_after>// Copyright © 2016 Valere JEANTET <valere.jeantet@gmail.com>
//
// 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 cmd

import (
	"fmt"
	"os"
	"runtime"

	"github.com/spf13/cobra"
)

var configPath, configString, logPath string
var filterworkers int
var verbose, debug, version, configtest bool

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "logstack",
	Short: "a logstash fork in go",
	Long: `Logstack is a logstash fork.

Process Any Data, From Any Source
Centralize data processing of all types
Normalize varying schema and formats
Quickly extend to custom log formats`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	Run: func(cmd *cobra.Command, args []string) {
		if version {
			printVersion()
		} else if configtest {
			testConfig(configPath, configString, args)
		} else if configString != "" {
			startLogstack("", configString, args)
		} else if configPath != "" {
			startLogstack(configPath, "", args)
		} else {
			cmd.Help()
		}
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	// cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.Flags().StringVarP(&configPath, "config", "f", "", "Load the Logstash config from a file or directory")
	RootCmd.Flags().StringVarP(&configString, "eval", "e", "", "Use the given string as the configuration data.")
	RootCmd.Flags().IntVarP(&filterworkers, "filterworkers", "w", runtime.NumCPU(), "number of workers")

	RootCmd.Flags().StringVarP(&logPath, "log", "l", "", "Log to a given path. Default is to log to stdout.")
	RootCmd.Flags().BoolVarP(&verbose, "verbose", "", false, "Increase verbosity to the first level (info), less verbose.")
	RootCmd.Flags().BoolVarP(&debug, "debug", "", false, "Increase verbosity to the last level (trace), more verbose.")

	RootCmd.Flags().BoolVarP(&version, "version", "V", false, "Display the version of Logstash.")
	RootCmd.Flags().BoolVarP(&configtest, "configtest", "t", false, "Test config file or directory")

}

// initConfig reads in config file and ENV variables if set.
// func initConfig() {
// 	if cfgFile != "" { // enable ability to specify config file via flag
// 		viper.SetConfigFile(cfgFile)
// 	}

// 	viper.SetConfigName(".logstack") // name of config file (without extension)
// 	viper.AddConfigPath("$HOME")     // adding home directory as first search path
// 	viper.AutomaticEnv()             // read in environment variables that match

// 	// If a config file is found, read it in.
// 	if err := viper.ReadInConfig(); err == nil {
// 		fmt.Println("Using config file:", viper.ConfigFileUsed())
// 	}
// }
<|endoftext|>