diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6651f6c7..4ed202c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,10 +18,10 @@ jobs: name: Build runs-on: ubuntu-20.04 steps: - - name: Set up Go 1.21 + - name: Set up Go 1.22 uses: actions/setup-go@v1 with: - go-version: '1.21' + go-version: '1.22' id: go - name: Check out code into the Go module directory diff --git a/Makefile b/Makefile index cefaaede..efa79978 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ BIN_PLATFORMS := $(DOCKER_PLATFORMS) darwin/amd64 darwin/arm64 OS := $(if $(GOOS),$(GOOS),$(shell go env GOOS)) ARCH := $(if $(GOARCH),$(GOARCH),$(shell go env GOARCH)) -GO_VERSION ?= 1.21 +GO_VERSION ?= 1.22 BUILD_IMAGE ?= ghcr.io/appscode/golang-dev:$(GO_VERSION) OUTBIN = bin/$(BIN)-$(OS)-$(ARCH) diff --git a/README.md b/README.md index d569db6f..2f50173f 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ These instructions are useful if you are trying to deploy your own license serve - Download pre-built binary into a server ```bash -curl -fsSL -O https://github.com/bytebuilders/offline-license-server/releases/download/v0.0.59/offline-license-server-linux-amd64 +curl -fsSL -O https://github.com/bytebuilders/offline-license-server/releases/download/v0.0.61/offline-license-server-linux-amd64 chmod +x offline-license-server-linux-amd64 mv offline-license-server-linux-amd64 /usr/local/bin/offline-license-server sudo systemctl restart offline-license-server @@ -86,7 +86,7 @@ sudo systemctl restart offline-license-server - Install systemd service ```bash -curl -fsSL -O https://github.com/bytebuilders/offline-license-server/raw/v0.0.59/hack/systemd/offline-license-server.service +curl -fsSL -O https://github.com/bytebuilders/offline-license-server/raw/v0.0.61/hack/systemd/offline-license-server.service chmod +x offline-license-server.service # 1. Copy Google cloud service account json key to /root/app/gcloud.json diff --git a/go.mod b/go.mod index ec37b37a..df05aa1b 100644 --- a/go.mod +++ b/go.mod @@ -69,7 +69,7 @@ require ( github.com/go-resty/resty/v2 v2.7.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -114,7 +114,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect google.golang.org/grpc v1.61.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 19d79d88..7a394e4e 100644 --- a/go.sum +++ b/go.sum @@ -182,8 +182,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -713,8 +713,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= diff --git a/main_extras.go b/main_extras.go index 0f119b11..5fd7c9f2 100644 --- a/main_extras.go +++ b/main_extras.go @@ -88,7 +88,7 @@ func main_sheets() { Timestamp: time.Now().UTC().Format(time.RFC3339), } - err = server.LogLicense(si, &info) + err = server.LogLicense(si, &info, "") if err != nil { klog.Fatal(err) } diff --git a/pkg/server/coupon.go b/pkg/server/coupon.go new file mode 100644 index 00000000..6ef73924 --- /dev/null +++ b/pkg/server/coupon.go @@ -0,0 +1,34 @@ +/* +Copyright AppsCode Inc. + +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 server + +import "strings" + +func ParseCouponCodes(in string) map[string]string { + parts := strings.FieldsFunc(in, func(r rune) bool { + return r == ',' || r == ';' + }) + + couponCodes := map[string]string{} + for _, part := range parts { + if event, code, ok := strings.Cut(part, ":"); ok { + couponCodes[code] = event + } + } + + return couponCodes +} diff --git a/pkg/server/enterprise.go b/pkg/server/enterprise.go index e3f8c153..0d7cb276 100644 --- a/pkg/server/enterprise.go +++ b/pkg/server/enterprise.go @@ -29,7 +29,7 @@ func (s *Server) IssueEnterpriseLicense(info LicenseForm, extendBy time.Duration } { - err = LogLicense(s.sheet, accesslog) + err = LogLicense(s.sheet, accesslog, "") if err != nil { return err } diff --git a/pkg/server/options.go b/pkg/server/options.go index d598068d..b7167031 100644 --- a/pkg/server/options.go +++ b/pkg/server/options.go @@ -53,6 +53,8 @@ type Options struct { BlockedEmails []string EnableDripCampaign bool + + Coupons string } func NewOptions() *Options { @@ -75,6 +77,7 @@ func NewOptions() *Options { listmonkPassword: os.Getenv("LISTMONK_PASSWORD"), GoogleCredentialDir: cwd, EnableDripCampaign: true, + Coupons: os.Getenv("COUPONS"), } } @@ -108,4 +111,6 @@ func (s *Options) AddFlags(fs *pflag.FlagSet) { fs.StringSliceVar(&s.BlockedEmails, "blocked-emails", s.BlockedEmails, "Emails blocked from downloading license automatically") fs.BoolVar(&s.EnableDripCampaign, "drip-campaign", s.EnableDripCampaign, "Set true to enable drip campaign runner") + + fs.StringVar(&s.Coupons, "coupons", s.Coupons, "Coupon codes") } diff --git a/pkg/server/server.go b/pkg/server/server.go index 9bfe605a..1e7e7b15 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -85,6 +85,8 @@ type Server struct { blockedDomains sets.String blockedEmails sets.String + + couponCodes map[string]string } func New(opts *Options) (*Server, error) { @@ -171,6 +173,7 @@ func New(opts *Options) (*Server, error) { zoomAccountEmail: os.Getenv("ZOOM_ACCOUNT_EMAIL"), blockedDomains: sets.NewString(opts.BlockedDomains...), blockedEmails: sets.NewString(opts.BlockedEmails...), + couponCodes: ParseCouponCodes(opts.Coupons), }, nil } @@ -432,7 +435,7 @@ func (s *Server) HandleIssueLicense(ctx *macaron.Context, info LicenseForm) erro if err != nil { return err } - err = s.recordLicenseEvent(ctx, info, timestamp, EventTypeLicenseBlocked) + err = s.recordLicenseEvent(ctx, info, timestamp, "", EventTypeLicenseBlocked) if err != nil { return err } @@ -456,6 +459,11 @@ func (s *Server) HandleIssueLicense(ctx *macaron.Context, info LicenseForm) erro if err != nil { return err } + couponEvent, couponOK := s.couponCodes[info.Coupon] + if couponOK { + oneyr := metav1.Duration{Duration: DefaultTTLForCommunityProduct} + license.TTL = &oneyr + } crtLicense, err := s.CreateOrRetrieveLicense(info, *license, info.Cluster) if err != nil { return err @@ -525,7 +533,7 @@ func (s *Server) HandleIssueLicense(ctx *macaron.Context, info LicenseForm) erro // return err //} - err = s.recordLicenseEvent(ctx, info, timestamp, EventTypeLicenseIssued) + err = s.recordLicenseEvent(ctx, info, timestamp, couponEvent, EventTypeLicenseIssued) return }() } @@ -565,7 +573,7 @@ func (s *Server) HandleIssueLicense(ctx *macaron.Context, info LicenseForm) erro return nil } -func (s *Server) recordLicenseEvent(ctx *macaron.Context, info LicenseForm, timestamp string, event LicenseEventType) error { +func (s *Server) recordLicenseEvent(ctx *macaron.Context, info LicenseForm, timestamp, couponEvent string, event LicenseEventType) error { domain := Domain(info.Email) // record request @@ -594,7 +602,7 @@ func (s *Server) recordLicenseEvent(ctx *macaron.Context, info LicenseForm, time return err } - err = LogLicense(s.sheet, &accesslog) + err = LogLicense(s.sheet, &accesslog, couponEvent) if err != nil { return err } @@ -679,12 +687,29 @@ func (s *Server) CreateOrRetrieveLicense(info LicenseForm, license ProductLicens return CreateLicense(s.fs, s.certs, info, license, cluster, nil) } -func LogLicense(si *gdrive.Spreadsheet, info *LogEntry) error { +func LogLicense(si *gdrive.Spreadsheet, info *LogEntry, couponEvent string) error { const sheetName = "License Issue Log" sheetId, err := si.EnsureSheet(sheetName, LogEntry{}.Headers()) if err != nil { return err } - return si.AppendRowData(sheetId, info.Data(), false) + err = si.AppendRowData(sheetId, info.Data(), false) + if err != nil { + return err + } + + if couponEvent != "" { + couponSheet := "COUPON_" + couponEvent + couponSheetId, err := si.EnsureSheet(couponSheet, LogEntry{}.Headers()) + if err != nil { + return err + } + err = si.AppendRowData(couponSheetId, info.Data(), false) + if err != nil { + return err + } + } + + return nil } diff --git a/pkg/server/types.go b/pkg/server/types.go index ce96dd99..9e38ca97 100644 --- a/pkg/server/types.go +++ b/pkg/server/types.go @@ -50,6 +50,7 @@ type LicenseForm struct { Cluster string `form:"cluster" binding:"Required" json:"cluster"` Tos string `form:"tos" binding:"Required" json:"tos"` Token string `form:"token" json:"token"` + Coupon string `form:"coupon" json:"coupon"` } type LicenseMailData struct { diff --git a/templates/index.html b/templates/index.html index 8350c721..c496d8f8 100644 --- a/templates/index.html +++ b/templates/index.html @@ -91,6 +91,12 @@

AppsCode License Server

>

+
+ +
+ +
+