<commit_before>package services

import (
	"errors"
	"github.com/jinzhu/gorm"
	"github.com/pufferpanel/pufferpanel/database"
	"github.com/pufferpanel/pufferpanel/models"
	"github.com/pufferpanel/pufferpanel/models/view"
	o2 "github.com/pufferpanel/pufferpanel/oauth2"
	oauth "gopkg.in/oauth2.v3"
	oauthErrors "gopkg.in/oauth2.v3/errors"
	"gopkg.in/oauth2.v3/manage"
	"gopkg.in/oauth2.v3/server"
	"log"
	"net/http"
	"time"
)

type OAuthService interface {
	HandleHTTPTokenRequest(writer http.ResponseWriter, request *http.Request)

	GetInfo(token string) (info *view.OAuthTokenInfoViewModel, valid bool, err error)

	Create(user *models.User, server *models.Server, clientId string) (clientSecret string, existing bool, err error)

	UpdateScopes(client *models.ClientInfo, server *models.Server, scopes ...string) (err error)

	Delete(clientId string) (err error)

	GetByClientId(clientId string) (client *models.ClientInfo, exists bool, err error)

	GetByUser(user *models.User) (client *models.ClientInfo, exists bool, err error)

	HasRights(accessToken string, serverId *uint, scope string) (client *models.ClientInfo, allowed bool, err error)

	HasTokenExpired(info oauth.TokenInfo) (expired bool)
}

type oauthService struct {
	server *server.Server
}

var _oauthService *oauthService

func GetOAuthService() (service OAuthService, err error) {
	if _oauthService == nil {
		err = configureServer()
	}
	return _oauthService, err
}

func configureServer() error {
	manager := manage.NewDefaultManager()
	manager.MapClientStorage(&o2.ClientStore{})
	manager.MapTokenStorage(&o2.TokenStore{})

	srv := server.NewServer(server.NewConfig(), manager)
	srv.SetClientInfoHandler(server.ClientFormHandler)

	srv.SetInternalErrorHandler(func(err error) (re *oauthErrors .Response) {
		log.Println("Internal Error:", err.Error())
		return
	})

	srv.SetResponseErrorHandler(func(re *oauthErrors.Response) {
		log.Println("Response Error:", re.Error.Error())
	})

	_oauthService = &oauthService{server: srv}
	return nil
}

func (oauth2 *oauthService) HandleHTTPTokenRequest(writer http.ResponseWriter, request *http.Request) {
	err := oauth2.server.HandleTokenRequest(writer, request)
	if err != nil {
		http.Error(writer, err.Error(), http.StatusInternalServerError)
	}
}

func (oauth2 *oauthService) GetInfo(token string) (info *view.OAuthTokenInfoViewModel, valid bool, err error) {
	ts := &o2.TokenStore{}
	info = &view.OAuthTokenInfoViewModel{Active: false}

	item, err := ts.GetByAccess(token)

	if err != nil {
		return
	}

	db, err := database.GetConnection()
	if err != nil {
		return
	}

	client := &models.ClientInfo{
		ClientID: item.GetClientID(),
	}
	err = db.Set("gorm:auto_preload", true).Where(client).First(client).Error
	if err != nil {
		return
	}

	//see if the access token expiration is after now
	info = view.FromTokenInfo(item, client)
	valid = info.Active

	return
}

func (oauth2 *oauthService) Create(user *models.User, server *models.Server, clientId string) (clientSecret string, existing bool, err error) {
	return
}

func (oauth2 *oauthService) UpdateScopes(client *models.ClientInfo, server *models.Server, scopes ...string) (err error) {
	db, err := database.GetConnection()
	if err != nil {
		return err
	}

	if server != nil && server.ID == 0 {
		res := db.Where(server).First(server)
		if res.Error != nil {
			return res.Error
		}
	}

	if client.ID == 0 {
		var query *gorm.DB
		if server != nil && server.ID != 0 {
			query = db.Preload("ServerScopes", "server_id = ?", server.ID)
		} else {
			query = db.Preload("ServerScopes", "server_id IS NULL")
		}
		res := query.Where(client).First(client)
		if res.Error != nil {
			return res.Error
		}
		if client.ID == 0 {
			return errors.New("no client with given information")
		}
	}

	//delete ones which don't exist on the new list
	for _, v := range client.ServerScopes {
		toDelete := true
		for _, s := range scopes {
			if s == v.Scope {
				toDelete = false
				break
			}
		}
		if toDelete {
			db.Delete(v)
		}
	}

	//add new values
	for _, v := range scopes {
		toAdd := true
		for _, s := range client.ServerScopes {
			if v == s.Scope {
				toAdd = false
				break
			}
		}
		if toAdd {
			replacement := &models.ClientServerScopes{
				Scope: v,
				ClientInfoID: client.ID,
			}
			if server != nil && server.ID != 0{
				replacement.ServerId = &server.ID
			}

			db.Create(replacement)
		}
	}

	return
}

func (oauth2 *oauthService) Delete(clientId string) (err error) {
	db, err := database.GetConnection()
	if err != nil {
		return err
	}

	model := &models.ClientInfo{ClientID: clientId}

	return db.Delete(model).Error
}

func (oauth2 *oauthService) GetByClientId(clientId string) (client *models.ClientInfo, exists bool, err error) {
	db, err := database.GetConnection()
	if err != nil {
		return nil, false, err
	}

	model := &models.ClientInfo{ClientID: clientId}

	res := db.Where(model).First(model)

	return model, model.ID != 0, res.Error
}

func (oauth2 *oauthService) GetByUser(user *models.User) (client *models.ClientInfo, exists bool, err error) {
	db, err := database.GetConnection()
	if err != nil {
		return nil, false, err
	}

	model := &models.ClientInfo{UserID: user.ID}

	res := db.Where(model).First(model)

	return model, model.ID != 0, res.Error
}

func (oauth2 *oauthService) HasRights(accessToken string, serverId *uint, scope string) (client *models.ClientInfo, allowed bool, err error) {
	ts := o2.TokenStore{}

	var ti oauth.TokenInfo
	if  ti, err = ts.GetByAccess(accessToken); err != nil {
		return
	}
	if oauth2.HasTokenExpired(ti) {
		return
	}

	converted, ok := ti.(*models.TokenInfo)
	if !ok {
		err = errors.New("token info state was invalid")
		return
	}

	for _, v := range converted.ClientInfo.ServerScopes {
		if (v.ServerId == nil && serverId == nil) || (v.ServerId == serverId) {
			if v.Scope == scope {
				return &converted.ClientInfo, true, nil
			}
		}
	}

	return &converted.ClientInfo, false, nil
}

func (oauth2 *oauthService) HasTokenExpired(info oauth.TokenInfo) (expired bool) {
	if info == nil {
		return true
	}

	if info.GetAccessCreateAt().Add(info.GetCodeExpiresIn()).Before(time.Now()) {
		return true
	}

	return false
}<commit_msg>Remove need for "admins" to have redundant scopes<commit_after>package services

import (
	"errors"
	"github.com/jinzhu/gorm"
	"github.com/pufferpanel/pufferpanel/database"
	"github.com/pufferpanel/pufferpanel/models"
	"github.com/pufferpanel/pufferpanel/models/view"
	o2 "github.com/pufferpanel/pufferpanel/oauth2"
	oauth "gopkg.in/oauth2.v3"
	oauthErrors "gopkg.in/oauth2.v3/errors"
	"gopkg.in/oauth2.v3/manage"
	"gopkg.in/oauth2.v3/server"
	"log"
	"net/http"
	"time"
)

type OAuthService interface {
	HandleHTTPTokenRequest(writer http.ResponseWriter, request *http.Request)

	GetInfo(token string) (info *view.OAuthTokenInfoViewModel, valid bool, err error)

	Create(user *models.User, server *models.Server, clientId string) (clientSecret string, existing bool, err error)

	UpdateScopes(client *models.ClientInfo, server *models.Server, scopes ...string) (err error)

	Delete(clientId string) (err error)

	GetByClientId(clientId string) (client *models.ClientInfo, exists bool, err error)

	GetByUser(user *models.User) (client *models.ClientInfo, exists bool, err error)

	HasRights(accessToken string, serverId *uint, scope string) (client *models.ClientInfo, allowed bool, err error)

	HasTokenExpired(info oauth.TokenInfo) (expired bool)
}

type oauthService struct {
	server *server.Server
}

var _oauthService *oauthService

func GetOAuthService() (service OAuthService, err error) {
	if _oauthService == nil {
		err = configureServer()
	}
	return _oauthService, err
}

func configureServer() error {
	manager := manage.NewDefaultManager()
	manager.MapClientStorage(&o2.ClientStore{})
	manager.MapTokenStorage(&o2.TokenStore{})

	srv := server.NewServer(server.NewConfig(), manager)
	srv.SetClientInfoHandler(server.ClientFormHandler)

	srv.SetInternalErrorHandler(func(err error) (re *oauthErrors .Response) {
		log.Println("Internal Error:", err.Error())
		return
	})

	srv.SetResponseErrorHandler(func(re *oauthErrors.Response) {
		log.Println("Response Error:", re.Error.Error())
	})

	_oauthService = &oauthService{server: srv}
	return nil
}

func (oauth2 *oauthService) HandleHTTPTokenRequest(writer http.ResponseWriter, request *http.Request) {
	err := oauth2.server.HandleTokenRequest(writer, request)
	if err != nil {
		http.Error(writer, err.Error(), http.StatusInternalServerError)
	}
}

func (oauth2 *oauthService) GetInfo(token string) (info *view.OAuthTokenInfoViewModel, valid bool, err error) {
	ts := &o2.TokenStore{}
	info = &view.OAuthTokenInfoViewModel{Active: false}

	item, err := ts.GetByAccess(token)

	if err != nil {
		return
	}

	db, err := database.GetConnection()
	if err != nil {
		return
	}

	client := &models.ClientInfo{
		ClientID: item.GetClientID(),
	}
	err = db.Set("gorm:auto_preload", true).Where(client).First(client).Error
	if err != nil {
		return
	}

	//see if the access token expiration is after now
	info = view.FromTokenInfo(item, client)
	valid = info.Active

	return
}

func (oauth2 *oauthService) Create(user *models.User, server *models.Server, clientId string) (clientSecret string, existing bool, err error) {
	return
}

func (oauth2 *oauthService) UpdateScopes(client *models.ClientInfo, server *models.Server, scopes ...string) (err error) {
	db, err := database.GetConnection()
	if err != nil {
		return err
	}

	if server != nil && server.ID == 0 {
		res := db.Where(server).First(server)
		if res.Error != nil {
			return res.Error
		}
	}

	if client.ID == 0 {
		var query *gorm.DB
		if server != nil && server.ID != 0 {
			query = db.Preload("ServerScopes", "server_id = ?", server.ID)
		} else {
			query = db.Preload("ServerScopes", "server_id IS NULL")
		}
		res := query.Where(client).First(client)
		if res.Error != nil {
			return res.Error
		}
		if client.ID == 0 {
			return errors.New("no client with given information")
		}
	}

	//delete ones which don't exist on the new list
	for _, v := range client.ServerScopes {
		toDelete := true
		for _, s := range scopes {
			if s == v.Scope {
				toDelete = false
				break
			}
		}
		if toDelete {
			db.Delete(v)
		}
	}

	//add new values
	for _, v := range scopes {
		toAdd := true
		for _, s := range client.ServerScopes {
			if v == s.Scope {
				toAdd = false
				break
			}
		}
		if toAdd {
			replacement := &models.ClientServerScopes{
				Scope: v,
				ClientInfoID: client.ID,
			}
			if server != nil && server.ID != 0{
				replacement.ServerId = &server.ID
			}

			db.Create(replacement)
		}
	}

	return
}

