├── .github
└── workflows
│ └── push-to-docker-hub.yml
├── Dockerfile
├── LICENSE
├── README.md
├── calico-networksets-controller.go
├── go.mod
└── k8s-mainfest.yaml
/.github/workflows/push-to-docker-hub.yml:
--------------------------------------------------------------------------------
1 | name: Publish Docker image
2 | on:
3 | release:
4 | types: [published]
5 | jobs:
6 | push_to_registry:
7 | name: Push Docker image to Docker Hub
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Check out the repo
11 | uses: actions/checkout@v2
12 | - name: Push to Docker Hub
13 | uses: docker/build-push-action@v1
14 | with:
15 | username: ${{ secrets.DOCKER_USERNAME }}
16 | password: ${{ secrets.DOCKER_PASSWORD }}
17 | repository: ktrufanov/k8s-calico-networksets-controller
18 | tag_with_ref: true
19 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.15 AS builder
2 |
3 | WORKDIR $GOPATH/src/github.com/ktrufanov/k8s-calico-networksets-controller
4 | COPY . .
5 | RUN CGO_ENABLED=0 GOOS=linux go build -o /calico-networksets-controller calico-networksets-controller.go
6 | FROM alpine:latest
7 | COPY --from=builder /calico-networksets-controller /calico-networksets-controller
8 |
9 | CMD ["./calico-networksets-controller"]
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # k8s-calico-networksets-controller
2 |
3 | With this controller, you can control access to/from custom resources by their names
4 | The addresses of these resources can be obtained from your own dedicated service
5 | For example, they can be salt hosts, net prefixes, dns names...
6 | Here is an example with dns names
7 | Service for dns resolving - [dns-resolver](https://github.com/ktrufanov/dns-resolver)
8 |
9 | ## Install
10 | quick start
11 | ```
12 | kubectl create ns calico-networksets-controller
13 | kubectl apply -f https://raw.githubusercontent.com/ktrufanov/dns-resolver/0.0.1/k8s-mainfest.yaml
14 | kubectl apply -f https://raw.githubusercontent.com/ktrufanov/k8s-calico-networksets-controller/0.0.11-1/k8s-mainfest.yaml
15 | ```
16 |
17 | ## Description
18 | Controller watches by create/update/delete [Calico NetworkPolicy](https://docs.projectcalico.org/reference/resources/networkpolicy).
19 | If source/destination selector of NetworkPolicy have the specific label then controller creates/updates [Calico NetworkSet](https://docs.projectcalico.org/reference/resources/networkset).
20 | IP networks/CIDRs for NetworkSet are requested from the http url. This url is customizable for specific label.
21 | Controller periodically updates the NetworkSet.
22 | Аlso works with GlobalNetworkPolicy/GlobalNetworkSet.
23 |
24 | ***/config-k8s/networksets-controller.toml:***
25 | ```
26 | [main]
27 | reload_time=60000
28 | debug=false
29 | service_port=8080
30 |
31 | [DNS_RESOLVER]
32 | url="http://dns-resolver.calico-networksets-controller:8080/dns"
33 |
34 | [OTHER_NET_SOURCE]
35 | url="http://other-net-source.calico-networksets-controller:8080/nets"
36 | ```
37 | ***main*** section:
38 | - ***reload-time*** - time to reload networksets in ms
39 | - ***debug*** - debug log
40 | - ***service_port*** - service listen port
41 |
42 | The names of other sections are specific labels
43 | - ***DNS_RESOLVER***, ***OTHER_NET_SOURCE*** - specific labels
44 | - ***url*** - net source for specific label
45 |
46 | http request example:
47 | ```
48 | curl -X POST --data "item=github.com" http://dns-resolver.calico-networksets-controller:8080/dns
49 | ```
50 | response must be in format:
51 | ```
52 | {"Nets":["140.82.121.4/32"]}
53 | ```
54 | ## Example
55 | NetworkPolicy:
56 | ```
57 | apiVersion: crd.projectcalico.org/v1
58 | kind: NetworkPolicy
59 | metadata:
60 | name: default.test-allow-github
61 | namespace: examples
62 | spec:
63 | selector: app == 'k8s-example'
64 | types:
65 | - Egress
66 | egress:
67 | - action: Allow
68 | protocol: TCP
69 | destination:
70 | selector: DNS_RESOLVER == 'github.com'
71 | ports:
72 | - 443
73 | ```
74 | This NetworkPolicy allow tcp port 443 to github.com
75 |
76 | NetworkSet will be create for this NetworkPolicy :
77 | ```
78 | apiVersion: crd.projectcalico.org/v1
79 | kind: NetworkSet
80 | metadata:
81 | annotations:
82 | automatization/networksets-controller: "true"
83 | labels:
84 | DNS_RESOLVER: github.com
85 | name: auto-ns-github-com
86 | namespace: examples
87 | spec:
88 | nets:
89 | - 140.82.121.3/32
90 | ```
91 | This NetworkSet will be refreshed every ***reload_time*** times
92 |
93 | ## Metrics
94 | - ***networksets_controller_errors*** - "Count of errors"
95 |
--------------------------------------------------------------------------------
/calico-networksets-controller.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "net/http"
5 | "reflect"
6 | "time"
7 | "sort"
8 | "fmt"
9 | "context"
10 | "strings"
11 | "regexp"
12 | "os"
13 | "os/signal"
14 | "encoding/json"
15 | "k8s.io/client-go/kubernetes"
16 | "k8s.io/client-go/rest"
17 | "k8s.io/apimachinery/pkg/runtime/schema"
18 | "k8s.io/client-go/dynamic"
19 | "k8s.io/client-go/dynamic/dynamicinformer"
20 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
21 | "k8s.io/client-go/tools/cache"
22 | "github.com/prometheus/client_golang/prometheus"
23 | "github.com/prometheus/client_golang/prometheus/promauto"
24 | "github.com/prometheus/client_golang/prometheus/promhttp"
25 | "github.com/projectcalico/libcalico-go/lib/options"
26 | "k8s.io/client-go/tools/clientcmd"
27 | "github.com/projectcalico/libcalico-go/lib/selector/tokenizer"
28 | "github.com/spf13/viper"
29 | calicoapi "github.com/projectcalico/libcalico-go/lib/apis/v3"
30 | calicoclient "github.com/projectcalico/libcalico-go/lib/clientv3"
31 | neturl "net/url"
32 | log "github.com/sirupsen/logrus"
33 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34 |
35 | )
36 |
37 |
38 | type networksetsController struct {
39 | runtime_viper *viper.Viper
40 | clientset *kubernetes.Clientset
41 | calicoClient calicoclient.Interface
42 | ctx context.Context
43 | metric_counter map[string]prometheus.Counter
44 | }
45 |
46 | type nets_type struct {
47 | Nets []string `json:"nets,omitempty" validate:"omitempty,dive,cidr"`
48 | }
49 |
50 | func getOneHTTPparamWithEmpty(r *http.Request,param string) string{
51 | if param, ok := r.Form[param]; ok {
52 | return param[0]
53 | }
54 | return ""
55 | }
56 |
57 |
58 |
59 | func in_array(a string, list []string) bool {
60 | for _, b := range list {
61 | if b == a {
62 | return true
63 | }
64 | }
65 | return false
66 | }
67 |
68 | func AppendIfMissingStr(slice []string, i string) []string {
69 | for _, ele := range slice {
70 | if ele == i {
71 | return slice
72 | }
73 | }
74 | return append(slice, i)
75 | }
76 |
77 | func AppendIfMissing(slice []string, i ...string) []string {
78 | for _, sli := range i {
79 | slice=AppendIfMissingStr(slice, sli)
80 | }
81 | return slice
82 | }
83 |
84 |
85 |
86 |
87 | // getClients builds and returns Kubernetes and Calico clients.
88 | func (nc *networksetsController) getClients(kubeconfig string) (*kubernetes.Clientset, calicoclient.Interface, error) {
89 | // Get Calico client
90 | calicoClient, err := calicoclient.NewFromEnv()
91 | if err != nil {
92 | return nil, nil, fmt.Errorf("failed to build Calico client: %s", err)
93 | }
94 |
95 | // Now build the Kubernetes client, we support in-cluster config and kubeconfig
96 | // as means of configuring the client.
97 | k8sconfig, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
98 | if err != nil {
99 | return nil, nil, fmt.Errorf("failed to build kubernetes client config: %s", err)
100 | }
101 |
102 | // Get Kubernetes clientset
103 | k8sClientset, err := kubernetes.NewForConfig(k8sconfig)
104 | if err != nil {
105 | return nil, nil, fmt.Errorf("failed to build kubernetes client: %s", err)
106 | }
107 |
108 | return k8sClientset, calicoClient, nil
109 | }
110 |
111 |
112 | func (nc *networksetsController) run() {
113 | config, err := rest.InClusterConfig()
114 | if err != nil {
115 | log.Println(err.Error())
116 | }
117 | // creates the dynami client
118 | dc, err := dynamic.NewForConfig(config)
119 | if err != nil {
120 | log.Println(err.Error())
121 | }
122 | // Create a factory object that we can say "hey, I need to watch this resource"
123 | // and it will give us back an informer for it
124 | f := dynamicinformer.NewFilteredDynamicSharedInformerFactory(dc, 0, metav1.NamespaceAll, nil)
125 |
126 | //Look by NetworkPolicies
127 | npr, _ := schema.ParseResourceArg("networkpolicies.v1.crd.projectcalico.org")
128 | // Finally, create our informer for resource!
129 | i := f.ForResource(*npr)
130 |
131 | stopChNetworkpolicy := make(chan struct{})
132 | go nc.startNetworkpolicyWatching(stopChNetworkpolicy, i.Informer())
133 |
134 |
135 | //Look by GlobalNetworkPolicies
136 | gnpr, _ := schema.ParseResourceArg("globalnetworkpolicies.v1.crd.projectcalico.org")
137 | // Finally, create our informer for resource!
138 | j := f.ForResource(*gnpr)
139 | stopChGlobalNetworkpolicy := make(chan struct{})
140 | go nc.startGlobalNetworkpolicyWatching(stopChGlobalNetworkpolicy, j.Informer())
141 |
142 | sigCh := make(chan os.Signal, 0)
143 | signal.Notify(sigCh, os.Kill, os.Interrupt)
144 |
145 | <-sigCh
146 | close(stopChNetworkpolicy)
147 | close(stopChGlobalNetworkpolicy)
148 | }
149 |
150 |
151 |
152 | func (nc *networksetsController) GetLabelsBySelector(sel string) (map[string][]string,error) {
153 |
154 | //Get config sections
155 | var config_strings []string
156 | for label,_ := range nc.runtime_viper.AllSettings() {
157 | if (label != "main") {
158 | config_strings = append(config_strings, label)
159 | }
160 | }
161 | log.Debug("config strings: ",config_strings)
162 |
163 | //Get tokens from selector
164 | tokens,parse_err := tokenizer.Tokenize(sel)
165 | if parse_err!=nil {
166 | return map[string][]string{}, parse_err
167 | }
168 | log.Debug("tokens: ",tokens)
169 |
170 | //return labels if tokens equal config label
171 | out := make(map[string][]string)
172 | now_label:=""
173 | for _,token := range tokens {
174 | token_label:=strings.ToLower(fmt.Sprintf("%v",token.Value))
175 | if ( token.Kind == tokenizer.TokLabel ) {
176 | if ( in_array(token_label, config_strings ) ) {
177 | now_label=fmt.Sprintf("%v",token.Value)
178 | } else {
179 | now_label = ""
180 | }
181 | }
182 | if ( now_label!="" && token.Kind == tokenizer.TokStringLiteral) {
183 | out[now_label] = AppendIfMissing( out[now_label], fmt.Sprintf("%v",token.Value) )
184 | }
185 | }
186 |
187 | return out,nil
188 | }
189 |
190 | func MergeMaps(base map[string][]string, in map[string][]string ) (map[string][]string) {
191 | out:=base
192 | for k,v := range in {
193 | out[k] = AppendIfMissing(out[k],v...)
194 | }
195 | return out
196 | }
197 |
198 |
199 | /*
200 | NETWORK POLICIES
201 | */
202 | func (nc *networksetsController) GetNetworkPolicyRuleLabels( namespace string, np_name string ) ( map[string][]string, error) {
203 |
204 | //Read Network Policy
205 | out:=make(map[string][]string)
206 | np, err := nc.calicoClient.NetworkPolicies().Get(nc.ctx, namespace, np_name, options.GetOptions{})
207 | if err != nil {
208 | return out, err
209 | }
210 | for _,rule := range np.Spec.Ingress {
211 | log.Debug("Ingress selector - ", rule.Source.Selector)
212 |
213 | lbls,lblerr := nc.GetLabelsBySelector(rule.Source.Selector)
214 | if lblerr != nil {
215 | return out, lblerr
216 | }
217 | out=MergeMaps(out,lbls)
218 |
219 | lbls,lblerr = nc.GetLabelsBySelector(rule.Destination.Selector)
220 | if lblerr != nil {
221 | return out, lblerr
222 | }
223 | out=MergeMaps(out,lbls)
224 |
225 | }
226 | for _,rule := range np.Spec.Egress {
227 | log.Debug("Egress selector - ", rule.Source.Selector)
228 |
229 | lbls,lblerr := nc.GetLabelsBySelector(rule.Source.Selector)
230 | if lblerr != nil {
231 | return out, lblerr
232 | }
233 | out=MergeMaps(out,lbls)
234 |
235 | lbls,lblerr = nc.GetLabelsBySelector(rule.Destination.Selector)
236 | if lblerr != nil {
237 | return out, lblerr
238 | }
239 | out=MergeMaps(out,lbls)
240 | }
241 | log.Debug("labels=",out)
242 | return out, nil
243 |
244 | }
245 |
246 | func (nc *networksetsController) SetupNetworksets(namespace string, name string) (error) {
247 |
248 | //Collect all policy in current namespace
249 | namespace_rules := make(map[string][]string)
250 | calicoPolicies, err := nc.calicoClient.NetworkPolicies().List(nc.ctx, options.ListOptions{Namespace: namespace})
251 | if err != nil {
252 | return err
253 | }
254 | for _, policy := range calicoPolicies.Items {
255 |
256 |
257 | log.Debug("Find policy: ",policy.Name)
258 | //Check rules for selector
259 | rl,err_rule:=nc.GetNetworkPolicyRuleLabels( namespace, policy.Name )
260 | if err_rule != nil {
261 | log.Info(err_rule)
262 | nc.metric_counter["error_counter"].Inc()
263 | continue
264 | }
265 | //In namespace_rules collect all label vaules
266 | namespace_rules = MergeMaps(namespace_rules,rl)
267 | }
268 | log.Debug("rule labels = ",namespace_rules)
269 |
270 | //Get NetwrokSets in current namespace
271 | current_networksets := make(map[string]map[string]bool)
272 | calicoNetworksets, err := nc.calicoClient.NetworkSets().List(nc.ctx, options.ListOptions{Namespace: namespace})
273 | if err != nil {
274 | return err
275 | }
276 | //Find networksets with label from configuration
277 | for _, networkset := range calicoNetworksets.Items {
278 | if (metav1.HasAnnotation(networkset.ObjectMeta,"automatization/networksets-controller")) {
279 | meta_labels := networkset.ObjectMeta.GetLabels()
280 | for lbl,lbl_slice := range namespace_rules {
281 | for _,val := range lbl_slice {
282 | if meta_labels[lbl] == val {
283 | log.Debug("Find networkset ",networkset.Name," with label ",lbl," = ",val)
284 | if _,ok := current_networksets[lbl]; !ok {
285 | current_networksets[lbl] = map[string]bool{val: true}
286 | } else {
287 | current_networksets[lbl][val] = true
288 | }
289 | }
290 | }
291 | }
292 |
293 | }
294 | }
295 | log.Debug("current networksets ",current_networksets)
296 |
297 | //Create networksets
298 | for lbl,lbl_slice := range namespace_rules {
299 | for _,val := range lbl_slice {
300 | if _,ok := current_networksets[lbl][val];!ok {
301 | log.Info("Create networkset ",lbl," = ",val)
302 | re := regexp.MustCompile(`[^a-z0-9\-]`)
303 | name_ns := re.ReplaceAllString(strings.ToLower("auto-ns-"+val),"-")
304 | ns, ns_err := nc.NetworksetDef(namespace, name_ns , lbl, val)
305 | if ns_err != nil {
306 | log.Info(ns_err)
307 | nc.metric_counter["error_counter"].Inc()
308 | continue
309 | }
310 | _, err := nc.calicoClient.NetworkSets().Create(nc.ctx, ns, options.SetOptions{})
311 | if err != nil {
312 | log.Info(err)
313 | nc.metric_counter["error_counter"].Inc()
314 | continue
315 | }
316 | }
317 | }
318 | }
319 |
320 | //Delete networksets
321 | for _, networkset := range calicoNetworksets.Items {
322 | if (metav1.HasAnnotation(networkset.ObjectMeta,"automatization/networksets-controller")) {
323 | meta_labels := networkset.ObjectMeta.GetLabels()
324 | for_delete := true
325 | for del_lbl, val_lbl := range meta_labels {
326 | if v,ok := current_networksets[del_lbl][val_lbl]; ok && v {
327 | for_delete = false
328 | continue
329 | }
330 | }
331 | if for_delete {
332 | ns_name:=networkset.GetName()
333 | log.Info("Delete NetworkSet ", ns_name)
334 | _, err := nc.calicoClient.NetworkSets().Delete(nc.ctx, namespace, ns_name, options.DeleteOptions{})
335 | if err != nil {
336 | return err
337 | }
338 | }
339 | }
340 | }
341 |
342 | return nil
343 | }
344 |
345 |
346 | func (nc *networksetsController) ReloadNetworksets() (error) {
347 |
348 | var config_strings []string
349 | for label,_ := range nc.runtime_viper.AllSettings() {
350 | if (label != "main") {
351 | config_strings = append(config_strings, label)
352 | }
353 | }
354 | log.Debug("config strings: ",config_strings)
355 |
356 | calicoNetworksets, err := nc.calicoClient.NetworkSets().List(nc.ctx, options.ListOptions{})
357 | if err != nil {
358 | return err
359 | }
360 | normal:=make(map[string]map[string]*calicoapi.NetworkSet)
361 | for _, networkset := range calicoNetworksets.Items {
362 | if (metav1.HasAnnotation(networkset.ObjectMeta,"automatization/networksets-controller")) {
363 | meta_labels := networkset.ObjectMeta.GetLabels()
364 | for lbl, val := range meta_labels {
365 | if in_array(strings.ToLower(lbl),config_strings) {
366 |
367 | var ns *calicoapi.NetworkSet
368 | if _,ok := normal[lbl][val]; ok {
369 | ns = normal[lbl][val]
370 | } else {
371 |
372 | var ns_err error
373 | ns, ns_err = nc.NetworksetDef(networkset.ObjectMeta.GetNamespace(), networkset.ObjectMeta.GetName() , lbl, val)
374 | if ns_err != nil {
375 | log.Info(ns_err)
376 | nc.metric_counter["error_counter"].Inc()
377 | continue
378 | }
379 | normal[lbl]=map[string]*calicoapi.NetworkSet{val:ns}
380 | }
381 | sort.Strings(ns.Spec.Nets)
382 | sort.Strings(networkset.Spec.Nets)
383 | if !reflect.DeepEqual(ns.Spec.Nets,networkset.Spec.Nets) {
384 | log.Debug("Nets are not in normal state. Update networkset ",networkset.ObjectMeta.GetName())
385 |
386 | //Update networkset
387 | ns.ObjectMeta.SetResourceVersion(networkset.ObjectMeta.GetResourceVersion())
388 | ns.ObjectMeta.SetCreationTimestamp(networkset.ObjectMeta.GetCreationTimestamp())
389 | ns.ObjectMeta.SetUID(networkset.ObjectMeta.GetUID())
390 | ns.ObjectMeta.SetNamespace(networkset.ObjectMeta.GetNamespace())
391 | _, err := nc.calicoClient.NetworkSets().Update(nc.ctx, ns, options.SetOptions{})
392 | if err != nil {
393 | log.Info(err)
394 | nc.metric_counter["error_counter"].Inc()
395 | continue
396 | }
397 |
398 | } else {
399 | log.Debug("Networkset '",networkset.ObjectMeta.GetName(),"' in normal state")
400 | }
401 |
402 |
403 |
404 | }
405 | }
406 | }
407 | }
408 | return nil
409 | }
410 |
411 |
412 | func (nc *networksetsController) startNetworkpolicyWatching(stopCh <-chan struct{}, s cache.SharedIndexInformer) {
413 |
414 |
415 | handlers := cache.ResourceEventHandlerFuncs{
416 | AddFunc: func(obj interface{}) {
417 |
418 | u := obj.(*unstructured.Unstructured)
419 | namespace := u.GetNamespace()
420 | //Hack for strange calico networkpolicy names
421 | np_name:=strings.Replace(u.GetName(), "default.","",1)
422 |
423 | log.Debug("create event (namespace:",namespace," np:",np_name,")")
424 | err := nc.SetupNetworksets( namespace, np_name )
425 | if err!= nil {
426 | log.Info(err)
427 | nc.metric_counter["error_counter"].Inc()
428 | }
429 |
430 | },
431 | UpdateFunc: func(oldObj, obj interface{}) {
432 |
433 | u := obj.(*unstructured.Unstructured)
434 | namespace := u.GetNamespace()
435 | //Hack for strange calico networkpolicy names
436 | np_name:=strings.Replace(u.GetName(), "default.","",1)
437 |
438 | log.Debug("update event (namespace:",namespace," np:",np_name,")")
439 | err := nc.SetupNetworksets( namespace, np_name )
440 | if err!= nil {
441 | log.Info(err)
442 | nc.metric_counter["error_counter"].Inc()
443 | }
444 |
445 |
446 | },
447 | DeleteFunc: func(obj interface{}) {
448 |
449 | u := obj.(*unstructured.Unstructured)
450 | namespace := u.GetNamespace()
451 | //Hack for strange calico networkpolicy names
452 | np_name:=strings.Replace(u.GetName(), "default.","",1)
453 |
454 | log.Debug("create event (namespace:",namespace," np:",np_name,")")
455 | err := nc.SetupNetworksets( namespace, np_name )
456 | if err!= nil {
457 | log.Info(err)
458 | nc.metric_counter["error_counter"].Inc()
459 | }
460 |
461 | },
462 | }
463 |
464 | s.AddEventHandler(handlers)
465 | s.Run(stopCh)
466 | }
467 |
468 | func (nc *networksetsController) NetworksetDef(namespace string, name string, label string, value string) (*calicoapi.NetworkSet,error) {
469 |
470 | url := nc.runtime_viper.GetString(strings.ToLower(label+".url"))
471 | if url=="" {
472 | return &calicoapi.NetworkSet{}, fmt.Errorf("Empty url for config [%s]", label)
473 | }
474 |
475 | //Get nets from source network services
476 | v := neturl.Values{}
477 | v.Add( "item", value )
478 | resp, err := http.PostForm( url, v )
479 | if err!=nil {
480 | return &calicoapi.NetworkSet{}, err
481 | }
482 | defer resp.Body.Close()
483 | decoder := json.NewDecoder(resp.Body)
484 | var nets nets_type
485 | err_get_nets := decoder.Decode(&nets)
486 | if err_get_nets != nil {
487 | return &calicoapi.NetworkSet{}, fmt.Errorf("Fail to parse response from url(%s) %s = %s - %v",url,label,value,err_get_nets)
488 | }
489 | log.Debug("Nets from api [",label,"]: ",nets)
490 | if len(nets.Nets)<1 {
491 | return &calicoapi.NetworkSet{}, fmt.Errorf("Empty nets for %s = %s",label,value)
492 | }
493 |
494 | labels := map[string]string{
495 | label: value,
496 | }
497 | return &calicoapi.NetworkSet{
498 | ObjectMeta: metav1.ObjectMeta{
499 | Name: name ,
500 | Namespace: namespace,
501 | Labels: labels,
502 | Annotations: map[string]string{
503 | "automatization/networksets-controller": "true",
504 | },
505 | },
506 | Spec: calicoapi.NetworkSetSpec{
507 | Nets: nets.Nets,
508 | },
509 | }, nil
510 | }
511 |
512 |
513 | /*
514 | GLOBAL NETWORK POLICIES
515 | */
516 |
517 | func (nc *networksetsController) ReloadGlobalNetworksets() (error) {
518 |
519 | var config_strings []string
520 | for label,_ := range nc.runtime_viper.AllSettings() {
521 | if (label != "main") {
522 | config_strings = append(config_strings, label)
523 | }
524 | }
525 | log.Debug("config strings: ",config_strings)
526 |
527 | calicoGlobalNetworksets, err := nc.calicoClient.GlobalNetworkSets().List(nc.ctx, options.ListOptions{})
528 | if err != nil {
529 | return err
530 | }
531 | normal:=make(map[string]map[string]*calicoapi.GlobalNetworkSet)
532 | for _, globalnetworkset := range calicoGlobalNetworksets.Items {
533 | if (metav1.HasAnnotation(globalnetworkset.ObjectMeta,"automatization/networksets-controller")) {
534 | meta_labels := globalnetworkset.ObjectMeta.GetLabels()
535 | for lbl, val := range meta_labels {
536 | if in_array(strings.ToLower(lbl),config_strings) {
537 |
538 | var gns *calicoapi.GlobalNetworkSet
539 | if _,ok := normal[lbl][val]; ok {
540 | gns = normal[lbl][val]
541 | } else {
542 |
543 | var gns_err error
544 | gns, gns_err = nc.GlobalNetworksetDef( globalnetworkset.ObjectMeta.GetName() , lbl, val)
545 | if gns_err != nil {
546 | log.Info(gns_err)
547 | nc.metric_counter["error_counter"].Inc()
548 | continue
549 | }
550 | normal[lbl]=map[string]*calicoapi.GlobalNetworkSet{val:gns}
551 | }
552 |
553 | sort.Strings(gns.Spec.Nets)
554 | sort.Strings(globalnetworkset.Spec.Nets)
555 | if !reflect.DeepEqual(gns.Spec.Nets,globalnetworkset.Spec.Nets) {
556 | log.Debug("Nets are not in normal state. Update global networkset ",globalnetworkset.ObjectMeta.GetName())
557 |
558 | //Update networkset
559 | gns.ObjectMeta.SetResourceVersion(globalnetworkset.ObjectMeta.GetResourceVersion())
560 | gns.ObjectMeta.SetCreationTimestamp(globalnetworkset.ObjectMeta.GetCreationTimestamp())
561 | gns.ObjectMeta.SetUID(globalnetworkset.ObjectMeta.GetUID())
562 | _, err := nc.calicoClient.GlobalNetworkSets().Update(nc.ctx, gns, options.SetOptions{})
563 | if err != nil {
564 | log.Info(err)
565 | nc.metric_counter["error_counter"].Inc()
566 | continue
567 | }
568 |
569 | } else {
570 | log.Debug("GlobalNetworkset '",globalnetworkset.ObjectMeta.GetName(),"' in normal state")
571 | }
572 |
573 |
574 |
575 | }
576 | }
577 | }
578 | }
579 | return nil
580 | }
581 |
582 |
583 | func (nc *networksetsController) GlobalNetworksetDef( name string, label string, value string) (*calicoapi.GlobalNetworkSet,error) {
584 |
585 | url := nc.runtime_viper.GetString(strings.ToLower(label+".url"))
586 | if url=="" {
587 | return &calicoapi.GlobalNetworkSet{}, fmt.Errorf("Empty url for config [%s]", label)
588 | }
589 |
590 | //Get nets from source network services
591 | v := neturl.Values{}
592 | v.Add( "item", value )
593 | resp, err := http.PostForm( url, v )
594 | if err!=nil {
595 | return &calicoapi.GlobalNetworkSet{}, err
596 | }
597 | defer resp.Body.Close()
598 | decoder := json.NewDecoder(resp.Body)
599 | var nets nets_type
600 | err_get_nets := decoder.Decode(&nets)
601 | if err_get_nets != nil {
602 | return &calicoapi.GlobalNetworkSet{}, fmt.Errorf("Fail to parse response from url(%s) %s = %s - %v",url,label,value,err_get_nets)
603 | }
604 | log.Debug("Nets from api [",label,"]: ",nets)
605 | if len(nets.Nets)<1 {
606 | return &calicoapi.GlobalNetworkSet{}, fmt.Errorf("Empty nets for %s = %s",label,value)
607 | }
608 |
609 | labels := map[string]string{
610 | label: value,
611 | }
612 | return &calicoapi.GlobalNetworkSet{
613 | ObjectMeta: metav1.ObjectMeta{
614 | Name: name ,
615 | Labels: labels,
616 | Annotations: map[string]string{
617 | "automatization/networksets-controller": "true",
618 | },
619 | },
620 | Spec: calicoapi.GlobalNetworkSetSpec{
621 | Nets: nets.Nets,
622 | },
623 | }, nil
624 | }
625 |
626 |
627 | func (nc *networksetsController) GetGlobalNetworkPolicyRuleLabels( np_name string ) ( map[string][]string, error) {
628 |
629 | //Read Network Policy
630 | out:=make(map[string][]string)
631 | np, err := nc.calicoClient.GlobalNetworkPolicies().Get(nc.ctx, np_name, options.GetOptions{})
632 | if err != nil {
633 | return out, err
634 | }
635 | for _,rule := range np.Spec.Ingress {
636 | log.Debug("Ingress selector - ", rule.Source.Selector)
637 |
638 | lbls,lblerr := nc.GetLabelsBySelector(rule.Source.Selector)
639 | if lblerr != nil {
640 | return out, lblerr
641 | }
642 | out=MergeMaps(out,lbls)
643 |
644 | lbls,lblerr = nc.GetLabelsBySelector(rule.Destination.Selector)
645 | if lblerr != nil {
646 | return out, lblerr
647 | }
648 | out=MergeMaps(out,lbls)
649 |
650 | }
651 | for _,rule := range np.Spec.Egress {
652 | log.Debug("Egress selector - ", rule.Source.Selector)
653 |
654 | lbls,lblerr := nc.GetLabelsBySelector(rule.Source.Selector)
655 | if lblerr != nil {
656 | return out, lblerr
657 | }
658 | out=MergeMaps(out,lbls)
659 |
660 | lbls,lblerr = nc.GetLabelsBySelector(rule.Destination.Selector)
661 | if lblerr != nil {
662 | return out, lblerr
663 | }
664 | out=MergeMaps(out,lbls)
665 | }
666 | log.Debug("global labels=",out)
667 | return out, nil
668 |
669 | }
670 |
671 |
672 |
673 | func (nc *networksetsController) SetupGlobalNetworksets(name string) (error) {
674 |
675 | //Collect all policy in current namespace
676 | global_rules := make(map[string][]string)
677 | calicoPolicies, err := nc.calicoClient.GlobalNetworkPolicies().List(nc.ctx, options.ListOptions{})
678 | if err != nil {
679 | return err
680 | }
681 | for _, policy := range calicoPolicies.Items {
682 |
683 | log.Debug("Find global policy: ",policy.Name)
684 | //Check rules for selector
685 | rl,err_rule:=nc.GetGlobalNetworkPolicyRuleLabels( policy.Name )
686 | if err_rule != nil {
687 | log.Info(err_rule)
688 | nc.metric_counter["error_counter"].Inc()
689 | continue
690 | }
691 | //In namespace_rules collect all label vaules
692 | global_rules = MergeMaps(global_rules,rl)
693 | }
694 | log.Debug("global rule labels = ",global_rules)
695 |
696 | //Get GlobalNetwrokSets
697 | current_globalnetworksets := make(map[string]map[string]bool)
698 | calicoGlobalNetworksets, err := nc.calicoClient.GlobalNetworkSets().List(nc.ctx, options.ListOptions{})
699 | if err != nil {
700 | return err
701 | }
702 | //Find networksets with label from configuration
703 | for _, globalnetworkset := range calicoGlobalNetworksets.Items {
704 | if (metav1.HasAnnotation(globalnetworkset.ObjectMeta,"automatization/networksets-controller")) {
705 | meta_labels := globalnetworkset.ObjectMeta.GetLabels()
706 | for lbl,lbl_slice := range global_rules {
707 | for _,val := range lbl_slice {
708 | if meta_labels[lbl] == val {
709 | log.Debug("Find global networkset ",globalnetworkset.Name," with label ",lbl," = ",val)
710 | if _,ok := current_globalnetworksets[lbl]; !ok {
711 | current_globalnetworksets[lbl] = map[string]bool{val: true}
712 | } else {
713 | current_globalnetworksets[lbl][val] = true
714 | }
715 | }
716 | }
717 | }
718 |
719 | }
720 | }
721 | log.Debug("current global networksets ",current_globalnetworksets)
722 |
723 | //Create networksets
724 | for lbl,lbl_slice := range global_rules {
725 | for _,val := range lbl_slice {
726 | if _,ok := current_globalnetworksets[lbl][val];!ok {
727 | log.Info("Create global networkset ",lbl," = ",val)
728 | re := regexp.MustCompile(`[^a-z0-9\-]`)
729 | name_ns := re.ReplaceAllString(strings.ToLower("auto-ns-"+val),"-")
730 | ns, ns_err := nc.GlobalNetworksetDef( name_ns , lbl, val)
731 | if ns_err != nil {
732 | log.Info(ns_err)
733 | nc.metric_counter["error_counter"].Inc()
734 | continue
735 | }
736 | _, err := nc.calicoClient.GlobalNetworkSets().Create(nc.ctx, ns, options.SetOptions{})
737 | if err != nil {
738 | log.Info(err)
739 | nc.metric_counter["error_counter"].Inc()
740 | continue
741 | }
742 | }
743 | }
744 | }
745 |
746 | //Delete networksets
747 | for _, globalnetworkset := range calicoGlobalNetworksets.Items {
748 | if (metav1.HasAnnotation(globalnetworkset.ObjectMeta,"automatization/networksets-controller")) {
749 | meta_labels := globalnetworkset.ObjectMeta.GetLabels()
750 | for_delete := true
751 | for del_lbl, val_lbl := range meta_labels {
752 | if v,ok := current_globalnetworksets[del_lbl][val_lbl]; ok && v {
753 | for_delete = false
754 | continue
755 | }
756 | }
757 | if for_delete {
758 | ns_name:=globalnetworkset.GetName()
759 | log.Info("Delete GlobalNetworkSet ", ns_name)
760 | _, err := nc.calicoClient.GlobalNetworkSets().Delete(nc.ctx, ns_name, options.DeleteOptions{})
761 | if err != nil {
762 | return err
763 | }
764 | }
765 | }
766 | }
767 |
768 | return nil
769 | }
770 |
771 |
772 | func (nc *networksetsController) startGlobalNetworkpolicyWatching(stopCh <-chan struct{}, s cache.SharedIndexInformer) {
773 |
774 |
775 | handlers := cache.ResourceEventHandlerFuncs{
776 | AddFunc: func(obj interface{}) {
777 |
778 | u := obj.(*unstructured.Unstructured)
779 | //Hack for strange calico networkpolicy names
780 | gnp_name:=strings.Replace(u.GetName(), "default.","",1)
781 |
782 | log.Debug("create event global network policy "," gnp:",gnp_name,")")
783 | err := nc.SetupGlobalNetworksets( gnp_name )
784 | if err!= nil {
785 | log.Info(err)
786 | nc.metric_counter["error_counter"].Inc()
787 | }
788 |
789 | },
790 | UpdateFunc: func(oldObj, obj interface{}) {
791 |
792 | u := obj.(*unstructured.Unstructured)
793 | //Hack for strange calico networkpolicy names
794 | gnp_name:=strings.Replace(u.GetName(), "default.","",1)
795 |
796 | log.Debug("create event global network policy "," gnp:",gnp_name,")")
797 | err := nc.SetupGlobalNetworksets( gnp_name )
798 | if err!= nil {
799 | log.Info(err)
800 | nc.metric_counter["error_counter"].Inc()
801 | }
802 |
803 |
804 | },
805 | DeleteFunc: func(obj interface{}) {
806 |
807 | u := obj.(*unstructured.Unstructured)
808 | //Hack for strange calico networkpolicy names
809 | gnp_name:=strings.Replace(u.GetName(), "default.","",1)
810 |
811 | log.Debug("create event global network policy "," gnp:",gnp_name,")")
812 | err := nc.SetupGlobalNetworksets( gnp_name )
813 | if err!= nil {
814 | log.Info(err)
815 | nc.metric_counter["error_counter"].Inc()
816 | }
817 |
818 | },
819 | }
820 |
821 | s.AddEventHandler(handlers)
822 | s.Run(stopCh)
823 | }
824 |
825 |
826 |
827 |
828 | func (nc *networksetsController) Init() (error){
829 |
830 | nc.runtime_viper = viper.New()
831 | nc.runtime_viper.SetConfigName("networksets-controller")
832 | nc.runtime_viper.AddConfigPath("/config-k8s")
833 | nc.runtime_viper.WatchConfig()
834 | err := nc.runtime_viper.ReadInConfig()
835 | if err != nil {
836 | fmt.Printf("Fatal error config file: %s \n", err)
837 | return err
838 | }
839 |
840 | //Get clients for calico and k8s
841 | var err_calico error
842 | nc.clientset, nc.calicoClient, err_calico = nc.getClients("")
843 | if err_calico != nil {
844 | return err_calico
845 | }
846 |
847 | nc.ctx = context.Background()
848 |
849 | is_debug := nc.runtime_viper.GetBool("main.debug")
850 | if is_debug {
851 | log.SetLevel(log.DebugLevel)
852 | }
853 |
854 | //Prometheus metrics
855 | nc.metric_counter = make(map[string]prometheus.Counter)
856 |
857 | nc.metric_counter["error_counter"] = promauto.NewCounter(prometheus.CounterOpts{
858 | Name: "networksets_controller_errors",
859 | Help: "Count of errors",
860 | })
861 |
862 |
863 | go nc.run()
864 |
865 | reload_time := nc.runtime_viper.GetDuration("main.reload_time")
866 | ticker := time.NewTicker(time.Millisecond * reload_time)
867 | go func() {
868 | for _ = range ticker.C {
869 | err_reload := nc.ReloadNetworksets()
870 | if err_reload != nil {
871 | log.Info(err_reload)
872 | nc.metric_counter["error_counter"].Inc()
873 | }
874 | }
875 | }()
876 |
877 | globalticker := time.NewTicker(time.Millisecond * reload_time)
878 | go func() {
879 | for _ = range globalticker.C {
880 | err_reload := nc.ReloadGlobalNetworksets()
881 | if err_reload != nil {
882 | log.Info(err_reload)
883 | nc.metric_counter["error_counter"].Inc()
884 | }
885 | }
886 | }()
887 |
888 | return nil
889 | }
890 |
891 | func main() {
892 |
893 |
894 | var nc networksetsController
895 | err:=nc.Init()
896 | if err!=nil {
897 | log.Info("Fail to start networksets controller", err)
898 | return
899 | }
900 |
901 | http.Handle("/metrics", promhttp.Handler())
902 |
903 | service_port := nc.runtime_viper.GetString("main.service_port")
904 |
905 | log.Fatal(http.ListenAndServe(":"+service_port, nil))
906 | }
907 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/projectcalico/libcalico-go/v3
2 |
3 | go 1.15
4 |
5 | require (
6 | github.com/banzaicloud/k8s-objectmatcher v1.5.0 // indirect
7 | github.com/ghodss/yaml v1.0.0 // indirect
8 | github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627
9 | github.com/projectcalico/kube-controllers v3.8.9+incompatible
10 | github.com/projectcalico/libcalico-go v1.7.2-0.20201211095255-5d3be5f39c7c
11 | github.com/prometheus/client_golang v1.9.0
12 | github.com/sirupsen/logrus v1.6.0
13 | github.com/spf13/viper v1.7.1 // indirect
14 | k8s.io/api v0.20.1
15 | k8s.io/apimachinery v0.20.1
16 | k8s.io/apiserver v0.20.1
17 | k8s.io/client-go v0.20.1
18 | )
19 |
--------------------------------------------------------------------------------
/k8s-mainfest.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: networksets-controller
5 | namespace: calico-networksets-controller
6 | data:
7 | networksets-controller.toml: |
8 | [main]
9 | reload_time=60000
10 | debug=false
11 | service_port=8080
12 | [DNS_RESOLVER]
13 | url="http://dns-resolver.calico-networksets-controller:8080/dns"
14 | ---
15 | apiVersion: v1
16 | kind: Secret
17 | metadata:
18 | annotations:
19 | kubernetes.io/service-account.name: calico-networksets-controller
20 | name: calico-networksets-controller-token
21 | namespace: calico-networksets-controller
22 | type: kubernetes.io/service-account-token
23 | ---
24 | apiVersion: v1
25 | kind: ServiceAccount
26 | metadata:
27 | name: calico-networksets-controller
28 | namespace: calico-networksets-controller
29 | labels:
30 | vault: secret
31 | ---
32 | apiVersion: rbac.authorization.k8s.io/v1
33 | kind: ClusterRole
34 | metadata:
35 | labels:
36 | app: calico-networksets-controller
37 | name: calico-networksets-controller
38 | rules:
39 | - apiGroups: ["crd.projectcalico.org"]
40 | resources:
41 | - networksets
42 | - globalnetworksets
43 | verbs:
44 | - get
45 | - list
46 | - watch
47 | - create
48 | - update
49 | - patch
50 | - delete
51 | - apiGroups: ["networking.k8s.io","crd.projectcalico.org"]
52 | resources:
53 | - networkpolicies
54 | - globalnetworkpolicies
55 | verbs:
56 | - get
57 | - list
58 | - watch
59 | ---
60 | apiVersion: rbac.authorization.k8s.io/v1
61 | kind: ClusterRoleBinding
62 | metadata:
63 | name: calico-networksets-controller
64 | roleRef:
65 | apiGroup: rbac.authorization.k8s.io
66 | kind: ClusterRole
67 | name: calico-networksets-controller
68 | subjects:
69 | - kind: ServiceAccount
70 | name: calico-networksets-controller
71 | namespace: calico-networksets-controller
72 | ---
73 | apiVersion: apps/v1
74 | kind: Deployment
75 | metadata:
76 | name: calico-networksets-controller
77 | namespace: calico-networksets-controller
78 | spec:
79 | selector:
80 | matchLabels:
81 | app: calico-networksets-controller
82 | replicas: 1
83 | template:
84 | metadata:
85 | labels:
86 | app: calico-networksets-controller
87 | spec:
88 | volumes:
89 | - name: networksets-controller
90 | configMap:
91 | name: networksets-controller
92 | items:
93 | - key: networksets-controller.toml
94 | path: networksets-controller.toml
95 | containers:
96 | - name: calico-networksets-controller
97 | image: ktrufanov/k8s-calico-networksets-controller:0.0.11
98 | env:
99 | - name: SERVICE_PORT
100 | value: "8080"
101 | imagePullPolicy: Always
102 | volumeMounts:
103 | - name: networksets-controller
104 | mountPath: /config-k8s
105 | ports:
106 | - name: http
107 | containerPort: 8080
108 | ---
109 | apiVersion: v1
110 | kind: Service
111 | metadata:
112 | name: calico-networksets-controller
113 | namespace: calico-networksets-controller
114 | labels:
115 | app: calico-networksets-controller
116 | spec:
117 | ports:
118 | - port: 8080
119 | targetPort: http
120 | protocol: TCP
121 | name: http
122 | selector:
123 | app: calico-networksets-controller
124 |
--------------------------------------------------------------------------------