/
context.go
166 lines (140 loc) · 6.48 KB
/
context.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
* Tencent is pleased to support the open source community by making TKEStack
* available.
*
* Copyright (C) 2012-2019 Tencent. 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
*
* https://opensource.org/licenses/Apache-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 OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package app
import (
"fmt"
"net/http"
"time"
"github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait"
cacheddiscovery "k8s.io/client-go/discovery/cached"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
"tkestack.io/tke/api/auth"
versionedclientset "tkestack.io/tke/api/client/clientset/versioned"
v1 "tkestack.io/tke/api/client/clientset/versioned/typed/auth/v1"
versionedinformers "tkestack.io/tke/api/client/informers/externalversions"
"tkestack.io/tke/cmd/tke-auth-controller/app/config"
util2 "tkestack.io/tke/pkg/auth/util"
"tkestack.io/tke/pkg/controller"
"tkestack.io/tke/pkg/controller/util"
)
// InitFunc is used to launch a particular controller. It may run additional "should I activate checks".
// Any error returned will cause the controller process to `Fatal`
// The bool indicates whether the controller was enabled.
type InitFunc func(ctx ControllerContext) (debuggingHandler http.Handler, enabled bool, err error)
// ControllerContext represents the context of controller.
type ControllerContext struct {
// ClientBuilder will provide a client for this controller to use
ClientBuilder controller.ClientBuilder
// InformerFactory gives access to informers for the controller.
InformerFactory versionedinformers.SharedInformerFactory
// DeferredDiscoveryRESTMapper is a RESTMapper that will defer
// initialization of the RESTMapper until the first mapping is
// requested.
RESTMapper *restmapper.DeferredDiscoveryRESTMapper
// AvailableResources is a map listing currently available resources
AvailableResources map[schema.GroupVersionResource]bool
// Enforcer is a casbin enforcer to operate policy.
Enforcer *casbin.SyncedEnforcer
// Stop is the stop channel
Stop <-chan struct{}
// InformersStarted is closed after all of the controllers have been initialized and are running. After this point it is safe,
// for an individual controller to start the shared informers. Before it is closed, they should not.
InformersStarted chan struct{}
// ResyncPeriod generates a duration each time it is invoked; this is so that
// multiple controllers don't get into lock-step and all hammer the apiserver
// with list requests simultaneously.
ResyncPeriod func() time.Duration
ControllerStartInterval time.Duration
PolicyPath string
CategoryPath string
TenantAdmin string
TenantAdminSecret string
AuthClient v1.AuthV1Interface
}
// IsControllerEnabled returns whether the controller has been enabled
func (c ControllerContext) IsControllerEnabled(name string) bool {
return util.IsControllerEnabled(name, ControllersDisabledByDefault)
}
// CreateControllerContext creates a context struct containing references to resources needed by the
// controllers such as the cloud provider and clientBuilder. rootClientBuilder is only used for
// the shared-informers client and token controller.
func CreateControllerContext(cfg *config.Config, rootClientBuilder controller.ClientBuilder, stop <-chan struct{}) (ControllerContext, error) {
client, err := versionedclientset.NewForConfig(rest.AddUserAgent(cfg.AuthAPIServerClientConfig, "tke-auth-controller"))
if err != nil {
return ControllerContext{}, fmt.Errorf("failed to create the business client: %v", err)
}
versionedClient := rootClientBuilder.ClientOrDie("shared-informers")
sharedInformers := versionedinformers.NewSharedInformerFactory(versionedClient, controller.ResyncPeriod(&cfg.Component)())
// If apiserver is not running we should wait for some time and fail only then. This is particularly
// important when we start apiserver and controller manager at the same time.
if err := controller.WaitForAPIServer(versionedClient, 10*time.Second); err != nil {
return ControllerContext{}, fmt.Errorf("failed to wait for apiserver being healthy: %v", err)
}
// Use a discovery client capable of being refreshed.
discoveryClient := rootClientBuilder.ClientOrDie("controller-discovery")
cachedClient := cacheddiscovery.NewMemCacheClient(discoveryClient.Discovery())
restMapper := restmapper.NewDeferredDiscoveryRESTMapper(cachedClient)
go wait.Until(func() {
restMapper.Reset()
}, 5*time.Minute, stop)
availableResources, err := controller.GetAvailableResources(rootClientBuilder)
if err != nil {
return ControllerContext{}, err
}
adpt := util2.NewAdapter(client.AuthV1().Rules(), sharedInformers.Auth().V1().Rules().Lister())
var enforcer *casbin.SyncedEnforcer
if len(cfg.CasbinModelFile) == 0 {
m, err := model.NewModelFromString(auth.DefaultRuleModel)
if err != nil {
return ControllerContext{}, fmt.Errorf("failed to new model from default model string: %v", err)
}
enforcer, err = casbin.NewSyncedEnforcer(m, adpt)
if err != nil {
return ControllerContext{}, fmt.Errorf("failed to new casbin enforcer: %v", err)
}
} else {
enforcer, err = casbin.NewSyncedEnforcer(cfg.CasbinModelFile, adpt)
if err != nil {
return ControllerContext{}, fmt.Errorf("failed to new casbin enforcer from model file: %v", err)
}
}
rm := util2.NewRoleManager(10)
enforcer.SetRoleManager(rm)
enforcer.StartAutoLoadPolicy(cfg.CasbinReloadInterval)
ctx := ControllerContext{
ClientBuilder: rootClientBuilder,
InformerFactory: sharedInformers,
RESTMapper: restMapper,
AvailableResources: availableResources,
Enforcer: enforcer,
Stop: stop,
InformersStarted: make(chan struct{}),
ResyncPeriod: controller.ResyncPeriod(&cfg.Component),
ControllerStartInterval: cfg.Component.ControllerStartInterval,
PolicyPath: cfg.PolicyPath,
CategoryPath: cfg.CategoryPath,
TenantAdmin: cfg.TenantAdmin,
TenantAdminSecret: cfg.TenantAdminSecret,
AuthClient: client.AuthV1(),
}
return ctx, nil
}