func (oauth2 *oauthService) Delete(clientId string) (err error) {
	db, err := database.GetConnection()
	if err != nil {
		return err
	}

	model := &models.ClientInfo{ClientID: clientId}

	return db.Delete(model).Error
}

func (oauth2 *oauthService) GetByClientId(clientId string) (client *models.ClientInfo, exists bool, err error) {
	db, err := database.GetConnection()
	if err != nil {
		return nil, false, err
	}

	model := &models.ClientInfo{ClientID: clientId}

	res := db.Where(model).First(model)

	return model, model.ID != 0, res.Error
}

func (oauth2 *oauthService) GetByUser(user *models.User) (client *models.ClientInfo, exists bool, err error) {
	db, err := database.GetConnection()
	if err != nil {
		return nil, false, err
	}

	model := &models.ClientInfo{UserID: user.ID}

	res := db.Where(model).First(model)

	return model, model.ID != 0, res.Error
}

func (oauth2 *oauthService) HasRights(accessToken string, serverId *uint, scope string) (client *models.ClientInfo, allowed bool, err error) {
	ts := o2.TokenStore{}

	var ti oauth.TokenInfo
	if  ti, err = ts.GetByAccess(accessToken); err != nil {
		return
	}
	if oauth2.HasTokenExpired(ti) {
		return
	}

	converted, ok := ti.(*models.TokenInfo)
	if !ok {
		err = errors.New("token info state was invalid")
		return
	}

	for _, v := range converted.ClientInfo.ServerScopes {
		if v.ServerId == nil || v.ServerId == serverId {
			if v.Scope == scope {
				return &converted.ClientInfo, true, nil
			}
		}
	}

	return &converted.ClientInfo, false, nil
}

func (oauth2 *oauthService) HasTokenExpired(info oauth.TokenInfo) (expired bool) {
	if info == nil {
		return true
	}

	if info.GetAccessCreateAt().Add(info.GetCodeExpiresIn()).Before(time.Now()) {
		return true
	}

	return false
}<|endoftext|>


<commit_before>package shells

import (
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"path/filepath"
	"strconv"
	"strings"
)

type AbstractShell struct {
}

type ShellWriter interface {
	Variable(variable common.BuildVariable)
	Command(command string, arguments ...string)
	Line(text string)

	IfDirectory(path string)
	IfFile(file string)
	Else()
	EndIf()

	Cd(path string)
	RmDir(path string)
	RmFile(path string)
	Absolute(path string) string

	Print(fmt string, arguments ...interface{})
	Notice(fmt string, arguments ...interface{})
	Warning(fmt string, arguments ...interface{})
	Error(fmt string, arguments ...interface{})
	EmptyLine()
}

func (b *AbstractShell) GetFeatures(features *common.FeaturesInfo) {
	features.Artifacts = true
	features.Cache = true
}

func (s *AbstractShell) GetSupportedOptions() []string {
	return []string{"artifacts", "cache"}
}

func (b *AbstractShell) writeCdBuildDir(w ShellWriter, info common.ShellScriptInfo) {
	w.Cd(info.Build.FullProjectDir())
}

func (b *AbstractShell) writeExports(w ShellWriter, info common.ShellScriptInfo) {
	for _, variable := range info.Build.GetAllVariables() {
		w.Variable(variable)
	}
}

func (b *AbstractShell) writeTLSCAInfo(w ShellWriter, build *common.Build, key string) {
	if build.TLSCAChain != "" {
		w.Variable(common.BuildVariable{
			Key: key,
			Value: build.TLSCAChain,
			Public: true,
			Internal: true,
			File: true,
		})
	}
}

func (b *AbstractShell) writeCloneCmd(w ShellWriter, build *common.Build, projectDir string) {
	w.Notice("Cloning repository...")
	w.RmDir(projectDir)
	w.Command("git", "clone", build.RepoURL, projectDir)
	w.Cd(projectDir)
}

func (b *AbstractShell) writeFetchCmd(w ShellWriter, build *common.Build, projectDir string, gitDir string) {
	w.IfDirectory(gitDir)
	w.Notice("Fetching changes...")
	w.Cd(projectDir)
	w.Command("git", "clean", "-ffdx")
	w.Command("git", "reset", "--hard")
	w.Command("git", "remote", "set-url", "origin", build.RepoURL)
	w.Command("git", "fetch", "origin")
	w.Else()
	b.writeCloneCmd(w, build, projectDir)
	w.EndIf()
}

func (b *AbstractShell) writeCheckoutCmd(w ShellWriter, build *common.Build) {
	w.Notice("Checking out %s as %s...", build.Sha[0:8], build.RefName)
	w.Command("git", "checkout", build.Sha)
}

func (b *AbstractShell) GeneratePreBuild(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)

	build := info.Build
	projectDir := build.FullProjectDir()
	gitDir := filepath.Join(build.FullProjectDir(), ".git")

	b.writeTLSCAInfo(w, info.Build, "GIT_SSL_CAINFO")

	if build.AllowGitFetch {
		b.writeFetchCmd(w, build, projectDir, gitDir)
	} else {
		b.writeCloneCmd(w, build, projectDir)
	}

	b.writeCheckoutCmd(w, build)

	cacheFile := info.Build.CacheFile()
	cacheFile2 := info.Build.CacheFileForRef("master")
	if cacheFile == "" {
		cacheFile = cacheFile2
		cacheFile2 = ""
	}

	// Try to restore from main cache, if not found cache for master
	if cacheFile != "" {
		// If we have cache, restore it
		w.IfFile(cacheFile)
		b.extractFiles(w, info.RunnerCommand, "cache", cacheFile)
		if cacheFile2 != "" {
			w.Else()

			// If we have cache, restore it
			w.IfFile(cacheFile2)
			b.extractFiles(w, info.RunnerCommand, "cache", cacheFile2)
			w.EndIf()
		}
		w.EndIf()
	}
}

func (b *AbstractShell) GenerateCommands(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	commands := info.Build.Commands
	commands = strings.TrimSpace(commands)
	for _, command := range strings.Split(commands, "\n") {
		command = strings.TrimSpace(command)
		if !helpers.BoolOrDefault(info.Build.Runner.DisableVerbose, false) {
			if command != "" {
				w.Notice("$ %s", command)
			} else {
				w.EmptyLine()
			}
		}
		w.Line(command)
	}
}

func (b *AbstractShell) archiveFiles(w ShellWriter, list interface{}, runnerCommand, archiveType, archivePath string) {
	hash, ok := helpers.ToConfigMap(list)
	if !ok {
		return
	}

	if runnerCommand == "" {
		w.Warning("The %s is not supported in this executor.", archiveType)
		return
	}

	args := []string{
		"archive",
		"--file",
		archivePath,
	}

	// Collect paths
	if paths, ok := hash["paths"].([]interface{}); ok {
		for _, artifactPath := range paths {
			if file, ok := artifactPath.(string); ok {
				args = append(args, "--path", file)
			}
		}
	}

	// Archive also untracked files
	if untracked, ok := hash["untracked"].(bool); ok && untracked {
		args = append(args, "--untracked")
	}

	// Skip creating archive
	if len(args) <= 3 {
		return
	}

	// Execute archive command
	w.Notice("Archiving %s...", archiveType)
	w.Command(runnerCommand, args...)
}

func (b *AbstractShell) extractFiles(w ShellWriter, runnerCommand, archiveType, archivePath string) {
	if runnerCommand == "" {
		w.Warning("The %s is not supported in this executor.", archiveType)
		return
	}

	args := []string{
		"extract",
		"--file",
		archivePath,
	}

	// Execute extract command
	w.Notice("Restoring %s...", archiveType)
	w.Command(runnerCommand, args...)
}

func (b *AbstractShell) uploadArtifacts(w ShellWriter, build *common.Build, runnerCommand, archivePath string) {
	if runnerCommand == "" {
		w.Warning("The artifacts uploading is not supported in this executor.")
		return
	}

	args := []string{
		"artifacts",
		"--url",
		build.Runner.URL,
		"--token",
		build.Token,
		"--id",
		strconv.Itoa(build.ID),
		"--file",
		archivePath,
	}

	w.Notice("Uploading artifacts...")
	b.writeTLSCAInfo(w, build, "CI_SERVER_TLS_CA_FILE")
	w.Command(runnerCommand, args...)
}

func (b *AbstractShell) GeneratePostBuild(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	// Find cached files and archive them
	if cacheFile := info.Build.CacheFile(); cacheFile != "" {
		b.archiveFiles(w, info.Build.Options["cache"], info.RunnerCommand, "cache", cacheFile)
	}

	if info.Build.Network != nil {
		// Find artifacts
		b.archiveFiles(w, info.Build.Options["artifacts"], info.RunnerCommand, "artifacts", "artifacts.zip")

		// If archive is created upload it
		w.IfFile("artifacts.zip")
		b.uploadArtifacts(w, info.Build, info.RunnerCommand, "artifacts.zip")
		w.RmFile("aritfacts.zip")
		w.EndIf()
	}
}
<commit_msg>Make `go fmt` happy<commit_after>package shells

import (
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"path/filepath"
	"strconv"
	"strings"
)

type AbstractShell struct {
}

type ShellWriter interface {
	Variable(variable common.BuildVariable)
	Command(command string, arguments ...string)
	Line(text string)

	IfDirectory(path string)
	IfFile(file string)
	Else()
	EndIf()

	Cd(path string)
	RmDir(path string)
	RmFile(path string)
	Absolute(path string) string

	Print(fmt string, arguments ...interface{})
	Notice(fmt string, arguments ...interface{})
	Warning(fmt string, arguments ...interface{})
	Error(fmt string, arguments ...interface{})
	EmptyLine()
}

func (b *AbstractShell) GetFeatures(features *common.FeaturesInfo) {
	features.Artifacts = true
	features.Cache = true
}

func (s *AbstractShell) GetSupportedOptions() []string {
	return []string{"artifacts", "cache"}
}

func (b *AbstractShell) writeCdBuildDir(w ShellWriter, info common.ShellScriptInfo) {
	w.Cd(info.Build.FullProjectDir())
}

func (b *AbstractShell) writeExports(w ShellWriter, info common.ShellScriptInfo) {
	for _, variable := range info.Build.GetAllVariables() {
		w.Variable(variable)
	}
}

func (b *AbstractShell) writeTLSCAInfo(w ShellWriter, build *common.Build, key string) {
	if build.TLSCAChain != "" {
		w.Variable(common.BuildVariable{
			Key:      key,
			Value:    build.TLSCAChain,
			Public:   true,
			Internal: true,
			File:     true,
		})
	}
}

func (b *AbstractShell) writeCloneCmd(w ShellWriter, build *common.Build, projectDir string) {
	w.Notice("Cloning repository...")
	w.RmDir(projectDir)
	w.Command("git", "clone", build.RepoURL, projectDir)
	w.Cd(projectDir)
}

func (b *AbstractShell) writeFetchCmd(w ShellWriter, build *common.Build, projectDir string, gitDir string) {
	w.IfDirectory(gitDir)
	w.Notice("Fetching changes...")
	w.Cd(projectDir)
	w.Command("git", "clean", "-ffdx")
	w.Command("git", "reset", "--hard")
	w.Command("git", "remote", "set-url", "origin", build.RepoURL)
	w.Command("git", "fetch", "origin")
	w.Else()
	b.writeCloneCmd(w, build, projectDir)
	w.EndIf()
}

