Skip to content

Commit 1bfeb81

Browse files
committed
Fix license expiration check
Signed-off-by: Tamal Saha <tamal@appscode.com>
1 parent e93a886 commit 1bfeb81

File tree

6 files changed

+77
-22
lines changed

6 files changed

+77
-22
lines changed

pkg/apiserver/apiserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ func (c completedConfig) New(ctx context.Context) (*LicenseProxyServer, error) {
197197
}
198198

199199
rb := storage.NewRecordBook()
200-
reg := storage.NewLicenseRegistry(c.ExtraConfig.CacheDir, rb)
200+
reg := storage.NewLicenseRegistry(c.ExtraConfig.CacheDir, storage.MinRemainingLife, rb)
201201
if c.ExtraConfig.LicenseDir != "" {
202202
err = storage.LoadDir(cid, c.ExtraConfig.LicenseDir, reg)
203203
if err != nil {

pkg/controllers/secret/license_syncer.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ import (
2020
"context"
2121
"crypto/x509"
2222
"fmt"
23+
"time"
2324

2425
"go.bytebuilders.dev/license-proxyserver/pkg/common"
2526
"go.bytebuilders.dev/license-proxyserver/pkg/storage"
2627
verifier "go.bytebuilders.dev/license-verifier"
2728

2829
core "k8s.io/api/core/v1"
2930
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31+
"k8s.io/klog/v2"
3032
kutil "kmodules.xyz/client-go"
3133
cu "kmodules.xyz/client-go/client"
3234
ctrl "sigs.k8s.io/controller-runtime"
@@ -100,6 +102,15 @@ func (r *LicenseSyncer) addLicense(data []byte) error {
100102
if err != nil {
101103
return err
102104
}
103-
r.R.Add(&license, nil)
105+
106+
if time.Until(license.NotAfter.Time) >= storage.MinRemainingLife {
107+
klog.InfoS("adding license",
108+
"id", license.ID,
109+
"product", license.ProductLine,
110+
"plan", license.PlanName,
111+
"expiry", license.NotAfter.UTC().Format(time.RFC822),
112+
)
113+
r.R.Add(&license, nil)
114+
}
104115
return nil
105116
}

pkg/manager/license_acquirer.go

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"path/filepath"
2626
"strings"
2727
"sync"
28+
"time"
2829

2930
"go.bytebuilders.dev/license-proxyserver/pkg/common"
3031
"go.bytebuilders.dev/license-proxyserver/pkg/storage"
@@ -46,6 +47,8 @@ import (
4647
"sigs.k8s.io/controller-runtime/pkg/reconcile"
4748
)
4849

50+
const ttl = storage.LicenseAcquisitionBuffer + storage.MinRemainingLife
51+
4952
type LicenseAcquirer struct {
5053
client.Client
5154
BaseURL string
@@ -88,10 +91,7 @@ func (r *LicenseAcquirer) Reconcile(ctx context.Context, request reconcile.Reque
8891
}
8992
}
9093
if cid != "" && len(features) > 0 {
91-
err = r.reconcile(ctx, managedCluster.Name, cid, features)
92-
if err != nil {
93-
return reconcile.Result{}, err
94-
}
94+
return r.reconcile(managedCluster.Name, cid, features)
9595
}
9696

9797
return reconcile.Result{}, nil
@@ -111,12 +111,12 @@ func (r *LicenseAcquirer) getLicenseRegistry(cid string) (*storage.LicenseRegist
111111
if err != nil {
112112
return nil, err
113113
}
114-
reg = storage.NewLicenseRegistry(dir, nil)
114+
reg = storage.NewLicenseRegistry(dir, ttl, nil)
115115
r.LicenseCache[cid] = reg
116116
return reg, nil
117117
}
118118

119-
func (r *LicenseAcquirer) reconcile(ctx context.Context, clusterName, cid string, features []string) error {
119+
func (r *LicenseAcquirer) reconcile(clusterName, cid string, features []string) (reconcile.Result, error) {
120120
sec := core.Secret{
121121
ObjectMeta: metav1.ObjectMeta{
122122
Name: common.LicenseSecret,
@@ -130,20 +130,21 @@ func (r *LicenseAcquirer) reconcile(ctx context.Context, clusterName, cid string
130130
} else if apierrors.IsNotFound(err) {
131131
sec.Data = map[string][]byte{}
132132
} else {
133-
return err
133+
return reconcile.Result{}, err
134134
}
135135

136136
var errList []error
137+
var earliestExpired time.Time
137138

138139
reg, err := r.getLicenseRegistry(cid)
139140
if err != nil {
140-
return err
141+
return reconcile.Result{}, err
141142
}
142143
for _, feature := range features {
143144
l, found := reg.LicenseForFeature(feature)
144145
if !found {
145146
var c *v1alpha1.Contract
146-
l, c, err = r.getNewLicense(ctx, cid, []string{feature})
147+
l, c, err = r.getNewLicense(cid, []string{feature})
147148
if err == nil {
148149
reg.Add(l, c)
149150
} else {
@@ -156,6 +157,9 @@ func (r *LicenseAcquirer) reconcile(ctx context.Context, clusterName, cid string
156157
}
157158
if l != nil && l.Status == v1alpha1.LicenseActive {
158159
sec.Data[l.PlanName] = l.Data
160+
if earliestExpired.IsZero() || earliestExpired.After(l.NotAfter.Time) {
161+
earliestExpired = l.NotAfter.Time
162+
}
159163
}
160164
}
161165

@@ -165,12 +169,15 @@ func (r *LicenseAcquirer) reconcile(ctx context.Context, clusterName, cid string
165169
errList = append(errList, r.Create(context.TODO(), &sec))
166170
}
167171

168-
return utilerrors.NewAggregate(errList)
172+
if !earliestExpired.IsZero() {
173+
return reconcile.Result{
174+
RequeueAfter: time.Until(earliestExpired.Add(-ttl)),
175+
}, utilerrors.NewAggregate(errList)
176+
}
177+
return reconcile.Result{}, utilerrors.NewAggregate(errList)
169178
}
170179

171-
func (r *LicenseAcquirer) getNewLicense(ctx context.Context, cid string, features []string) (*v1alpha1.License, *v1alpha1.Contract, error) {
172-
logger := log.FromContext(ctx)
173-
180+
func (r *LicenseAcquirer) getNewLicense(cid string, features []string) (*v1alpha1.License, *v1alpha1.Contract, error) {
174181
lc, err := pc.NewClient(r.BaseURL, r.Token, cid, r.CaCert, r.InsecureSkipTLSVerify, fmt.Sprintf("license-proxyserver-manager/%s", v.Version.Version))
175182
if err != nil {
176183
return nil, nil, err
@@ -180,7 +187,6 @@ func (r *LicenseAcquirer) getNewLicense(ctx context.Context, cid string, feature
180187
if err != nil {
181188
return nil, nil, err
182189
}
183-
logger.Info("acquired new license", "cid", cid, "features", strings.Join(features, ","))
184190

185191
caData, err := info.LoadLicenseCA()
186192
if err != nil {
@@ -200,5 +206,12 @@ func (r *LicenseAcquirer) getNewLicense(ctx context.Context, cid string, feature
200206
return nil, nil, err
201207
}
202208

209+
klog.InfoS("acquired new license",
210+
"cluster", cid,
211+
"id", l.ID,
212+
"product", l.ProductLine,
213+
"plan", l.PlanName,
214+
"expiry", l.NotAfter.UTC().Format(time.RFC822),
215+
)
203216
return &l, con, nil
204217
}

pkg/registry/proxyserver/licenserequest/storage.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"crypto/x509"
2222
"sort"
2323
"strings"
24+
"time"
2425

2526
proxyv1alpha1 "go.bytebuilders.dev/license-proxyserver/apis/proxyserver/v1alpha1"
2627
"go.bytebuilders.dev/license-proxyserver/pkg/common"
@@ -36,6 +37,7 @@ import (
3637
"k8s.io/apimachinery/pkg/util/sets"
3738
"k8s.io/apiserver/pkg/endpoints/request"
3839
"k8s.io/apiserver/pkg/registry/rest"
40+
"k8s.io/klog/v2"
3941
clustermeta "kmodules.xyz/client-go/cluster"
4042
clusterv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
4143
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -143,6 +145,7 @@ func (r *Storage) Create(ctx context.Context, obj runtime.Object, _ rest.Validat
143145
}
144146
} else {
145147
// return blank response instead of error
148+
// typically license mounted via secret has expired
146149
in.Response = &proxyv1alpha1.LicenseRequestResponse{}
147150
}
148151

@@ -172,6 +175,13 @@ func (r *Storage) getLicense(features []string) (*v1alpha1.License, error) {
172175
if err != nil {
173176
return nil, err
174177
}
178+
179+
klog.InfoS("adding license",
180+
"id", l.ID,
181+
"product", l.ProductLine,
182+
"plan", l.PlanName,
183+
"expiry", l.NotAfter.UTC().Format(time.RFC822),
184+
)
175185
r.reg.Add(&l, c)
176186
return &l, nil
177187
}

pkg/storage/loader.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package storage
1919
import (
2020
"os"
2121
"path/filepath"
22+
"time"
2223

2324
verifier "go.bytebuilders.dev/license-verifier"
2425
"go.bytebuilders.dev/license-verifier/info"
@@ -68,7 +69,14 @@ func LoadDir(cid, dir string, reg *LicenseRegistry) error {
6869
if err != nil {
6970
klog.ErrorS(err, "Skipping", "file", filename)
7071
continue
71-
} else {
72+
} else if time.Until(license.NotAfter.Time) >= MinRemainingLife {
73+
klog.InfoS("adding license",
74+
"dir", dir,
75+
"id", license.ID,
76+
"product", license.ProductLine,
77+
"plan", license.PlanName,
78+
"expiry", license.NotAfter.UTC().Format(time.RFC822),
79+
)
7280
reg.Add(&license, nil)
7381
}
7482
}

pkg/storage/store.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,14 @@ import (
2525
"time"
2626

2727
"go.bytebuilders.dev/license-verifier/apis/licenses/v1alpha1"
28+
29+
"k8s.io/klog/v2"
2830
)
2931

30-
const minRemainingLife = 10 * time.Minute
32+
const (
33+
LicenseAcquisitionBuffer = 5 * time.Second
34+
MinRemainingLife = 5 * time.Minute
35+
)
3136

3237
// A LicenseQueue implements heap.Interface and holds Items.
3338
type LicenseQueue []*v1alpha1.License
@@ -67,11 +72,13 @@ type LicenseRegistry struct {
6772
store map[string]*Record // serial # -> Record
6873
rb *RecordBook
6974
cacheDir string
75+
ttl time.Duration
7076
}
7177

72-
func NewLicenseRegistry(cacheDir string, rb *RecordBook) *LicenseRegistry {
78+
func NewLicenseRegistry(cacheDir string, ttl time.Duration, rb *RecordBook) *LicenseRegistry {
7379
return &LicenseRegistry{
7480
cacheDir: cacheDir,
81+
ttl: ttl,
7582
reg: make(map[string]LicenseQueue),
7683
store: make(map[string]*Record),
7784
rb: rb,
@@ -109,13 +116,19 @@ func (r *LicenseRegistry) LicenseForFeature(feature string) (*v1alpha1.License,
109116
if !ok {
110117
return nil, false
111118
}
112-
now := time.Now().Add(minRemainingLife)
113119
for q.Len() > 0 {
114120
// ref: https://stackoverflow.com/a/63328950
115121
item := q[0]
116-
if now.After(item.NotAfter.Time) {
122+
if time.Until(item.NotAfter.Time) < r.ttl {
117123
heap.Pop(&q)
118124
r.reg[feature] = q
125+
126+
klog.InfoS("removing license",
127+
"id", item.ID,
128+
"product", item.ProductLine,
129+
"plan", item.PlanName,
130+
"expiry", item.NotAfter.UTC().Format(time.RFC822),
131+
)
119132
r.removeFromStore(item)
120133
} else {
121134
return item, true
@@ -153,7 +166,7 @@ func (r *LicenseRegistry) List() []*Record {
153166
r.m.Lock()
154167
defer r.m.Unlock()
155168

156-
now := time.Now().Add(minRemainingLife)
169+
now := time.Now().Add(r.ttl)
157170
out := make([]*Record, 0, len(r.store))
158171
for _, rec := range r.store {
159172
if rec.License.NotAfter.After(now) {

0 commit comments

Comments
 (0)