Skip to content

Commit

Permalink
Build versioning
Browse files Browse the repository at this point in the history
RE: Nordstrom#45
- Added version to cli and server packages
- Version is injected by make based either on a Env VAR or
autoincremented patch level
- If version is not injected during build we panic
- For testing a simple string is added
- Added unit tests
- Very minor clean up and style improvment
  • Loading branch information
paha committed Jan 24, 2018
1 parent 635d088 commit 5737455
Show file tree
Hide file tree
Showing 7 changed files with 298 additions and 205 deletions.
12 changes: 11 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ GITHUB_REPO_HOST_AND_PATH := github.com/$(GITHUB_REPO_OWNER)/$(GITHUB_REPO_NAME)
IMAGE_NAME := quay.io/nordstrom/kubelogin
BUILD := build
CURRENT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
CURRENT_TAG := v0.0.52
# NOTE: only patch level version is auto incremented to set a new version
# to specify a new version: $ make version CURRENT_TAG="v0.2.0"
LAST_TAG := $(shell git tag --list | tail -1)
CURRENT_TAG ?= $(shell echo $(LAST_TAG) | awk -F. '{print $$1"."$$2"."$$NF+1}')
GOLANG_TOOLCHAIN_VERSION := 1.9.1

.PHONY: image/build image/push
Expand Down Expand Up @@ -139,6 +142,7 @@ $(BUILD)/server/kubelogin-server-$(CURRENT_TAG)-%: cmd/server/*.go | $(BUILD)/se
-e GOOS=$* \
golang:$(GOLANG_TOOLCHAIN_VERSION) \
go build -v -o /go/bin/$(@F) \
-ldflags "-X main.version=$(CURRENT_TAG)" \
$(GITHUB_REPO_HOST_AND_PATH)/cmd/server/

$(BUILD)/cli/kubelogin-cli-$(CURRENT_TAG)-%: cmd/cli/*.go | $(BUILD)/cli
Expand All @@ -149,6 +153,7 @@ $(BUILD)/cli/kubelogin-cli-$(CURRENT_TAG)-%: cmd/cli/*.go | $(BUILD)/cli
-e GOOS=$* \
golang:$(GOLANG_TOOLCHAIN_VERSION) \
go build -v -o /go/bin/$(@F) \
-ldflags "-X main.version=$(CURRENT_TAG)" \
$(GITHUB_REPO_HOST_AND_PATH)/cmd/cli/ \

.PHONY: test_app
Expand All @@ -160,3 +165,8 @@ build $(BUILD)/server $(BUILD)/server/linux $(BUILD)/cli $(BUILD)/cli/mac $(BUIL

clean:
rm -rf build

.PHONY: version
version: ${ARGS}
@echo "Last tag: $(LAST_TAG)"
@echo "Next tag: $(CURRENT_TAG)"
118 changes: 118 additions & 0 deletions cmd/cli/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package main

import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os/exec"

"github.com/pkg/errors"
yaml "gopkg.in/yaml.v2"
)

type app struct {
filenameWithPath string
kubectlUser string
kubeloginAlias string
kubeloginServer string
}

func (app *app) makeExchange(token string) error {
url := fmt.Sprintf("%s/exchange?token=%s", app.kubeloginServer, token)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Printf("Unable to create request. %s", err)
return err
}
client := http.DefaultClient
res, err := client.Do(req)
if err != nil {
log.Printf("Unable to make request. %s", err)
return err
}
if res.StatusCode != http.StatusOK {
log.Fatalf("Failed to retrieve token from kubelogin server. Please try again or contact your administrator")
}
defer res.Body.Close() // nolint: errcheck
jwt, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Printf("Unable to read response body. %s", err)
return err
}
if err := app.configureKubectl(string(jwt)); err != nil {
log.Printf("Error when setting credentials: %v", err)
return err
}
return nil
}

func (app *app) tokenHandler(w http.ResponseWriter, r *http.Request) {
token := r.FormValue("token")
if err := app.makeExchange(token); err != nil {
log.Fatalf("Could not exchange token for jwt %v", err)
}
fmt.Fprint(w, "You are now logged in! You can close this window")
doneChannel <- true
}

func (app *app) configureKubectl(jwt string) error {
configCmd := exec.Command("kubectl", "config", "set-credentials", app.kubectlUser, "--token="+jwt)
return configCmd.Run()
}

func (app *app) generateAuthURL() (string, string, error) {
portNum, err := findFreePort()
if err != nil {
log.Print("err, could not find an open port")
return "", "", err
}

loginURL := fmt.Sprintf("%s/login?port=%s", app.kubeloginServer, portNum)

return loginURL, portNum, nil
}

func (app *app) getConfigSettings(alias string) error {
yamlFile, err := ioutil.ReadFile(app.filenameWithPath)
if err != nil {
return errors.Wrap(err, "failed to read config file for login use")
}
var config Config
if err := yaml.Unmarshal(yamlFile, &config); err != nil {
return errors.Wrap(err, "failed to unmarshal yaml file for login use")
}

aliasConfig, ok := config.aliasSearch(alias)
if !ok {
return errors.New("Could not find specified alias, check spelling or use the config verb to create an alias")
}
app.kubectlUser = aliasConfig.KubectlUser
app.kubeloginServer = aliasConfig.BaseURL
return nil
}

func (app *app) configureFile(kubeloginrcAlias string, loginServerURL *url.URL, kubectlUser string) error {
var config Config
aliasConfig := config.newAliasConfig(kubeloginrcAlias, loginServerURL.String(), kubectlUser)
yamlFile, err := ioutil.ReadFile(app.filenameWithPath)
if err != nil {
return config.createConfig(app.filenameWithPath, aliasConfig) // Either error or nil value
}
if err := yaml.Unmarshal(yamlFile, &config); err != nil {
return errors.Wrap(err, "failed to unmarshal yaml file")
}
foundAliasConfig, ok := config.aliasSearch(aliasFlag)
if !ok {
newConfig := config.newAliasConfig(kubeloginrcAlias, loginServerURL.String(), kubectlUser)
config.appendAlias(newConfig)
if err := config.writeToFile(app.filenameWithPath); err != nil {
log.Fatal(err)
}
log.Print("New Alias configured")
return nil
}

return config.updateAlias(foundAliasConfig, loginServerURL, app.filenameWithPath) // Either error or nil value
}
81 changes: 81 additions & 0 deletions cmd/cli/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package main

import (
"io/ioutil"
"log"
"net/url"
"os"

"github.com/pkg/errors"
yaml "gopkg.in/yaml.v2"
)

// Config contains the array of aliases (AliasConfig)
type Config struct {
Aliases []*AliasConfig `yaml:"aliases"`
}

func (config *Config) aliasSearch(alias string) (*AliasConfig, bool) {
for index, aliases := range config.Aliases {
if alias == aliases.Alias {
return config.Aliases[index], true
}
}
return nil, false
}

func (config *Config) createConfig(onDiskFile string, aliasConfig AliasConfig) error {
log.Print("Couldn't find config file in root directory. Creating config file...")
_, e := os.Stat(onDiskFile) // Does config file exist?
if os.IsNotExist(e) { // Create file
fh, err := os.Create(onDiskFile)
if err != nil {
return errors.Wrap(err, "failed to create file in root directory")
}
_ = fh.Close()
}

log.Print("Config file created, setting config values...")
config.Aliases = make([]*AliasConfig, 0)
config.appendAlias(aliasConfig)
if err := config.writeToFile(onDiskFile); err != nil {
log.Fatal(err)
}
log.Print("File configured")
return nil
}

func (config *Config) newAliasConfig(kubeloginrcAlias, loginServerURL, kubectlUser string) AliasConfig {
newConfig := AliasConfig{
BaseURL: loginServerURL,
Alias: kubeloginrcAlias,
KubectlUser: kubectlUser,
}
return newConfig
}

func (config *Config) appendAlias(aliasConfig AliasConfig) {
config.Aliases = append(config.Aliases, &aliasConfig)
}

func (config *Config) writeToFile(onDiskFile string) error {
marshaledYaml, err := yaml.Marshal(config)
if err != nil {
return errors.Wrap(err, "failed to marshal alias yaml")
}
if err := ioutil.WriteFile(onDiskFile, marshaledYaml, 0600); err != nil {
return errors.Wrap(err, "failed to write to kubeloginrc file with the alias")
}
log.Printf(string(marshaledYaml))
return nil
}

func (config *Config) updateAlias(aliasConfig *AliasConfig, loginServerURL *url.URL, onDiskFile string) error {
aliasConfig.KubectlUser = userFlag
aliasConfig.BaseURL = loginServerURL.String()
if err := config.writeToFile(onDiskFile); err != nil {
log.Fatal(err)
}
log.Print("Alias updated")
return nil
}
Loading

0 comments on commit 5737455

Please sign in to comment.