func (b *AbstractShell) writeCheckoutCmd(w ShellWriter, build *common.Build) {
	w.Notice("Checking out %s as %s...", build.Sha[0:8], build.RefName)
	w.Command("git", "checkout", build.Sha)
}

func (b *AbstractShell) GeneratePreBuild(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)

	build := info.Build
	projectDir := build.FullProjectDir()
	gitDir := filepath.Join(build.FullProjectDir(), ".git")

	b.writeTLSCAInfo(w, info.Build, "GIT_SSL_CAINFO")

	if build.AllowGitFetch {
		b.writeFetchCmd(w, build, projectDir, gitDir)
	} else {
		b.writeCloneCmd(w, build, projectDir)
	}

	b.writeCheckoutCmd(w, build)

	cacheFile := info.Build.CacheFile()
	cacheFile2 := info.Build.CacheFileForRef("master")
	if cacheFile == "" {
		cacheFile = cacheFile2
		cacheFile2 = ""
	}

	// Try to restore from main cache, if not found cache for master
	if cacheFile != "" {
		// If we have cache, restore it
		w.IfFile(cacheFile)
		b.extractFiles(w, info.RunnerCommand, "cache", cacheFile)
		if cacheFile2 != "" {
			w.Else()

			// If we have cache, restore it
			w.IfFile(cacheFile2)
			b.extractFiles(w, info.RunnerCommand, "cache", cacheFile2)
			w.EndIf()
		}
		w.EndIf()
	}
}

func (b *AbstractShell) GenerateCommands(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	commands := info.Build.Commands
	commands = strings.TrimSpace(commands)
	for _, command := range strings.Split(commands, "\n") {
		command = strings.TrimSpace(command)
		if !helpers.BoolOrDefault(info.Build.Runner.DisableVerbose, false) {
			if command != "" {
				w.Notice("$ %s", command)
			} else {
				w.EmptyLine()
			}
		}
		w.Line(command)
	}
}

func (b *AbstractShell) archiveFiles(w ShellWriter, list interface{}, runnerCommand, archiveType, archivePath string) {
	hash, ok := helpers.ToConfigMap(list)
	if !ok {
		return
	}

	if runnerCommand == "" {
		w.Warning("The %s is not supported in this executor.", archiveType)
		return
	}

	args := []string{
		"archive",
		"--file",
		archivePath,
	}

	// Collect paths
	if paths, ok := hash["paths"].([]interface{}); ok {
		for _, artifactPath := range paths {
			if file, ok := artifactPath.(string); ok {
				args = append(args, "--path", file)
			}
		}
	}

	// Archive also untracked files
	if untracked, ok := hash["untracked"].(bool); ok && untracked {
		args = append(args, "--untracked")
	}

	// Skip creating archive
	if len(args) <= 3 {
		return
	}

	// Execute archive command
	w.Notice("Archiving %s...", archiveType)
	w.Command(runnerCommand, args...)
}

func (b *AbstractShell) extractFiles(w ShellWriter, runnerCommand, archiveType, archivePath string) {
	if runnerCommand == "" {
		w.Warning("The %s is not supported in this executor.", archiveType)
		return
	}

	args := []string{
		"extract",
		"--file",
		archivePath,
	}

	// Execute extract command
	w.Notice("Restoring %s...", archiveType)
	w.Command(runnerCommand, args...)
}

func (b *AbstractShell) uploadArtifacts(w ShellWriter, build *common.Build, runnerCommand, archivePath string) {
	if runnerCommand == "" {
		w.Warning("The artifacts uploading is not supported in this executor.")
		return
	}

	args := []string{
		"artifacts",
		"--url",
		build.Runner.URL,
		"--token",
		build.Token,
		"--id",
		strconv.Itoa(build.ID),
		"--file",
		archivePath,
	}

	w.Notice("Uploading artifacts...")
	b.writeTLSCAInfo(w, build, "CI_SERVER_TLS_CA_FILE")
	w.Command(runnerCommand, args...)
}

func (b *AbstractShell) GeneratePostBuild(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	// Find cached files and archive them
	if cacheFile := info.Build.CacheFile(); cacheFile != "" {
		b.archiveFiles(w, info.Build.Options["cache"], info.RunnerCommand, "cache", cacheFile)
	}

	if info.Build.Network != nil {
		// Find artifacts
		b.archiveFiles(w, info.Build.Options["artifacts"], info.RunnerCommand, "artifacts", "artifacts.zip")

		// If archive is created upload it
		w.IfFile("artifacts.zip")
		b.uploadArtifacts(w, info.Build, info.RunnerCommand, "artifacts.zip")
		w.RmFile("aritfacts.zip")
		w.EndIf()
	}
}
<|endoftext|>


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

// The following enables go generate to generate the doc.go file.
//go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go .

package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/security"
	"v.io/v23/verror"
	"v.io/x/lib/cmdline"
	"v.io/x/ref/lib/v23cmd"
	_ "v.io/x/ref/runtime/factories/generic"
)

var (
	flagConfigFile   string
	flagKubectlBin   string
	flagGcloudBin    string
	flagResourceFile string
	flagVerbose      bool
	flagTag          string
	flagWait         bool
)

func main() {
	cmdline.HideGlobalFlagsExcept()

	cmd := &cmdline.Command{
		Name:  "vkube",
		Short: "Manages Vanadium applications on kubernetes",
		Long:  "Manages Vanadium applications on kubernetes",
		Children: []*cmdline.Command{
			cmdStart,
			cmdUpdate,
			cmdStop,
			cmdStartClusterAgent,
			cmdStopClusterAgent,
			cmdClaimClusterAgent,
			cmdBuildDockerImages,
			cmdKubectl,
		},
	}
	cmd.Flags.StringVar(&flagConfigFile, "config", "vkube.cfg", "The 'vkube.cfg' file to use.")
	cmd.Flags.StringVar(&flagKubectlBin, "kubectl", "kubectl", "The 'kubectl' binary to use.")
	cmd.Flags.StringVar(&flagGcloudBin, "gcloud", "gcloud", "The 'gcloud' binary to use.")

	cmdStart.Flags.StringVar(&flagResourceFile, "f", "", "Filename to use to create the kubernetes resource.")
	cmdStart.Flags.BoolVar(&flagWait, "wait", false, "Wait for at least one replica to be ready.")

	cmdUpdate.Flags.StringVar(&flagResourceFile, "f", "", "Filename to use to update the kubernetes resource.")
	cmdUpdate.Flags.BoolVar(&flagWait, "wait", false, "Wait for at least one replica to be ready after the update.")

	cmdStop.Flags.StringVar(&flagResourceFile, "f", "", "Filename to use to stop the kubernetes resource.")

	cmdStartClusterAgent.Flags.BoolVar(&flagWait, "wait", false, "Wait for the cluster agent to be ready.")

	cmdBuildDockerImages.Flags.BoolVar(&flagVerbose, "v", false, "When true, the output is more verbose.")
	cmdBuildDockerImages.Flags.StringVar(&flagTag, "tag", "", "The tag to add to the docker images. If empty, the current timestamp is used.")

	cmdline.Main(cmd)
}

func kubeCmdRunner(kcmd func(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error) cmdline.Runner {
	return v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
		config, err := readConfig(flagConfigFile)
		if err != nil {
			return err
		}
		f, err := ioutil.TempFile("", "kubeconfig-")
		if err != nil {
			return err
		}
		os.Setenv("KUBECONFIG", f.Name())
		defer os.Remove(f.Name())
		f.Close()

		if out, err := exec.Command(flagGcloudBin, "container", "clusters", "get-credentials", config.Cluster, "--project", config.Project, "--zone", config.Zone).CombinedOutput(); err != nil {
			return fmt.Errorf("failed to get credentials for %q: %v: %s", config.Cluster, err, out)
		}
		return kcmd(ctx, env, args, config)
	})
}

var cmdStart = &cmdline.Command{
	Runner:   kubeCmdRunner(runCmdStart),
	Name:     "start",
	Short:    "Starts an application.",
	Long:     "Starts an application.",
	ArgsName: "<extension>",
	ArgsLong: "<extension> The blessing name extension to give to the application.",
}

func runCmdStart(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if expected, got := 1, len(args); expected != got {
		return env.UsageErrorf("start: incorrect number of arguments, expected %d, got %d", expected, got)
	}
	extension := args[0]
	if flagResourceFile == "" {
		return fmt.Errorf("-f must be specified.")
	}
	rc, err := readReplicationControllerConfig(flagResourceFile)
	if err != nil {
		return err
	}
	for _, v := range []string{"spec.template.metadata.labels.application", "spec.template.metadata.labels.version"} {
		if rc.getString(v) == "" {
			fmt.Fprintf(env.Stderr, "WARNING: %q is not set. Rolling updates will not work.\n", v)
		}
	}
	agentAddr, err := findClusterAgent(config, true)
	if err != nil {
		return err
	}
	secretName, err := makeSecretName()
	if err != nil {
		return err
	}
	namespace := rc.getString("metadata.namespace")
	appName := rc.getString("spec.template.metadata.labels.application")
	if n, err := findReplicationControllerNamesForApp(appName, namespace); err != nil {
		return err
	} else if len(n) != 0 {
		return fmt.Errorf("replication controller for application=%q already running: %q", appName, n)
	}
	if err := createSecret(ctx, secretName, namespace, agentAddr, extension); err != nil {
		return err
	}
	fmt.Fprintln(env.Stdout, "Created secret successfully.")

	if err := createReplicationController(ctx, config, rc, secretName); err != nil {
		if err := deleteSecret(ctx, config, secretName, rootBlessings(ctx), namespace); err != nil {
			ctx.Error(err)
		}
		return err
	}
	fmt.Fprintln(env.Stdout, "Created replication controller successfully.")
	if flagWait {
		if err := waitForReadyPods(appName, namespace); err != nil {
			return err
		}
		fmt.Fprintln(env.Stdout, "Application is running.")
	}
	return nil
}

var cmdUpdate = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdUpdate),
	Name:   "update",
	Short:  "Updates an application.",
	Long:   "Updates an application to a new version with a rolling update, preserving the existing blessings.",
}

func runCmdUpdate(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if flagResourceFile == "" {
		return fmt.Errorf("-f must be specified.")
	}
	rc, err := readReplicationControllerConfig(flagResourceFile)
	if err != nil {
		return err
	}
	if err := updateReplicationController(ctx, config, rc, env.Stdout, env.Stderr); err != nil {
		return err
	}
	fmt.Fprintln(env.Stdout, "Updated replication controller successfully.")
	if flagWait {
		namespace := rc.getString("metadata.namespace")
		appName := rc.getString("spec.template.metadata.labels.application")
		if err := waitForReadyPods(appName, namespace); err != nil {
			return err
		}
		fmt.Fprintln(env.Stdout, "Application is running.")
	}
	return nil
}

var cmdStop = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdStop),
	Name:   "stop",
	Short:  "Stops an application.",
	Long:   "Stops an application.",
}

func runCmdStop(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if flagResourceFile == "" {
		return fmt.Errorf("-f must be specified.")
	}
	rc, err := readReplicationControllerConfig(flagResourceFile)
	if err != nil {
		return err
	}
	name := rc.getString("metadata.name")
	if name == "" {
		return fmt.Errorf("metadata.name must be set")
	}
	namespace := rc.getString("metadata.namespace")
	secretName, rootBlessings, err := findPodAttributes(name, namespace)
	if err != nil {
		return err
	}
	if out, err := kubectl("--namespace="+namespace, "stop", "rc", name); err != nil {
		return fmt.Errorf("failed to stop replication controller: %v: %s", err, out)
	}
	fmt.Fprintln(env.Stdout, "Stopping replication controller.")
	if err := deleteSecret(ctx, config, secretName, rootBlessings, namespace); err != nil {
		return fmt.Errorf("failed to delete secret: %v", err)
	}
	fmt.Fprintln(env.Stdout, "Deleting secret.")
	return nil
}

