Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AppDefaults #17

Merged
merged 1 commit into from Apr 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Expand Up @@ -9,6 +9,23 @@ The primary usecase for this project is currently Rancher's [system-upgrade-cont

This service is in proudction for k3s here: https://update.k3s.io/v1-release/channels, which is driven by this config: https://github.com/rancher/k3s/blob/master/channel.yaml. Each channel's `self` link is the URL that will resolve to the latest GitHub release page for that channel.

## Compile and Run
1. build the binary
```
go build .
```
2. run the server
```
./channelserver --config-key k3s --path-prefix v1-release --channel-server-version v2.3.1
```

3. run the following curl command or open the url in the browser
```
curl 0.0.0.0:8080/v1-release/release
curl 0.0.0.0:8080/v1-release/channel
curl 0.0.0.0:8080/v1-release/appdefault
```

## License
Copyright (c) 2020 [Rancher Labs, Inc.](http://rancher.com)

Expand Down
82 changes: 48 additions & 34 deletions channels.yaml
@@ -1,35 +1,49 @@
# Example channels config
channels:
- name: stable
latest: v1.17.2+k3s1
- name: latest
latestRegexp: .*
excludeRegexp: rc
- name: testing
latestRegexp: .*
- name: v1.16
latestRegexp: v1\.16\..*
excludeRegexp: rc
- name: v1.16-testing
latestRegexp: v1\.16\.*
- name: v1.17
latestRegexp: v1\.17\..*
excludeRegexp: rc
- name: v1.17-testing
latestRegexp: v1\.17\..*
- name: v1.0
latestRegexp: v1\.0\..*
excludeRegexp: rc
- name: v1.0-testing
latestRegexp: v1\.0\..*
releases:
- version: v1.15.3+k3s2
minChannelServerVersion: v2.3.0
maxChannelServerVersion: v2.3.5
- version: v1.17.4+k3s1
minChannelServerVersion: v2.4.0
maxChannelServerVersion: v2.4.5
github:
owner: rancher
repo: k3s
redirectBase: https://github.com/rancher/k3s/releases/tag/
k3s:
channels:
- name: stable
latest: v1.17.2+k3s1
- name: latest
latestRegexp: .*
excludeRegexp: rc
- name: testing
latestRegexp: .*
- name: v1.16
latestRegexp: v1\.16\..*
excludeRegexp: rc
- name: v1.16-testing
latestRegexp: v1\.16\.*
- name: v1.17
latestRegexp: v1\.17\..*
excludeRegexp: rc
- name: v1.17-testing
latestRegexp: v1\.17\..*
- name: v1.0
latestRegexp: v1\.0\..*
excludeRegexp: rc
- name: v1.0-testing
latestRegexp: v1\.0\..*
releases:
- version: v1.15.3+k3s2
minChannelServerVersion: v2.3.0
maxChannelServerVersion: v2.3.5
- version: v1.17.4+k3s1
minChannelServerVersion: v2.4.0
maxChannelServerVersion: v2.4.5
appDefaults:
- appName: rancher
defaults:
- appVersion: '> 2.6.2-0 < 2.6.3-0'
defaultVersion: '1.20.x'
- appVersion: '> 2.6.2-0 < 2.6.4-0'
defaultVersion: '1.21.x'
- appVersion: '> 2.6.4-0'
defaultVersion: '1.22.x'
- appName: anotherApp
defaults:
- appVersion: '1.2.x'
defaultVersion: '1.19.5'
github:
owner: rancher
repo: k3s
redirectBase: https://github.com/rancher/k3s/releases/tag/
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -13,6 +13,6 @@ require (
github.com/rancher/apiserver v0.0.0-20201023000256-1a0a904f9197
github.com/rancher/wrangler v0.8.11-0.20220120160420-18c996a8e956
github.com/sirupsen/logrus v1.6.0
github.com/urfave/cli/v2 v2.2.0
github.com/urfave/cli/v2 v2.4.0
sigs.k8s.io/yaml v1.2.0
)
12 changes: 6 additions & 6 deletions go.sum
Expand Up @@ -80,9 +80,9 @@ github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down Expand Up @@ -382,11 +382,11 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
Expand Down Expand Up @@ -427,8 +427,8 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I=
github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
Expand Down
9 changes: 8 additions & 1 deletion main.go
Expand Up @@ -22,6 +22,7 @@ var (
SubKeys cli.StringSlice
ChannelServerVersion string
PathPrefix cli.StringSlice
AppName string
)

func main() {
Expand Down Expand Up @@ -56,6 +57,12 @@ func main() {
EnvVars: []string{"CHANNEL_SERVER_VERSION"},
Destination: &ChannelServerVersion,
},
&cli.StringFlag{
Name: "app-name",
Usage: "the app for which to retrieve the app default versions",
EnvVars: []string{"APP_NAME"},
Destination: &AppName,
},
&cli.StringSliceFlag{
Name: "path-prefix",
EnvVars: []string{"PATH_PREFIX"},
Expand Down Expand Up @@ -91,7 +98,7 @@ func run(c *cli.Context) error {
sources = append(sources, config.StringSource(url))
}
for index, subkey := range SubKeys.Value() {
config := config.NewConfig(ctx, subkey, &config.DurationWait{Duration: intval}, ChannelServerVersion, sources)
config := config.NewConfig(ctx, subkey, &config.DurationWait{Duration: intval}, ChannelServerVersion, AppName, sources)
configs[PathPrefix.Value()[index]] = config
}
return server.ListenAndServe(ctx, ListenAddress, configs)
Expand Down
51 changes: 33 additions & 18 deletions pkg/config/config.go
Expand Up @@ -2,6 +2,7 @@ package config

import (
"context"
"fmt"
"net/url"
"sync"
"time"
Expand All @@ -14,11 +15,12 @@ import (
type Config struct {
sync.Mutex

url string
redirect *url.URL
gh *github.Client
channelsConfig *model.ChannelsConfig
releasesConfig *model.ReleasesConfig
url string
redirect *url.URL
gh *github.Client
channelsConfig *model.ChannelsConfig
releasesConfig *model.ReleasesConfig
appDefaultsConfig *model.AppDefaultsConfig
}

type Wait interface {
Expand Down Expand Up @@ -48,45 +50,51 @@ func (s StringSource) URL() string {
return string(s)
}

func NewConfig(ctx context.Context, subKey string, wait Wait, channelServerVersion string, urls []Source) *Config {
func NewConfig(ctx context.Context, subKey string, wait Wait, channelServerVersion string, appName string, urls []Source) *Config {
c := &Config{
channelsConfig: &model.ChannelsConfig{},
releasesConfig: &model.ReleasesConfig{},
channelsConfig: &model.ChannelsConfig{},
releasesConfig: &model.ReleasesConfig{},
appDefaultsConfig: &model.AppDefaultsConfig{},
}

_, _ = c.loadConfig(ctx, subKey, channelServerVersion, urls...)
_, _ = c.loadConfig(ctx, subKey, channelServerVersion, appName, urls...)

go func() {
for wait.Wait(ctx) {
if index, err := c.loadConfig(ctx, subKey, channelServerVersion, urls...); err != nil {
logrus.Errorf("failed to reload configuration from %s: %v", urls, err)
if index, err := c.loadConfig(ctx, subKey, channelServerVersion, appName, urls...); err != nil {
logrus.Errorf("failed to reload configuration from %s: %v", urls[index].URL(), err)
} else {
urls = urls[:index+1]
logrus.Infof("Loaded configuration from %s in %v", urls[index], urls)
logrus.Infof("Loaded configuration from %s in %v", urls[index].URL(), urls)
}
}
}()

return c
}

func (c *Config) loadConfig(ctx context.Context, subKey string, channelServerVersion string, urls ...Source) (int, error) {
func (c *Config) loadConfig(ctx context.Context, subKey string, channelServerVersion string, appName string, urls ...Source) (int, error) {
content, index, err := getURLs(ctx, urls...)
if err != nil {
return index, err
return index, fmt.Errorf("failed to get content from url %s: %v", urls[index].URL(), err)
}

config, err := GetChannelsConfig(ctx, content, subKey)
if err != nil {
return index, err
return index, fmt.Errorf("failed to get channel config: %v", err)
}

releases, err := GetReleasesConfig(content, channelServerVersion, subKey)
if err != nil {
return index, err
return index, fmt.Errorf("failed to get release config: %v", err)
}

return index, c.setConfig(ctx, channelServerVersion, config, releases)
appDefaultsConfig, err := GetAppDefaultsConfig(content, subKey, appName)
if err != nil {
return index, fmt.Errorf("failed to get app default config: %v", err)
}

return index, c.setConfig(ctx, channelServerVersion, config, releases, appDefaultsConfig)
}

func (c *Config) ghClient(config *model.ChannelsConfig) (*github.Client, error) {
Expand All @@ -103,7 +111,7 @@ func (c *Config) ghClient(config *model.ChannelsConfig) (*github.Client, error)
return c.gh, nil
}

func (c *Config) setConfig(ctx context.Context, channelServerVersion string, config *model.ChannelsConfig, releases *model.ReleasesConfig) error {
func (c *Config) setConfig(ctx context.Context, channelServerVersion string, config *model.ChannelsConfig, releases *model.ReleasesConfig, appDefaultsConfig *model.AppDefaultsConfig) error {
gh, err := c.ghClient(config)
if err != nil {
return err
Expand Down Expand Up @@ -132,6 +140,7 @@ func (c *Config) setConfig(ctx context.Context, channelServerVersion string, con
c.channelsConfig = config
c.redirect = redirect
c.releasesConfig = releases
c.appDefaultsConfig = appDefaultsConfig
if config.GitHub != nil {
c.url = config.GitHub.APIURL
}
Expand Down Expand Up @@ -170,6 +179,12 @@ func (c *Config) ReleasesConfig() *model.ReleasesConfig {
return c.releasesConfig
}

func (c *Config) AppDefaultsConfig() *model.AppDefaultsConfig {
c.Lock()
defer c.Unlock()
return c.appDefaultsConfig
}

func (c *Config) Redirect(id string) (string, error) {
for _, channel := range c.channelsConfig.Channels {
if channel.Name == id && channel.Latest != "" {
Expand Down
41 changes: 41 additions & 0 deletions pkg/config/get.go
Expand Up @@ -47,6 +47,10 @@ func get(ctx context.Context, url Source) ([]byte, error) {
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status %v", resp.Status)
}
jiaqiluo marked this conversation as resolved.
Show resolved Hide resolved

return ioutil.ReadAll(resp.Body)
}

Expand Down Expand Up @@ -146,3 +150,40 @@ func GetGHReleases(ctx context.Context, client *github.Client, owner, repo strin

return allReleases, nil
}

func GetAppDefaultsConfig(content []byte, subKey, appName string) (*model.AppDefaultsConfig, error) {
var (
data map[string]interface{}
allConfigs model.AppDefaultsConfig
availableConfigs model.AppDefaultsConfig
)

if subKey == "" {
if err := yaml.Unmarshal(content, &allConfigs); err != nil {
return nil, err
}
} else {
if err := yaml.Unmarshal(content, &data); err != nil {
return nil, err
}
subData, ok := data[subKey].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("content at key %s expected to be map[string]interface{}, found %T instead", subKey, data[subKey])
}
if err := convert.ToObj(subData, &allConfigs); err != nil {
return nil, err
}
}

// no app name is specified, return all AppDefaultsConfigs
if appName == "" {
return &allConfigs, nil
}
for _, appDefault := range allConfigs.AppDefaults {
if appDefault.AppName == appName {
availableConfigs.AppDefaults = append(availableConfigs.AppDefaults, appDefault)
break
}
}
return &availableConfigs, nil
}
14 changes: 14 additions & 0 deletions pkg/model/config.go
Expand Up @@ -39,3 +39,17 @@ type GitHub struct {
Owner string `json:"owner,omitempty"`
Repo string `json:"repo,omitempty"`
}

type AppDefaultsConfig struct {
AppDefaults []AppDefault `json:"appDefaults,omitempty"`
}

type AppDefault struct {
AppName string `json:"appName,omitempty"`
Defaults []Default `json:"defaults,omitempty"`
}

type Default struct {
AppVersion string `json:"appVersion,omitempty"`
DefaultVersion string `json:"defaultVersion,omitempty"`
}
5 changes: 5 additions & 0 deletions pkg/server/server.go
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/rancher/channelserver/pkg/config"
"github.com/rancher/channelserver/pkg/model"
"github.com/rancher/channelserver/pkg/server/store"
"github.com/rancher/channelserver/pkg/server/store/appdefault"
"github.com/rancher/channelserver/pkg/server/store/release"
)

Expand Down Expand Up @@ -46,6 +47,10 @@ func NewHandler(configs map[string]*config.Config) http.Handler {
schema.Store = release.New(config)
schema.CollectionMethods = []string{http.MethodGet}
})
server.Schemas.MustImportAndCustomize(model.AppDefault{}, func(schema *types.APISchema) {
schema.Store = appdefault.New(config)
schema.CollectionMethods = []string{http.MethodGet}
})
prefix = strings.Trim(prefix, "/")
apiroot.Register(server.Schemas, []string{prefix})
router.MatcherFunc(setType("apiRoot", prefix)).Path("/").Handler(server)
Expand Down