var cmdStartClusterAgent = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdStartClusterAgent),
	Name:   "start-cluster-agent",
	Short:  "Starts the cluster agent.",
	Long:   "Starts the cluster agent.",
}

func runCmdStartClusterAgent(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if err := createClusterAgent(ctx, config); err != nil {
		return err
	}
	fmt.Fprintln(env.Stdout, "Starting cluster agent.")
	if flagWait {
		if err := waitForReadyPods(clusterAgentApplicationName, config.ClusterAgent.Namespace); err != nil {
			return err
		}
		for {
			if _, err := findClusterAgent(config, true); err == nil {
				break
			}
			time.Sleep(time.Second)
		}
		fmt.Fprintf(env.Stdout, "Cluster agent is ready.\n")
	}
	return nil
}

var cmdStopClusterAgent = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdStopClusterAgent),
	Name:   "stop-cluster-agent",
	Short:  "Stops the cluster agent.",
	Long:   "Stops the cluster agent.",
}

func runCmdStopClusterAgent(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if err := stopClusterAgent(config); err != nil {
		return err
	}
	fmt.Fprintln(env.Stdout, "Stopping cluster agent.")
	return nil
}

var cmdClaimClusterAgent = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdClaimClusterAgent),
	Name:   "claim-cluster-agent",
	Short:  "Claims the cluster agent.",
	Long:   "Claims the cluster agent.",
}

func runCmdClaimClusterAgent(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	myBlessings, _ := v23.GetPrincipal(ctx).BlessingStore().Default()
	claimer := clusterAgentClaimer(config)
	if !myBlessings.CouldHaveNames([]string{claimer}) {
		return fmt.Errorf("principal isn't the expected claimer: got %q, expected %q", myBlessings, claimer)
	}
	extension := strings.TrimPrefix(config.ClusterAgent.Blessing, claimer+security.ChainSeparator)
	if err := claimClusterAgent(ctx, config, extension); err != nil {
		if verror.ErrorID(err) == verror.ErrUnknownMethod.ID {
			return fmt.Errorf("already claimed")
		}
		return err
	}
	fmt.Fprintln(env.Stdout, "Claimed cluster agent successfully.")
	return nil
}

var cmdBuildDockerImages = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdBuildDockerImages),
	Name:   "build-docker-images",
	Short:  "Builds the docker images for the cluster and pod agents.",
	Long:   "Builds the docker images for the cluster and pod agents.",
}

func runCmdBuildDockerImages(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	return buildDockerImages(config, flagTag, flagVerbose, env.Stdout)
}

var cmdKubectl = &cmdline.Command{
	Runner:   kubeCmdRunner(runCmdKubectl),
	Name:     "kubectl",
	Short:    "Runs kubectl on the cluster defined in vkube.cfg.",
	Long:     "Runs kubectl on the cluster defined in vkube.cfg.",
	ArgsName: "-- <kubectl args>",
	ArgsLong: "<kubectl args> are passed directly to the kubectl command.",
}

func runCmdKubectl(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	cmd := exec.Command(flagKubectlBin, args...)
	cmd.Stdin = env.Stdin
	cmd.Stdout = env.Stdout
	cmd.Stderr = env.Stderr
	return cmd.Run()
}
<commit_msg>services/cluster/vkube: Show the cluster<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The following enables go generate to generate the doc.go file.
//go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go .

package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/security"
	"v.io/v23/verror"
	"v.io/x/lib/cmdline"
	"v.io/x/ref/lib/v23cmd"
	_ "v.io/x/ref/runtime/factories/generic"
)

var (
	flagConfigFile   string
	flagKubectlBin   string
	flagGcloudBin    string
	flagResourceFile string
	flagVerbose      bool
	flagTag          string
	flagWait         bool
)

func main() {
	cmdline.HideGlobalFlagsExcept()

	cmd := &cmdline.Command{
		Name:  "vkube",
		Short: "Manages Vanadium applications on kubernetes",
		Long:  "Manages Vanadium applications on kubernetes",
		Children: []*cmdline.Command{
			cmdStart,
			cmdUpdate,
			cmdStop,
			cmdStartClusterAgent,
			cmdStopClusterAgent,
			cmdClaimClusterAgent,
			cmdBuildDockerImages,
			cmdKubectl,
		},
	}
	cmd.Flags.StringVar(&flagConfigFile, "config", "vkube.cfg", "The 'vkube.cfg' file to use.")
	cmd.Flags.StringVar(&flagKubectlBin, "kubectl", "kubectl", "The 'kubectl' binary to use.")
	cmd.Flags.StringVar(&flagGcloudBin, "gcloud", "gcloud", "The 'gcloud' binary to use.")

	cmdStart.Flags.StringVar(&flagResourceFile, "f", "", "Filename to use to create the kubernetes resource.")
	cmdStart.Flags.BoolVar(&flagWait, "wait", false, "Wait for at least one replica to be ready.")

	cmdUpdate.Flags.StringVar(&flagResourceFile, "f", "", "Filename to use to update the kubernetes resource.")
	cmdUpdate.Flags.BoolVar(&flagWait, "wait", false, "Wait for at least one replica to be ready after the update.")

	cmdStop.Flags.StringVar(&flagResourceFile, "f", "", "Filename to use to stop the kubernetes resource.")

	cmdStartClusterAgent.Flags.BoolVar(&flagWait, "wait", false, "Wait for the cluster agent to be ready.")

	cmdBuildDockerImages.Flags.BoolVar(&flagVerbose, "v", false, "When true, the output is more verbose.")
	cmdBuildDockerImages.Flags.StringVar(&flagTag, "tag", "", "The tag to add to the docker images. If empty, the current timestamp is used.")

	cmdline.Main(cmd)
}

func kubeCmdRunner(kcmd func(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error) cmdline.Runner {
	return v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
		config, err := readConfig(flagConfigFile)
		if err != nil {
			return err
		}
		f, err := ioutil.TempFile("", "kubeconfig-")
		if err != nil {
			return err
		}
		os.Setenv("KUBECONFIG", f.Name())
		defer os.Remove(f.Name())
		f.Close()

		fmt.Fprintf(env.Stderr, "Project: %s Zone: %s Cluster: %s\n\n", config.Project, config.Zone, config.Cluster)
		if out, err := exec.Command(flagGcloudBin, "container", "clusters", "get-credentials", config.Cluster, "--project", config.Project, "--zone", config.Zone).CombinedOutput(); err != nil {
			return fmt.Errorf("failed to get credentials for %q: %v: %s", config.Cluster, err, out)
		}
		return kcmd(ctx, env, args, config)
	})
}

var cmdStart = &cmdline.Command{
	Runner:   kubeCmdRunner(runCmdStart),
	Name:     "start",
	Short:    "Starts an application.",
	Long:     "Starts an application.",
	ArgsName: "<extension>",
	ArgsLong: "<extension> The blessing name extension to give to the application.",
}

func runCmdStart(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if expected, got := 1, len(args); expected != got {
		return env.UsageErrorf("start: incorrect number of arguments, expected %d, got %d", expected, got)
	}
	extension := args[0]
	if flagResourceFile == "" {
		return fmt.Errorf("-f must be specified.")
	}
	rc, err := readReplicationControllerConfig(flagResourceFile)
	if err != nil {
		return err
	}
	for _, v := range []string{"spec.template.metadata.labels.application", "spec.template.metadata.labels.version"} {
		if rc.getString(v) == "" {
			fmt.Fprintf(env.Stderr, "WARNING: %q is not set. Rolling updates will not work.\n", v)
		}
	}
	agentAddr, err := findClusterAgent(config, true)
	if err != nil {
		return err
	}
	secretName, err := makeSecretName()
	if err != nil {
		return err
	}
	namespace := rc.getString("metadata.namespace")
	appName := rc.getString("spec.template.metadata.labels.application")
	if n, err := findReplicationControllerNamesForApp(appName, namespace); err != nil {
		return err
	} else if len(n) != 0 {
		return fmt.Errorf("replication controller for application=%q already running: %q", appName, n)
	}
	if err := createSecret(ctx, secretName, namespace, agentAddr, extension); err != nil {
		return err
	}
	fmt.Fprintln(env.Stdout, "Created secret successfully.")

	if err := createReplicationController(ctx, config, rc, secretName); err != nil {
		if err := deleteSecret(ctx, config, secretName, rootBlessings(ctx), namespace); err != nil {
			ctx.Error(err)
		}
		return err
	}
	fmt.Fprintln(env.Stdout, "Created replication controller successfully.")
	if flagWait {
		if err := waitForReadyPods(appName, namespace); err != nil {
			return err
		}
		fmt.Fprintln(env.Stdout, "Application is running.")
	}
	return nil
}

var cmdUpdate = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdUpdate),
	Name:   "update",
	Short:  "Updates an application.",
	Long:   "Updates an application to a new version with a rolling update, preserving the existing blessings.",
}

func runCmdUpdate(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if flagResourceFile == "" {
		return fmt.Errorf("-f must be specified.")
	}
	rc, err := readReplicationControllerConfig(flagResourceFile)
	if err != nil {
		return err
	}
	if err := updateReplicationController(ctx, config, rc, env.Stdout, env.Stderr); err != nil {
		return err
	}
	fmt.Fprintln(env.Stdout, "Updated replication controller successfully.")
	if flagWait {
		namespace := rc.getString("metadata.namespace")
		appName := rc.getString("spec.template.metadata.labels.application")
		if err := waitForReadyPods(appName, namespace); err != nil {
			return err
		}
		fmt.Fprintln(env.Stdout, "Application is running.")
	}
	return nil
}

var cmdStop = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdStop),
	Name:   "stop",
	Short:  "Stops an application.",
	Long:   "Stops an application.",
}

func runCmdStop(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if flagResourceFile == "" {
		return fmt.Errorf("-f must be specified.")
	}
	rc, err := readReplicationControllerConfig(flagResourceFile)
	if err != nil {
		return err
	}
	name := rc.getString("metadata.name")
	if name == "" {
		return fmt.Errorf("metadata.name must be set")
	}
	namespace := rc.getString("metadata.namespace")
	secretName, rootBlessings, err := findPodAttributes(name, namespace)
	if err != nil {
		return err
	}
	if out, err := kubectl("--namespace="+namespace, "stop", "rc", name); err != nil {
		return fmt.Errorf("failed to stop replication controller: %v: %s", err, out)
	}
	fmt.Fprintln(env.Stdout, "Stopping replication controller.")
	if err := deleteSecret(ctx, config, secretName, rootBlessings, namespace); err != nil {
		return fmt.Errorf("failed to delete secret: %v", err)
	}
	fmt.Fprintln(env.Stdout, "Deleting secret.")
	return nil
}

var cmdStartClusterAgent = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdStartClusterAgent),
	Name:   "start-cluster-agent",
	Short:  "Starts the cluster agent.",
	Long:   "Starts the cluster agent.",
}

func runCmdStartClusterAgent(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if err := createClusterAgent(ctx, config); err != nil {
		return err
	}
	fmt.Fprintln(env.Stdout, "Starting cluster agent.")
	if flagWait {
		if err := waitForReadyPods(clusterAgentApplicationName, config.ClusterAgent.Namespace); err != nil {
			return err
		}
		for {
			if _, err := findClusterAgent(config, true); err == nil {
				break
			}
			time.Sleep(time.Second)
		}
		fmt.Fprintf(env.Stdout, "Cluster agent is ready.\n")
	}
	return nil
}

var cmdStopClusterAgent = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdStopClusterAgent),
	Name:   "stop-cluster-agent",
	Short:  "Stops the cluster agent.",
	Long:   "Stops the cluster agent.",
}

func runCmdStopClusterAgent(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	if err := stopClusterAgent(config); err != nil {
		return err
	}
	fmt.Fprintln(env.Stdout, "Stopping cluster agent.")
	return nil
}

var cmdClaimClusterAgent = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdClaimClusterAgent),
	Name:   "claim-cluster-agent",
	Short:  "Claims the cluster agent.",
	Long:   "Claims the cluster agent.",
}

func runCmdClaimClusterAgent(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	myBlessings, _ := v23.GetPrincipal(ctx).BlessingStore().Default()
	claimer := clusterAgentClaimer(config)
	if !myBlessings.CouldHaveNames([]string{claimer}) {
		return fmt.Errorf("principal isn't the expected claimer: got %q, expected %q", myBlessings, claimer)
	}
	extension := strings.TrimPrefix(config.ClusterAgent.Blessing, claimer+security.ChainSeparator)
	if err := claimClusterAgent(ctx, config, extension); err != nil {
		if verror.ErrorID(err) == verror.ErrUnknownMethod.ID {
			return fmt.Errorf("already claimed")
		}
		return err
	}
	fmt.Fprintln(env.Stdout, "Claimed cluster agent successfully.")
	return nil
}

var cmdBuildDockerImages = &cmdline.Command{
	Runner: kubeCmdRunner(runCmdBuildDockerImages),
	Name:   "build-docker-images",
	Short:  "Builds the docker images for the cluster and pod agents.",
	Long:   "Builds the docker images for the cluster and pod agents.",
}

func runCmdBuildDockerImages(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	return buildDockerImages(config, flagTag, flagVerbose, env.Stdout)
}

var cmdKubectl = &cmdline.Command{
	Runner:   kubeCmdRunner(runCmdKubectl),
	Name:     "kubectl",
	Short:    "Runs kubectl on the cluster defined in vkube.cfg.",
	Long:     "Runs kubectl on the cluster defined in vkube.cfg.",
	ArgsName: "-- <kubectl args>",
	ArgsLong: "<kubectl args> are passed directly to the kubectl command.",
}

func runCmdKubectl(ctx *context.T, env *cmdline.Env, args []string, config *vkubeConfig) error {
	cmd := exec.Command(flagKubectlBin, args...)
	cmd.Stdin = env.Stdin
	cmd.Stdout = env.Stdout
	cmd.Stderr = env.Stderr
	return cmd.Run()
}
<|endoftext|>


<commit_before>package context

import (
	"fmt"
	"os"
	"testing"
)

type MockFileIO struct {
	data map[string][]byte
}

func (mock *MockFileIO) ReadFile(path string) ([]byte, error) {
	if contents, ok := mock.data[path]; ok {
		return contents, nil
	}
	return nil, fmt.Errorf("Failed to read file at path: `%s`", path)
}

func (mock *MockFileIO) WriteFile(path string, data []byte, perm os.FileMode) error {
	mock.data[path] = data
	return nil
}

func (mock *MockFileIO) Stat(path string) (os.FileInfo, error) {
	if _, ok := mock.data[path]; ok {
		return nil, nil
	}
	return nil, fmt.Errorf("Failed to stat file at path: `%s`", path)
}

func TestValidateDockercfgWithValidData(t *testing.T) {
	mockIO := &MockFileIO{data: map[string][]byte{"path": []byte(`
        {
            "https://d.ims.io": {
                "auth": "StopLookingAtMySecretsYouJerk=",
                "email": ""
            }
        }`)}}
	if err := validateDockercfg("path", mockIO); err != nil {
		t.Fatal(err)
	}
}

func TestValidateDockercfgWithInvalidData(t *testing.T) {
	mockIO := &MockFileIO{data: map[string][]byte{"path": []byte(`
        {
            "https://d.ims.io": {
                "auth": "StopLookingAtMySecretsYouJerk=",
                "email": ""
            },
        }`)}}
	if err := validateDockercfg("path", mockIO); err == nil {
		t.Fatal(err)
	}
}

func TestValidateDockercfgWithInvalidPath(t *testing.T) {
	mockIO := &MockFileIO{data: map[string][]byte{"path": []byte(`
        {
            "https://d.ims.io": {
                "auth": "StopLookingAtMySecretsYouJerk=",
                "email": ""
            }
        }`)}}
	if err := validateDockercfg("badpath", mockIO); err == nil {
		t.Fatal(err)
	}
}
<commit_msg>Remove commands_test.go<commit_after><|endoftext|>


<commit_before>package main

import (
  "log"
  "errors"
  "os/exec"
  "strings"
)

type DependencyItem struct {
  targetRelativePath string
  originalPath string
}

type AppDeployer struct {
  processedLibs map[string]bool

  libsChannel chan string
  copyChannel chan DependencyItem
  stripChannel chan string
  rpathChannel chan string
  qtChannel chan string

  additionalLibPaths []string
  destinationPath string
}

func (ad *AppDeployer) DeployApp(exePath string) {
  go func() { ad.libsChannel <- exePath }()
  ad.processLibs()
}

func (ad *AppDeployer) processLibs() {
  for filepath := range ad.libsChannel {
    if _, ok := ad.processedLibs[filepath]; !ok {
      dependencies, err := findLddDependencies(filepath)
      if (err != nil) {
        log.Println(err)
        continue
      }

      ad.processedLibs[filepath] = true
      //go func() { ad.copyChannel <- &{DependencyItem{originalPath: filepath} }()

      for _, dependPath := range dependencies {
        if _, ok := ad.processedLibs[dependPath]; !ok {
          go func() { ad.libsChannel <- dependPath }()
        }
      }
    }
  }
}

func findLddDependencies(filepath string) ([]string, error) {
  log.Printf("Inspecting %v", filepath)

  out, err := exec.Command("ldd", filepath).Output()
  if err != nil { return nil, err }

  dependencies := make([]string, 10)

  output := string(out)
  lines := strings.Split(output, "\n")
  for _, line := range lines {
    line = strings.TrimSpace(line)
    libpath, err := parseLddOutputLine(line)

    if err != nil {
      log.Printf("Found dependency %v", libpath)
      dependencies = append(dependencies, libpath)
    } else {
      log.Printf("Cannot parse ldd line: %v", line)
    }
  }

  return dependencies, nil
}

func parseLddOutputLine(line string) (string, error) {
  if len(line) == 0 { return "", errors.New("Empty") }

  var libpath string

  if strings.Contains(line, " => ") {
    parts := strings.Split(line, " => ")

    if len(parts) != 2 {
      return "", errors.New("Wrong format")
    }

    shortpath := strings.TrimSpace(parts[0])

    if parts[1] == "not found" { return parts[0], nil }
    if len(strings.TrimSpace(parts[1])) == 0 { return "", errors.New("vdso") }

    lastUseful := strings.LastIndex(parts[1], "(0x")
    if lastUseful != -1 {
      libpath = strings.TrimSpace(parts[1][:lastUseful])
    } else {
      libpath = shortpath
    }
  } else {
    log.Printf("Skipping ldd line: %v", line)
  }

  return libpath, nil
}
<commit_msg>Minor fixes<commit_after>package main

import (
  "log"
  "errors"
  "os/exec"
  "strings"
)

type DependencyItem struct {
  targetRelativePath string
  originalPath string
}

type AppDeployer struct {
  processedLibs map[string]bool

  libsChannel chan string
  copyChannel chan DependencyItem
  stripChannel chan string
  rpathChannel chan string
  qtChannel chan string

  additionalLibPaths []string
  destinationPath string
}

func (ad *AppDeployer) DeployApp(exePath string) {
  go func() { ad.libsChannel <- exePath }()
  ad.processLibs()
}

func (ad *AppDeployer) processLibs() {
  for filepath := range ad.libsChannel {
    if _, ok := ad.processedLibs[filepath]; !ok {
      dependencies, err := findLddDependencies(filepath)
      if (err != nil) {
        log.Println(err)
        continue
      }

      ad.processedLibs[filepath] = true
      //go func() { ad.copyChannel <- &{DependencyItem{originalPath: filepath} }()

      for _, dependPath := range dependencies {
        if _, ok := ad.processedLibs[dependPath]; !ok {
          go func() { ad.libsChannel <- dependPath }()
        }
      }
    }
  }
}

func findLddDependencies(filepath string) ([]string, error) {
  log.Printf("Inspecting %v", filepath)

  out, err := exec.Command("ldd", filepath).Output()
  if err != nil { return nil, err }

  dependencies := make([]string, 10)

  output := string(out)
  lines := strings.Split(output, "\n")
  for _, line := range lines {
    line = strings.TrimSpace(line)
    libpath, err := parseLddOutputLine(line)

    if err == nil {
      log.Printf("Found dependency %v", libpath)
      dependencies = append(dependencies, libpath)
    } else {
      log.Printf("Cannot parse ldd line: %v", line)
    }
  }

  return dependencies, nil
}

func parseLddOutputLine(line string) (string, error) {
  if len(line) == 0 { return "", errors.New("Empty") }

  var libpath string

  if strings.Contains(line, " => ") {
    parts := strings.Split(line, " => ")

    if len(parts) != 2 {
      return "", errors.New("Wrong format")
    }

    shortpath := strings.TrimSpace(parts[0])

    if parts[1] == "not found" { return parts[0], nil }
    if len(strings.TrimSpace(parts[1])) == 0 { return "", errors.New("vdso") }

    lastUseful := strings.LastIndex(parts[1], "(0x")
    if lastUseful != -1 {
      libpath = strings.TrimSpace(parts[1][:lastUseful])
    } else {
      libpath = shortpath
    }
  } else {
    log.Printf("Skipping ldd line: %v", line)
  }

  return libpath, nil
}
<|endoftext|>


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

/*

Cgo enables the creation of Go packages that call C code.

Usage: cgo [compiler options] file.go

The compiler options are passed through uninterpreted when
invoking gcc to compile the C parts of the package.

The input file.go is a syntactically valid Go source file that imports
the pseudo-package "C" and then refers to types such as C.size_t,
variables such as C.stdout, or functions such as C.putchar.

If the import of "C" is immediately preceded by a comment, that
comment is used as a header when compiling the C parts of
the package.  For example:

	// #include <stdio.h>
	// #include <errno.h>
	import "C"

CFLAGS and LDFLAGS may be defined with pseudo #cgo directives
within these comments to tweak the behavior of gcc.  Values defined
in multiple directives are concatenated together.  Options prefixed
by $GOOS, $GOARCH, or $GOOS/$GOARCH are only defined in matching
systems.  For example:

	// #cgo CFLAGS: -DPNG_DEBUG=1
	// #cgo linux CFLAGS: -DLINUX=1
	// #cgo LDFLAGS: -lpng
	// #include <png.h>
	import "C"

Alternatively, CFLAGS and LDFLAGS may be obtained via the pkg-config
tool using a '#cgo pkg-config:' directive followed by the package names.
For example:

	// #cgo pkg-config: png cairo
	// #include <png.h>
	import "C"

Within the Go file, C identifiers or field names that are keywords in Go
can be accessed by prefixing them with an underscore: if x points at a C
struct with a field named "type", x._type accesses the field.

The standard C numeric types are available under the names
C.char, C.schar (signed char), C.uchar (unsigned char),
C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
C.long, C.ulong (unsigned long), C.longlong (long long),
C.ulonglong (unsigned long long), C.float, C.double.
The C type void* is represented by Go's unsafe.Pointer.

To access a struct, union, or enum type directly, prefix it with
struct_, union_, or enum_, as in C.struct_stat.

Any C function that returns a value may be called in a multiple
assignment context to retrieve both the return value and the
C errno variable as an error.  For example:

	n, err := C.atoi("abc")

In C, a function argument written as a fixed size array
actually requires a pointer to the first element of the array.
C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot.  In Go, you must pass
the pointer to the first element explicitly: C.f(&x[0]).

A few special functions convert between Go and C types
by making copies of the data.  In pseudo-Go definitions:

	// Go string to C string
	// The C string is allocated in the C heap using malloc.
	// It is the caller's responsibility to arrange for it to be
	// freed, such as by calling C.free.
	func C.CString(string) *C.char

	// C string to Go string
	func C.GoString(*C.char) string

	// C string, length to Go string
	func C.GoStringN(*C.char, C.int) string

	// C pointer, length to Go []byte
	func C.GoBytes(unsafe.Pointer, C.int) []byte

Go functions can be exported for use by C code in the following way:

	//export MyFunction
	func MyFunction(arg1, arg2 int, arg3 string) int64 {...}

	//export MyFunction2
	func MyFunction2(arg1, arg2 int, arg3 string) (int64, C.char*) {...}

They will be available in the C code as:

	extern int64 MyFunction(int arg1, int arg2, GoString arg3);
	extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);

found in _cgo_export.h generated header. Functions with multiple
return values are mapped to functions returning a struct.
Not all Go types can be mapped to C types in a useful way.

Cgo transforms the input file into four output files: two Go source
files, a C file for 6c (or 8c or 5c), and a C file for gcc.

The standard package makefile rules in Make.pkg automate the
process of using cgo.  See $GOROOT/misc/cgo/stdio and
$GOROOT/misc/cgo/gmp for examples.

Cgo does not yet work with gccgo.

See "C? Go? Cgo!" for an introduction to using cgo:
http://blog.golang.org/2011/03/c-go-cgo.html
*/
package documentation
<commit_msg>cgo: fix typo in the documentation<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*

Cgo enables the creation of Go packages that call C code.

Usage: cgo [compiler options] file.go

The compiler options are passed through uninterpreted when
invoking gcc to compile the C parts of the package.

The input file.go is a syntactically valid Go source file that imports
the pseudo-package "C" and then refers to types such as C.size_t,
variables such as C.stdout, or functions such as C.putchar.

If the import of "C" is immediately preceded by a comment, that
comment is used as a header when compiling the C parts of
the package.  For example:

	// #include <stdio.h>
	// #include <errno.h>
	import "C"

CFLAGS and LDFLAGS may be defined with pseudo #cgo directives
within these comments to tweak the behavior of gcc.  Values defined
in multiple directives are concatenated together.  Options prefixed
by $GOOS, $GOARCH, or $GOOS/$GOARCH are only defined in matching
systems.  For example:

	// #cgo CFLAGS: -DPNG_DEBUG=1
	// #cgo linux CFLAGS: -DLINUX=1
	// #cgo LDFLAGS: -lpng
	// #include <png.h>
	import "C"

Alternatively, CFLAGS and LDFLAGS may be obtained via the pkg-config
tool using a '#cgo pkg-config:' directive followed by the package names.
For example:

	// #cgo pkg-config: png cairo
	// #include <png.h>
	import "C"

Within the Go file, C identifiers or field names that are keywords in Go
can be accessed by prefixing them with an underscore: if x points at a C
struct with a field named "type", x._type accesses the field.

The standard C numeric types are available under the names
C.char, C.schar (signed char), C.uchar (unsigned char),
C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
C.long, C.ulong (unsigned long), C.longlong (long long),
C.ulonglong (unsigned long long), C.float, C.double.
The C type void* is represented by Go's unsafe.Pointer.

To access a struct, union, or enum type directly, prefix it with
struct_, union_, or enum_, as in C.struct_stat.

Any C function that returns a value may be called in a multiple
assignment context to retrieve both the return value and the
C errno variable as an error.  For example:

	n, err := C.atoi("abc")

In C, a function argument written as a fixed size array
actually requires a pointer to the first element of the array.
C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot.  In Go, you must pass
the pointer to the first element explicitly: C.f(&x[0]).

A few special functions convert between Go and C types
by making copies of the data.  In pseudo-Go definitions:

	// Go string to C string
	// The C string is allocated in the C heap using malloc.
	// It is the caller's responsibility to arrange for it to be
	// freed, such as by calling C.free.
	func C.CString(string) *C.char

	// C string to Go string
	func C.GoString(*C.char) string

	// C string, length to Go string
	func C.GoStringN(*C.char, C.int) string

	// C pointer, length to Go []byte
	func C.GoBytes(unsafe.Pointer, C.int) []byte

Go functions can be exported for use by C code in the following way:

	//export MyFunction
	func MyFunction(arg1, arg2 int, arg3 string) int64 {...}

	//export MyFunction2
	func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}

They will be available in the C code as:

	extern int64 MyFunction(int arg1, int arg2, GoString arg3);
	extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);

found in _cgo_export.h generated header. Functions with multiple
return values are mapped to functions returning a struct.
Not all Go types can be mapped to C types in a useful way.

Cgo transforms the input file into four output files: two Go source
files, a C file for 6c (or 8c or 5c), and a C file for gcc.

The standard package makefile rules in Make.pkg automate the
process of using cgo.  See $GOROOT/misc/cgo/stdio and
$GOROOT/misc/cgo/gmp for examples.

Cgo does not yet work with gccgo.

See "C? Go? Cgo!" for an introduction to using cgo:
http://blog.golang.org/2011/03/c-go-cgo.html
*/
package documentation
<|endoftext|>


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

/*
Fix finds Go programs that use old APIs and rewrites them to use
newer ones.  After you update to a new Go release, fix helps make
the necessary changes to your programs.

Usage:
	go tool fix [-r name,...] [path ...]

Without an explicit path, fix reads standard input and writes the
result to standard output.

If the named path is a file, fix rewrites the named files in place.
If the named path is a directory, fix rewrites all .go files in that
directory tree.  When fix rewrites a file, it prints a line to standard
error giving the name of the file and the rewrite applied.

If the -diff flag is set, no files are rewritten. Instead fix prints
the differences a rewrite would introduce.

The -r flag restricts the set of rewrites considered to those in the
named list.  By default fix considers all known rewrites.  Fix's
rewrites are idempotent, so that it is safe to apply fix to updated
or partially updated code even without using the -r flag.

Fix prints the full list of fixes it can apply in its help output;
to see them, run go tool fix -?.

Fix does not make backup copies of the files that it edits.
Instead, use a version control system's ``diff'' functionality to inspect
the changes that fix makes before committing them.
*/
package main
<commit_msg>cmd/fix: mention -help instead of the non-existent -? flag<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Fix finds Go programs that use old APIs and rewrites them to use
newer ones.  After you update to a new Go release, fix helps make
the necessary changes to your programs.

Usage:
	go tool fix [-r name,...] [path ...]

Without an explicit path, fix reads standard input and writes the
result to standard output.

If the named path is a file, fix rewrites the named files in place.
If the named path is a directory, fix rewrites all .go files in that
directory tree.  When fix rewrites a file, it prints a line to standard
error giving the name of the file and the rewrite applied.

If the -diff flag is set, no files are rewritten. Instead fix prints
the differences a rewrite would introduce.

The -r flag restricts the set of rewrites considered to those in the
named list.  By default fix considers all known rewrites.  Fix's
rewrites are idempotent, so that it is safe to apply fix to updated
or partially updated code even without using the -r flag.

Fix prints the full list of fixes it can apply in its help output;
to see them, run go tool fix -help.

Fix does not make backup copies of the files that it edits.
Instead, use a version control system's ``diff'' functionality to inspect
the changes that fix makes before committing them.
*/
package main
<|endoftext|>


<commit_before>package facebook

import (
	"http"
	"io/ioutil"
	"json"
	"os"
	"strconv"
	"fmt"
)

const (
	GRAPHURL = "http://graph.facebook.com/"
)

type Object struct {
	ID   string
	Name string
}

func parseObject(value map[string]interface{}) (obj Object) {
	obj.ID = value["id"].(string)
	obj.Name = value["name"].(string)
	return
}

func parseObjects(value []interface{}) (objs []Object) {
	objs = make([]Object, len(value))
	for i, v := range value {
		objs[i] = parseObject(v.(map[string]interface{}))
	}
	return
}

type Link struct {
	Name string
	URL  string
}

func parseLink(value map[string]interface{}) (link Link) {
	link.Name = value["name"].(string)
	link.URL = value["link"].(string)
	return
}

func parseLinks(value []interface{}) (links []Link) {
	links = make([]Link, len(value))
	for i, v := range value {
		links[i] = parseLink(v.(map[string]interface{}))
	}
	return
}

func getJsonMap(body []byte) (data map[string]interface{}, err os.Error) {
	var values interface{}

	if err = json.Unmarshal(body, &values); err != nil {
		return
	}
	data = values.(map[string]interface{})
	return
}

func fetchBody(method string) (body []byte, err os.Error) {
	body, err = fetchPage(GRAPHURL + method)
	return
}

func fetchPage(url string) (body []byte, err os.Error) {
	resp, _, err := http.Get(url) // Response, final URL, error
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err = ioutil.ReadAll(resp.Body)
	return
}

func debugInterface(value interface{}, key, funcName string) {
	var str string
	switch value.(type) {
	case float64:
		str = strconv.Ftoa64(value.(float64), 'e', -1)
	}
	fmt.Printf("%s: Unknown pair: %s : %s\n", funcName, key, str)
}
<commit_msg>Add parseTime to parse different fetched time formats.<commit_after>package facebook

import (
	"http"
	"io/ioutil"
	"json"
	"os"
	"strconv"
	"fmt"
	"time"
)

const (
	GRAPHURL = "http://graph.facebook.com/"
)

type Object struct {
	ID   string
	Name string
}

func parseObject(value map[string]interface{}) (obj Object) {
	obj.ID = value["id"].(string)
	obj.Name = value["name"].(string)
	return
}

func parseObjects(value []interface{}) (objs []Object) {
	objs = make([]Object, len(value))
	for i, v := range value {
		objs[i] = parseObject(v.(map[string]interface{}))
	}
	return
}

type Link struct {
	Name string
	URL  string
}

func parseLink(value map[string]interface{}) (link Link) {
	link.Name = value["name"].(string)
	link.URL = value["link"].(string)
	return
}

func parseLinks(value []interface{}) (links []Link) {
	links = make([]Link, len(value))
	for i, v := range value {
		links[i] = parseLink(v.(map[string]interface{}))
	}
	return
}

func getJsonMap(body []byte) (data map[string]interface{}, err os.Error) {
	var values interface{}

	if err = json.Unmarshal(body, &values); err != nil {
		return
	}
	data = values.(map[string]interface{})
	return
}

func fetchBody(method string) (body []byte, err os.Error) {
	body, err = fetchPage(GRAPHURL + method)
	return
}

func fetchPage(url string) (body []byte, err os.Error) {
	resp, _, err := http.Get(url) // Response, final URL, error
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err = ioutil.ReadAll(resp.Body)
	return
}

func parseTime(value string) (t *time.Time, err os.Error) {
	t, err = time.Parse("RFC3339", value)
	if err != nil {
		t, err = time.Parse("January 2, 2006", value)
		if err != nil {
			t, err = time.Parse("Jan 2006", value)
		}
	}
	return
}

func debugInterface(value interface{}, key, funcName string) {
	var str string
	switch value.(type) {
	case float64:
		str = strconv.Ftoa64(value.(float64), 'e', -1)
	}
	fmt.Printf("%s: Unknown pair: %s : %s\n", funcName, key, str)
}
<|endoftext|>


<commit_before>// Copyright 2017 The etcd-operator 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 v1beta2

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

const (
	CRDResourceKind   = "EtcdCluster"
	CRDResourcePlural = "etcdclusters"
	groupName         = "etcd.database.coreos.com"

	EtcdBackupResourceKind   = "EtcdBackup"
	EtcdBackupResourcePlural = "etcdbackups"
)

var (
	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
	AddToScheme   = SchemeBuilder.AddToScheme

	SchemeGroupVersion = schema.GroupVersion{Group: groupName, Version: "v1beta2"}
	CRDName            = CRDResourcePlural + "." + groupName
	EtcdBackupCRDName  = EtcdBackupResourceKind + "." + groupName
)

// Resource gets an EtcdCluster GroupResource for a specified resource
func Resource(resource string) schema.GroupResource {
	return SchemeGroupVersion.WithResource(resource).GroupResource()
}

// addKnownTypes adds the set of types defined in this package to the supplied scheme.
func addKnownTypes(s *runtime.Scheme) error {
	s.AddKnownTypes(SchemeGroupVersion,
		&EtcdCluster{},
		&EtcdClusterList{},
		&EtcdBackup{},
		&EtcdBackupList{},
	)
	metav1.AddToGroupVersion(s, SchemeGroupVersion)
	return nil
}
<commit_msg>apis: add etcd restore related constants in register.go<commit_after>// Copyright 2017 The etcd-operator 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 v1beta2

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

const (
	CRDResourceKind   = "EtcdCluster"
	CRDResourcePlural = "etcdclusters"
	groupName         = "etcd.database.coreos.com"

	EtcdBackupResourceKind   = "EtcdBackup"
	EtcdBackupResourcePlural = "etcdbackups"

	EtcdRestoreResourceKind   = "EtcdRestore"
	EtcdRestoreResourcePlural = "etcdrestores"
)

var (
	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
	AddToScheme   = SchemeBuilder.AddToScheme

	SchemeGroupVersion = schema.GroupVersion{Group: groupName, Version: "v1beta2"}
	CRDName            = CRDResourcePlural + "." + groupName
	EtcdBackupCRDName  = EtcdBackupResourceKind + "." + groupName
	EtcdRestoreCRDName = EtcdRestoreResourcePlural + "." + groupName
)

// Resource gets an EtcdCluster GroupResource for a specified resource
func Resource(resource string) schema.GroupResource {
	return SchemeGroupVersion.WithResource(resource).GroupResource()
}

// addKnownTypes adds the set of types defined in this package to the supplied scheme.
func addKnownTypes(s *runtime.Scheme) error {
	s.AddKnownTypes(SchemeGroupVersion,
		&EtcdCluster{},
		&EtcdClusterList{},
		&EtcdBackup{},
		&EtcdBackupList{},
		&EtcdRestore{},
		&EtcdRestoreList{},
	)
	metav1.AddToGroupVersion(s, SchemeGroupVersion)
	return nil
}
<|endoftext|>


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

package v1alpha1

import (
	"agones.dev/agones/pkg/apis/stable"
	"github.com/pkg/errors"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
)

const (
	// PortAllocation is for when a dynamically allocating GameServer
	// is being created, an open port needs to be allocated
	PortAllocation State = "PortAllocation"
	// Creating is before the Pod for the GameServer is being created
	Creating State = "Creating"
	// Starting is for when the Pods for the GameServer are being
	// created but have yet to register themselves as Ready
	Starting State = "Starting"
	// RequestReady is when the GameServer has declared that it is ready
	RequestReady State = "RequestReady"
	// Ready is when a GameServer is ready to take connections
	// from Game clients
	Ready State = "Ready"
	// Shutdown is when the GameServer has shutdown and everything needs to be
	// deleted from the cluster
	Shutdown State = "Shutdown"
	// Error is when something has gone with the Gameserver and
	// it cannot be resolved
	Error State = "Error"
	// Unhealthy is when the GameServer has failed its health checks
	Unhealthy State = "Unhealthy"

	// Static PortPolicy means that the user defines the hostPort to be used
	// in the configuration.
	Static PortPolicy = "static"
	// Dynamic PortPolicy means that the system will choose an open
	// port for the GameServer in question
	Dynamic PortPolicy = "dynamic"

	// RoleLabel is the label in which the Agones role is specified.
	// Pods from a GameServer will have the value "gameserver"
	RoleLabel = stable.GroupName + "/role"
	// GameServerLabelRole is the GameServer label value for RoleLabel
	GameServerLabelRole = "gameserver"
	// GameServerPodLabel is the label that the name of the GameServer
	// is set on the Pod the GameServer controls
	GameServerPodLabel = stable.GroupName + "/gameserver"
	// GameServerContainerAnnotation is the annotation that stores
	// which container is the container that runs the dedicated game server
	GameServerContainerAnnotation = stable.GroupName + "/container"
	// SidecarServiceAccountName is the default service account for managing access to get/update GameServers
	SidecarServiceAccountName = "agones-sdk"
)

var (
	// GameServerRolePodSelector is the selector to get all GameServer Pods
	GameServerRolePodSelector = labels.SelectorFromSet(labels.Set{RoleLabel: GameServerLabelRole})
)

// +genclient
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// GameServer is the data structure for a gameserver resource
type GameServer struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   GameServerSpec   `json:"spec"`
	Status GameServerStatus `json:"status"`
}

// GameServerSpec is the spec for a GameServer resource
type GameServerSpec struct {
	// Container specifies which Pod container is the game server. Only required if there is more than once
	// container defined
	Container string `json:"container,omitempty"`
	// PortPolicy defined the policy for how the HostPort is populated.
	// Dynamic port will allocate a HostPort within the selected MIN_PORT and MAX_PORT range passed to the controller
	// at installation time.
	// When `static` is the policy specified, `HostPort` is required, to specify the port that game clients will
	// connect to
	PortPolicy PortPolicy `json:"PortPolicy,omitempty"`
	// ContainerPort is the port that is being opened on the game server process
	ContainerPort int32 `json:"containerPort"`
	// HostPort the port exposed on the host for clients to connect to
	HostPort int32 `json:"hostPort,omitempty"`
	// Protocol is the network protocol being used. Defaults to UDP. TCP is the only other option
	Protocol corev1.Protocol `json:"protocol,omitempty"`
	// Health configures health checking
	Health Health `json:"health,omitempty"`
	// Template describes the Pod that will be created for the GameServer
	Template corev1.PodTemplateSpec `json:"template"`
}

// State is the state for the GameServer
type State string

// PortPolicy is the port policy for the GameServer
type PortPolicy string

// Health configures health checking on the GameServer
type Health struct {
	// Disabled is whether health checking is disabled or not
	Disabled bool `json:"disabled,omitempty"`
	// PeriodSeconds is the number of seconds each health ping has to occur in
	PeriodSeconds int32 `json:"periodSeconds,omitempty"`
	// FailureThreshold how many failures in a row constitutes unhealthy
	FailureThreshold int32 `json:"failureThreshold,omitempty"`
	// InitialDelaySeconds initial delay before checking health
	InitialDelaySeconds int32 `json:"initialDelaySeconds,omitempty"`
}

// GameServerStatus is the status for a GameServer resource
type GameServerStatus struct {
	// State is the current state of a GameServer, e.g. Creating, Starting, Ready, etc
	State    State  `json:"state"`
	Port     int32  `json:"port"`
	Address  string `json:"address"`
	NodeName string `json:"nodeName"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// GameServerList is a list of GameServer resources
type GameServerList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`

	Items []GameServer `json:"items"`
}

// ApplyDefaults applies default values to the GameServer if they are not already populated
func (gs *GameServer) ApplyDefaults() {
	gs.ObjectMeta.Finalizers = append(gs.ObjectMeta.Finalizers, stable.GroupName)

	if len(gs.Spec.Template.Spec.Containers) == 1 {
		gs.Spec.Container = gs.Spec.Template.Spec.Containers[0].Name
	}

	// basic spec
	if gs.Spec.PortPolicy == "" {
		gs.Spec.PortPolicy = Dynamic
	}

	if gs.Spec.Protocol == "" {
		gs.Spec.Protocol = "UDP"
	}

	if gs.Status.State == "" {
		if gs.Spec.PortPolicy == Dynamic {
			gs.Status.State = PortAllocation
		} else {
			gs.Status.State = Creating
		}
	}

	// health
	if !gs.Spec.Health.Disabled {
		if gs.Spec.Health.PeriodSeconds <= 0 {
			gs.Spec.Health.PeriodSeconds = 5
		}
		if gs.Spec.Health.FailureThreshold <= 0 {
			gs.Spec.Health.FailureThreshold = 3
		}
		if gs.Spec.Health.InitialDelaySeconds <= 0 {
			gs.Spec.Health.InitialDelaySeconds = 5
		}
	}
}

// Validate validates the GameServer configuration.
// If a GameServer is invalid there will be > 0 values in
// the returned array
func (gs *GameServer) Validate() (bool, []metav1.StatusCause) {
	var causes []metav1.StatusCause

	// make sure a name is specified when there is multiple containers in the pod.
	if len(gs.Spec.Container) == 0 && len(gs.Spec.Template.Spec.Containers) > 1 {
		causes = append(causes, metav1.StatusCause{
			Type:    metav1.CauseTypeFieldValueInvalid,
			Field:   "container",
			Message: "Container is required when using multiple containers in the pod templace",
		})
	}

	// no host port when using dynamic PortPolicy
	if gs.Spec.HostPort > 0 && gs.Spec.PortPolicy == Dynamic {
		causes = append(causes, metav1.StatusCause{
			Type:    metav1.CauseTypeFieldValueInvalid,
			Field:   "hostPort",
			Message: "HostPort cannot be specified with a Dynamic PortPolicy",
		})
	}

	// make sure the container value points to a valid container
	_, _, err := gs.FindGameServerContainer()
	if err != nil {
		causes = append(causes, metav1.StatusCause{
			Type:    metav1.CauseTypeFieldValueInvalid,
			Field:   "container",
			Message: err.Error(),
		})
	}

	return len(causes) == 0, causes
}

// FindGameServerContainer returns the container that is specified in
// spec.gameServer.container. Returns the index and the value.
// Returns an error if not found
func (gs *GameServer) FindGameServerContainer() (int, corev1.Container, error) {
	for i, c := range gs.Spec.Template.Spec.Containers {
		if c.Name == gs.Spec.Container {
			return i, c, nil
		}
	}

	return -1, corev1.Container{}, errors.Errorf("Could not find a container named %s", gs.Spec.Container)
}

// Pod creates a new Pod from the PodTemplateSpec
// attached for the
func (gs *GameServer) Pod(sidecars ...corev1.Container) (*corev1.Pod, error) {
	pod := &corev1.Pod{
		ObjectMeta: *gs.Spec.Template.ObjectMeta.DeepCopy(),
		Spec:       *gs.Spec.Template.Spec.DeepCopy(),
	}
	// Switch to GenerateName, so that we always get a Unique name for the Pod, and there
	// can be no collisions
	pod.ObjectMeta.GenerateName = gs.ObjectMeta.Name + "-"
	pod.ObjectMeta.Name = ""
	// Pods for GameServers need to stay in the same namespace
	pod.ObjectMeta.Namespace = gs.ObjectMeta.Namespace
	// Make sure these are blank, just in case
	pod.ResourceVersion = ""
	if pod.Spec.ServiceAccountName == "" {
		pod.Spec.ServiceAccountName = SidecarServiceAccountName
	}
	pod.UID = ""
	if pod.ObjectMeta.Labels == nil {
		pod.ObjectMeta.Labels = make(map[string]string, 2)
	}
	if pod.ObjectMeta.Annotations == nil {
		pod.ObjectMeta.Annotations = make(map[string]string, 1)
	}
	pod.ObjectMeta.Labels[RoleLabel] = GameServerLabelRole
	// store the GameServer name as a label, for easy lookup later on
	pod.ObjectMeta.Labels[GameServerPodLabel] = gs.ObjectMeta.Name
	// store the GameServer container as an annotation, to make lookup at a Pod level easier
	pod.ObjectMeta.Annotations[GameServerContainerAnnotation] = gs.Spec.Container

	ref := metav1.NewControllerRef(gs, SchemeGroupVersion.WithKind("GameServer"))
	pod.ObjectMeta.OwnerReferences = append(pod.ObjectMeta.OwnerReferences, *ref)

	i, gsContainer, err := gs.FindGameServerContainer()
	// this shouldn't happen, but if it does.
	if err != nil {
		return pod, err
	}

	cp := corev1.ContainerPort{
		ContainerPort: gs.Spec.ContainerPort,
		HostPort:      gs.Spec.HostPort,
		Protocol:      gs.Spec.Protocol,
	}
	gsContainer.Ports = append(gsContainer.Ports, cp)
	pod.Spec.Containers[i] = gsContainer

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

package v1alpha1

import (
	"agones.dev/agones/pkg/apis/stable"
	"github.com/pkg/errors"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
)

const (
	// PortAllocation is for when a dynamically allocating GameServer
	// is being created, an open port needs to be allocated
	PortAllocation State = "PortAllocation"
	// Creating is before the Pod for the GameServer is being created
	Creating State = "Creating"
	// Starting is for when the Pods for the GameServer are being
	// created but have yet to register themselves as Ready
	Starting State = "Starting"
	// RequestReady is when the GameServer has declared that it is ready
	RequestReady State = "RequestReady"
	// Ready is when a GameServer is ready to take connections
	// from Game clients
	Ready State = "Ready"
	// Shutdown is when the GameServer has shutdown and everything needs to be
	// deleted from the cluster
	Shutdown State = "Shutdown"
	// Error is when something has gone with the Gameserver and
	// it cannot be resolved
	Error State = "Error"
	// Unhealthy is when the GameServer has failed its health checks
	Unhealthy State = "Unhealthy"

	// Static PortPolicy means that the user defines the hostPort to be used
	// in the configuration.
	Static PortPolicy = "static"
	// Dynamic PortPolicy means that the system will choose an open
	// port for the GameServer in question
	Dynamic PortPolicy = "dynamic"

	// RoleLabel is the label in which the Agones role is specified.
	// Pods from a GameServer will have the value "gameserver"
	RoleLabel = stable.GroupName + "/role"
	// GameServerLabelRole is the GameServer label value for RoleLabel
	GameServerLabelRole = "gameserver"
	// GameServerPodLabel is the label that the name of the GameServer
	// is set on the Pod the GameServer controls
	GameServerPodLabel = stable.GroupName + "/gameserver"
	// GameServerContainerAnnotation is the annotation that stores
	// which container is the container that runs the dedicated game server
	GameServerContainerAnnotation = stable.GroupName + "/container"
	// SidecarServiceAccountName is the default service account for managing access to get/update GameServers
	SidecarServiceAccountName = "agones-sdk"
)

var (
	// GameServerRolePodSelector is the selector to get all GameServer Pods
	GameServerRolePodSelector = labels.SelectorFromSet(labels.Set{RoleLabel: GameServerLabelRole})
)

// +genclient
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// GameServer is the data structure for a gameserver resource
type GameServer struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   GameServerSpec   `json:"spec"`
	Status GameServerStatus `json:"status"`
}

// GameServerSpec is the spec for a GameServer resource
type GameServerSpec struct {
	// Container specifies which Pod container is the game server. Only required if there is more than one
	// container defined
	Container string `json:"container,omitempty"`
	// PortPolicy defines the policy for how the HostPort is populated.
	// Dynamic port will allocate a HostPort within the selected MIN_PORT and MAX_PORT range passed to the controller
	// at installation time.
	// When `static` is the policy specified, `HostPort` is required, to specify the port that game clients will
	// connect to
	PortPolicy PortPolicy `json:"PortPolicy,omitempty"`
	// ContainerPort is the port that is being opened on the game server process
	ContainerPort int32 `json:"containerPort"`
	// HostPort the port exposed on the host for clients to connect to
	HostPort int32 `json:"hostPort,omitempty"`
	// Protocol is the network protocol being used. Defaults to UDP. TCP is the only other option
	Protocol corev1.Protocol `json:"protocol,omitempty"`
	// Health configures health checking
	Health Health `json:"health,omitempty"`
	// Template describes the Pod that will be created for the GameServer
	Template corev1.PodTemplateSpec `json:"template"`
}

// State is the state for the GameServer
type State string

// PortPolicy is the port policy for the GameServer
type PortPolicy string

// Health configures health checking on the GameServer
type Health struct {
	// Disabled is whether health checking is disabled or not
	Disabled bool `json:"disabled,omitempty"`
	// PeriodSeconds is the number of seconds each health ping has to occur in
	PeriodSeconds int32 `json:"periodSeconds,omitempty"`
	// FailureThreshold how many failures in a row constitutes unhealthy
	FailureThreshold int32 `json:"failureThreshold,omitempty"`
	// InitialDelaySeconds initial delay before checking health
	InitialDelaySeconds int32 `json:"initialDelaySeconds,omitempty"`
}

// GameServerStatus is the status for a GameServer resource
type GameServerStatus struct {
	// State is the current state of a GameServer, e.g. Creating, Starting, Ready, etc
	State    State  `json:"state"`
	Port     int32  `json:"port"`
	Address  string `json:"address"`
	NodeName string `json:"nodeName"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// GameServerList is a list of GameServer resources
type GameServerList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`

	Items []GameServer `json:"items"`
}

// ApplyDefaults applies default values to the GameServer if they are not already populated
func (gs *GameServer) ApplyDefaults() {
	gs.ObjectMeta.Finalizers = append(gs.ObjectMeta.Finalizers, stable.GroupName)

	if len(gs.Spec.Template.Spec.Containers) == 1 {
		gs.Spec.Container = gs.Spec.Template.Spec.Containers[0].Name
	}

	// basic spec
	if gs.Spec.PortPolicy == "" {
		gs.Spec.PortPolicy = Dynamic
	}

	if gs.Spec.Protocol == "" {
		gs.Spec.Protocol = "UDP"
	}

	if gs.Status.State == "" {
		if gs.Spec.PortPolicy == Dynamic {
			gs.Status.State = PortAllocation
		} else {
			gs.Status.State = Creating
		}
	}

	// health
	if !gs.Spec.Health.Disabled {
		if gs.Spec.Health.PeriodSeconds <= 0 {
			gs.Spec.Health.PeriodSeconds = 5
		}
		if gs.Spec.Health.FailureThreshold <= 0 {
			gs.Spec.Health.FailureThreshold = 3
		}
		if gs.Spec.Health.InitialDelaySeconds <= 0 {
			gs.Spec.Health.InitialDelaySeconds = 5
		}
	}
}

// Validate validates the GameServer configuration.
// If a GameServer is invalid there will be > 0 values in
// the returned array
func (gs *GameServer) Validate() (bool, []metav1.StatusCause) {
	var causes []metav1.StatusCause

	// make sure a name is specified when there is multiple containers in the pod.
	if len(gs.Spec.Container) == 0 && len(gs.Spec.Template.Spec.Containers) > 1 {
		causes = append(causes, metav1.StatusCause{
			Type:    metav1.CauseTypeFieldValueInvalid,
			Field:   "container",
			Message: "Container is required when using multiple containers in the pod template",
		})
	}

	// no host port when using dynamic PortPolicy
	if gs.Spec.HostPort > 0 && gs.Spec.PortPolicy == Dynamic {
		causes = append(causes, metav1.StatusCause{
			Type:    metav1.CauseTypeFieldValueInvalid,
			Field:   "hostPort",
			Message: "HostPort cannot be specified with a Dynamic PortPolicy",
		})
	}

	// make sure the container value points to a valid container
	_, _, err := gs.FindGameServerContainer()
	if err != nil {
		causes = append(causes, metav1.StatusCause{
			Type:    metav1.CauseTypeFieldValueInvalid,
			Field:   "container",
			Message: err.Error(),
		})
	}

	return len(causes) == 0, causes
}

// FindGameServerContainer returns the container that is specified in
// spec.gameServer.container. Returns the index and the value.
// Returns an error if not found
func (gs *GameServer) FindGameServerContainer() (int, corev1.Container, error) {
	for i, c := range gs.Spec.Template.Spec.Containers {
		if c.Name == gs.Spec.Container {
			return i, c, nil
		}
	}

	return -1, corev1.Container{}, errors.Errorf("Could not find a container named %s", gs.Spec.Container)
}

// Pod creates a new Pod from the PodTemplateSpec
// attached to the GameServer resource
func (gs *GameServer) Pod(sidecars ...corev1.Container) (*corev1.Pod, error) {
	pod := &corev1.Pod{
		ObjectMeta: *gs.Spec.Template.ObjectMeta.DeepCopy(),
		Spec:       *gs.Spec.Template.Spec.DeepCopy(),
	}
	// Switch to GenerateName, so that we always get a Unique name for the Pod, and there
	// can be no collisions
	pod.ObjectMeta.GenerateName = gs.ObjectMeta.Name + "-"
	pod.ObjectMeta.Name = ""
	// Pods for GameServers need to stay in the same namespace
	pod.ObjectMeta.Namespace = gs.ObjectMeta.Namespace
	// Make sure these are blank, just in case
	pod.ResourceVersion = ""
	if pod.Spec.ServiceAccountName == "" {
		pod.Spec.ServiceAccountName = SidecarServiceAccountName
	}
	pod.UID = ""
	if pod.ObjectMeta.Labels == nil {
		pod.ObjectMeta.Labels = make(map[string]string, 2)
	}
	if pod.ObjectMeta.Annotations == nil {
		pod.ObjectMeta.Annotations = make(map[string]string, 1)
	}
	pod.ObjectMeta.Labels[RoleLabel] = GameServerLabelRole
	// store the GameServer name as a label, for easy lookup later on
	pod.ObjectMeta.Labels[GameServerPodLabel] = gs.ObjectMeta.Name
	// store the GameServer container as an annotation, to make lookup at a Pod level easier
	pod.ObjectMeta.Annotations[GameServerContainerAnnotation] = gs.Spec.Container

	ref := metav1.NewControllerRef(gs, SchemeGroupVersion.WithKind("GameServer"))
	pod.ObjectMeta.OwnerReferences = append(pod.ObjectMeta.OwnerReferences, *ref)

	i, gsContainer, err := gs.FindGameServerContainer()
	// this shouldn't happen, but if it does.
	if err != nil {
		return pod, err
	}

	cp := corev1.ContainerPort{
		ContainerPort: gs.Spec.ContainerPort,
		HostPort:      gs.Spec.HostPort,
		Protocol:      gs.Spec.Protocol,
	}
	gsContainer.Ports = append(gsContainer.Ports, cp)
	pod.Spec.Containers[i] = gsContainer

	pod.Spec.Containers = append(pod.Spec.Containers, sidecars...)
	return pod, nil
}
<|endoftext|>