1
0
mirror of https://github.com/rancher/types.git synced 2026-05-07 03:57:05 +00:00

Update vendor

This commit is contained in:
Darren Shepherd
2020-05-16 22:04:28 -07:00
parent 02e11aeb41
commit 8d8abc899c
368 changed files with 11643 additions and 22381 deletions

9
go.mod
View File

@@ -11,10 +11,11 @@ replace (
require (
github.com/coreos/prometheus-operator v0.36.0
github.com/knative/pkg v0.0.0-20190817231834-12ee58e32cc8
github.com/pkg/errors v0.8.1
github.com/rancher/norman v0.0.0-20200326201949-eb806263e8ad
github.com/rancher/wrangler v0.5.4-0.20200326191509-4054411d9736
github.com/rancher/wrangler-api v0.5.1-0.20200326194427-c13310506d04
github.com/pkg/errors v0.9.1
github.com/rancher/lasso v0.0.0-20200515155337-a34e1e26ad91
github.com/rancher/norman v0.0.0-20200517050325-f53cae161640
github.com/rancher/wrangler v0.6.2-0.20200515155908-1923f3f8ec3f
github.com/rancher/wrangler-api v0.6.1-0.20200515193802-dcf70881b087
github.com/sirupsen/logrus v1.4.2
k8s.io/api v0.18.0
k8s.io/apiextensions-apiserver v0.18.0

28
go.sum
View File

@@ -143,11 +143,13 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@@ -288,8 +290,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
@@ -345,8 +345,10 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
@@ -458,12 +460,15 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw=
github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@@ -480,6 +485,8 @@ github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -526,16 +533,18 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
github.com/prometheus/prometheus v1.8.2-0.20200107122003-4708915ac6ef/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI=
github.com/prometheus/prometheus v2.3.2+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
github.com/rancher/lasso v0.0.0-20200515155337-a34e1e26ad91 h1:p4VVl0tr6YAeUILFMCn+0DKzbUOS0ah9biSsL7Sy6S4=
github.com/rancher/lasso v0.0.0-20200515155337-a34e1e26ad91/go.mod h1:G6Vv2aj6xB2YjTVagmu4NkhBvbE8nBcGykHRENH6arI=
github.com/rancher/moq v0.0.0-20190404221404-ee5226d43009 h1:Xsxh7fX3+2wAUJtPy8g2lZh0cYuyifqhBL0vxCIYojs=
github.com/rancher/moq v0.0.0-20190404221404-ee5226d43009/go.mod h1:wpITyDPTi/Na5h73XkbuEf2AP9fbgrIGqqxVzFhYD6U=
github.com/rancher/norman v0.0.0-20200326201949-eb806263e8ad h1:Ha6G8j9yfKrvJQeKmPpNzyloJ+98GuD4a3zMwASlgbs=
github.com/rancher/norman v0.0.0-20200326201949-eb806263e8ad/go.mod h1:g72A7RbW+GCqXicpQumVjmyHz2tP9AiiuRGRm+Ewnyo=
github.com/rancher/norman v0.0.0-20200517050325-f53cae161640 h1:wZT4IWBeMfKewJ+ZSCuOFjHh+voTJWYQo7jTd/ZtE90=
github.com/rancher/norman v0.0.0-20200517050325-f53cae161640/go.mod h1:92rz/7QN7DOeLQZlJY/8aFBOmF085igIVguR0wpxLas=
github.com/rancher/pkg v0.0.0-20190514055449-b30ab9de040e h1:j6+HqCET/NLPBtew2m5apL7jWw/PStQ7iGwXjgAqdvo=
github.com/rancher/pkg v0.0.0-20190514055449-b30ab9de040e/go.mod h1:XbYHTPaXuw8ZY9bylhYKQh/nJxDaTKk3YhAxPl4Qy/k=
github.com/rancher/wrangler v0.5.4-0.20200326191509-4054411d9736 h1:hqpVLgNUxU5sQUV6SzJPMY8Fy7T9Qht2QkA2Q7O/SH0=
github.com/rancher/wrangler v0.5.4-0.20200326191509-4054411d9736/go.mod h1:L4HtjPeX8iqLgsxfJgz+JjKMcX2q3qbRXSeTlC/CSd4=
github.com/rancher/wrangler-api v0.5.1-0.20200326194427-c13310506d04 h1:y55e+kUaz/UswjN/oJdqHWMuoCG1FxwZJkxJEUONZZE=
github.com/rancher/wrangler-api v0.5.1-0.20200326194427-c13310506d04/go.mod h1:R3nemXoECcrDqXDSHdY7yJay4j42TeEkU79Hep0rdJ8=
github.com/rancher/wrangler v0.6.2-0.20200515155908-1923f3f8ec3f h1:QPOlhiY3YCPLsEtOmPam+ghtqip/f/zsfz4F4PF70D8=
github.com/rancher/wrangler v0.6.2-0.20200515155908-1923f3f8ec3f/go.mod h1:NmtmlLkchboIksYJuBemwcP4RBfv8FpeyhVoWXB9Wdc=
github.com/rancher/wrangler-api v0.6.1-0.20200515193802-dcf70881b087 h1:+hiZFORh4fMvRSg5SIClz4y6nD5wkKLAdtPzjxyeHgs=
github.com/rancher/wrangler-api v0.6.1-0.20200515193802-dcf70881b087/go.mod h1:s95VCVHV19b+EUo7BAwwe6nhaDx2/lHu91hxxDHbZs0=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -858,6 +867,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
@@ -868,6 +878,7 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.1.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -930,6 +941,7 @@ k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4y
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM=
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6 h1:p0Ai3qVtkbCG/Af26dBmU0E1W58NID3hSSh7cMyylpM=

16
vendor/github.com/evanphx/json-patch/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,16 @@
language: go
go:
- 1.8
- 1.7
install:
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
- go get github.com/jessevdk/go-flags
script:
- go get
- go test -cover ./...
notifications:
email: false

25
vendor/github.com/evanphx/json-patch/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,25 @@
Copyright (c) 2014, Evan Phoenix
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the Evan Phoenix nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

297
vendor/github.com/evanphx/json-patch/README.md generated vendored Normal file
View File

@@ -0,0 +1,297 @@
# JSON-Patch
`jsonpatch` is a library which provides functionallity for both applying
[RFC6902 JSON patches](http://tools.ietf.org/html/rfc6902) against documents, as
well as for calculating & applying [RFC7396 JSON merge patches](https://tools.ietf.org/html/rfc7396).
[![GoDoc](https://godoc.org/github.com/evanphx/json-patch?status.svg)](http://godoc.org/github.com/evanphx/json-patch)
[![Build Status](https://travis-ci.org/evanphx/json-patch.svg?branch=master)](https://travis-ci.org/evanphx/json-patch)
[![Report Card](https://goreportcard.com/badge/github.com/evanphx/json-patch)](https://goreportcard.com/report/github.com/evanphx/json-patch)
# Get It!
**Latest and greatest**:
```bash
go get -u github.com/evanphx/json-patch
```
**Stable Versions**:
* Version 4: `go get -u gopkg.in/evanphx/json-patch.v4`
(previous versions below `v3` are unavailable)
# Use It!
* [Create and apply a merge patch](#create-and-apply-a-merge-patch)
* [Create and apply a JSON Patch](#create-and-apply-a-json-patch)
* [Comparing JSON documents](#comparing-json-documents)
* [Combine merge patches](#combine-merge-patches)
# Configuration
* There is a global configuration variable `jsonpatch.SupportNegativeIndices`.
This defaults to `true` and enables the non-standard practice of allowing
negative indices to mean indices starting at the end of an array. This
functionality can be disabled by setting `jsonpatch.SupportNegativeIndices =
false`.
* There is a global configuration variable `jsonpatch.AccumulatedCopySizeLimit`,
which limits the total size increase in bytes caused by "copy" operations in a
patch. It defaults to 0, which means there is no limit.
## Create and apply a merge patch
Given both an original JSON document and a modified JSON document, you can create
a [Merge Patch](https://tools.ietf.org/html/rfc7396) document.
It can describe the changes needed to convert from the original to the
modified JSON document.
Once you have a merge patch, you can apply it to other JSON documents using the
`jsonpatch.MergePatch(document, patch)` function.
```go
package main
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
)
func main() {
// Let's create a merge patch from these two documents...
original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
target := []byte(`{"name": "Jane", "age": 24}`)
patch, err := jsonpatch.CreateMergePatch(original, target)
if err != nil {
panic(err)
}
// Now lets apply the patch against a different JSON document...
alternative := []byte(`{"name": "Tina", "age": 28, "height": 3.75}`)
modifiedAlternative, err := jsonpatch.MergePatch(alternative, patch)
fmt.Printf("patch document: %s\n", patch)
fmt.Printf("updated alternative doc: %s\n", modifiedAlternative)
}
```
When ran, you get the following output:
```bash
$ go run main.go
patch document: {"height":null,"name":"Jane"}
updated tina doc: {"age":28,"name":"Jane"}
```
## Create and apply a JSON Patch
You can create patch objects using `DecodePatch([]byte)`, which can then
be applied against JSON documents.
The following is an example of creating a patch from two operations, and
applying it against a JSON document.
```go
package main
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
)
func main() {
original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
patchJSON := []byte(`[
{"op": "replace", "path": "/name", "value": "Jane"},
{"op": "remove", "path": "/height"}
]`)
patch, err := jsonpatch.DecodePatch(patchJSON)
if err != nil {
panic(err)
}
modified, err := patch.Apply(original)
if err != nil {
panic(err)
}
fmt.Printf("Original document: %s\n", original)
fmt.Printf("Modified document: %s\n", modified)
}
```
When ran, you get the following output:
```bash
$ go run main.go
Original document: {"name": "John", "age": 24, "height": 3.21}
Modified document: {"age":24,"name":"Jane"}
```
## Comparing JSON documents
Due to potential whitespace and ordering differences, one cannot simply compare
JSON strings or byte-arrays directly.
As such, you can instead use `jsonpatch.Equal(document1, document2)` to
determine if two JSON documents are _structurally_ equal. This ignores
whitespace differences, and key-value ordering.
```go
package main
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
)
func main() {
original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
similar := []byte(`
{
"age": 24,
"height": 3.21,
"name": "John"
}
`)
different := []byte(`{"name": "Jane", "age": 20, "height": 3.37}`)
if jsonpatch.Equal(original, similar) {
fmt.Println(`"original" is structurally equal to "similar"`)
}
if !jsonpatch.Equal(original, different) {
fmt.Println(`"original" is _not_ structurally equal to "similar"`)
}
}
```
When ran, you get the following output:
```bash
$ go run main.go
"original" is structurally equal to "similar"
"original" is _not_ structurally equal to "similar"
```
## Combine merge patches
Given two JSON merge patch documents, it is possible to combine them into a
single merge patch which can describe both set of changes.
The resulting merge patch can be used such that applying it results in a
document structurally similar as merging each merge patch to the document
in succession.
```go
package main
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
)
func main() {
original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
nameAndHeight := []byte(`{"height":null,"name":"Jane"}`)
ageAndEyes := []byte(`{"age":4.23,"eyes":"blue"}`)
// Let's combine these merge patch documents...
combinedPatch, err := jsonpatch.MergeMergePatches(nameAndHeight, ageAndEyes)
if err != nil {
panic(err)
}
// Apply each patch individual against the original document
withoutCombinedPatch, err := jsonpatch.MergePatch(original, nameAndHeight)
if err != nil {
panic(err)
}
withoutCombinedPatch, err = jsonpatch.MergePatch(withoutCombinedPatch, ageAndEyes)
if err != nil {
panic(err)
}
// Apply the combined patch against the original document
withCombinedPatch, err := jsonpatch.MergePatch(original, combinedPatch)
if err != nil {
panic(err)
}
// Do both result in the same thing? They should!
if jsonpatch.Equal(withCombinedPatch, withoutCombinedPatch) {
fmt.Println("Both JSON documents are structurally the same!")
}
fmt.Printf("combined merge patch: %s", combinedPatch)
}
```
When ran, you get the following output:
```bash
$ go run main.go
Both JSON documents are structurally the same!
combined merge patch: {"age":4.23,"eyes":"blue","height":null,"name":"Jane"}
```
# CLI for comparing JSON documents
You can install the commandline program `json-patch`.
This program can take multiple JSON patch documents as arguments,
and fed a JSON document from `stdin`. It will apply the patch(es) against
the document and output the modified doc.
**patch.1.json**
```json
[
{"op": "replace", "path": "/name", "value": "Jane"},
{"op": "remove", "path": "/height"}
]
```
**patch.2.json**
```json
[
{"op": "add", "path": "/address", "value": "123 Main St"},
{"op": "replace", "path": "/age", "value": "21"}
]
```
**document.json**
```json
{
"name": "John",
"age": 24,
"height": 3.21
}
```
You can then run:
```bash
$ go install github.com/evanphx/json-patch/cmd/json-patch
$ cat document.json | json-patch -p patch.1.json -p patch.2.json
{"address":"123 Main St","age":"21","name":"Jane"}
```
# Help It!
Contributions are welcomed! Leave [an issue](https://github.com/evanphx/json-patch/issues)
or [create a PR](https://github.com/evanphx/json-patch/compare).
Before creating a pull request, we'd ask that you make sure tests are passing
and that you have added new tests when applicable.
Contributors can run tests using:
```bash
go test -cover ./...
```
Builds for pull requests are tested automatically
using [TravisCI](https://travis-ci.org/evanphx/json-patch).

38
vendor/github.com/evanphx/json-patch/errors.go generated vendored Normal file
View File

@@ -0,0 +1,38 @@
package jsonpatch
import "fmt"
// AccumulatedCopySizeError is an error type returned when the accumulated size
// increase caused by copy operations in a patch operation has exceeded the
// limit.
type AccumulatedCopySizeError struct {
limit int64
accumulated int64
}
// NewAccumulatedCopySizeError returns an AccumulatedCopySizeError.
func NewAccumulatedCopySizeError(l, a int64) *AccumulatedCopySizeError {
return &AccumulatedCopySizeError{limit: l, accumulated: a}
}
// Error implements the error interface.
func (a *AccumulatedCopySizeError) Error() string {
return fmt.Sprintf("Unable to complete the copy, the accumulated size increase of copy is %d, exceeding the limit %d", a.accumulated, a.limit)
}
// ArraySizeError is an error type returned when the array size has exceeded
// the limit.
type ArraySizeError struct {
limit int
size int
}
// NewArraySizeError returns an ArraySizeError.
func NewArraySizeError(l, s int) *ArraySizeError {
return &ArraySizeError{limit: l, size: s}
}
// Error implements the error interface.
func (a *ArraySizeError) Error() string {
return fmt.Sprintf("Unable to create array of size %d, limit is %d", a.size, a.limit)
}

383
vendor/github.com/evanphx/json-patch/merge.go generated vendored Normal file
View File

@@ -0,0 +1,383 @@
package jsonpatch
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
)
func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode {
curDoc, err := cur.intoDoc()
if err != nil {
pruneNulls(patch)
return patch
}
patchDoc, err := patch.intoDoc()
if err != nil {
return patch
}
mergeDocs(curDoc, patchDoc, mergeMerge)
return cur
}
func mergeDocs(doc, patch *partialDoc, mergeMerge bool) {
for k, v := range *patch {
if v == nil {
if mergeMerge {
(*doc)[k] = nil
} else {
delete(*doc, k)
}
} else {
cur, ok := (*doc)[k]
if !ok || cur == nil {
pruneNulls(v)
(*doc)[k] = v
} else {
(*doc)[k] = merge(cur, v, mergeMerge)
}
}
}
}
func pruneNulls(n *lazyNode) {
sub, err := n.intoDoc()
if err == nil {
pruneDocNulls(sub)
} else {
ary, err := n.intoAry()
if err == nil {
pruneAryNulls(ary)
}
}
}
func pruneDocNulls(doc *partialDoc) *partialDoc {
for k, v := range *doc {
if v == nil {
delete(*doc, k)
} else {
pruneNulls(v)
}
}
return doc
}
func pruneAryNulls(ary *partialArray) *partialArray {
newAry := []*lazyNode{}
for _, v := range *ary {
if v != nil {
pruneNulls(v)
newAry = append(newAry, v)
}
}
*ary = newAry
return ary
}
var errBadJSONDoc = fmt.Errorf("Invalid JSON Document")
var errBadJSONPatch = fmt.Errorf("Invalid JSON Patch")
var errBadMergeTypes = fmt.Errorf("Mismatched JSON Documents")
// MergeMergePatches merges two merge patches together, such that
// applying this resulting merged merge patch to a document yields the same
// as merging each merge patch to the document in succession.
func MergeMergePatches(patch1Data, patch2Data []byte) ([]byte, error) {
return doMergePatch(patch1Data, patch2Data, true)
}
// MergePatch merges the patchData into the docData.
func MergePatch(docData, patchData []byte) ([]byte, error) {
return doMergePatch(docData, patchData, false)
}
func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) {
doc := &partialDoc{}
docErr := json.Unmarshal(docData, doc)
patch := &partialDoc{}
patchErr := json.Unmarshal(patchData, patch)
if _, ok := docErr.(*json.SyntaxError); ok {
return nil, errBadJSONDoc
}
if _, ok := patchErr.(*json.SyntaxError); ok {
return nil, errBadJSONPatch
}
if docErr == nil && *doc == nil {
return nil, errBadJSONDoc
}
if patchErr == nil && *patch == nil {
return nil, errBadJSONPatch
}
if docErr != nil || patchErr != nil {
// Not an error, just not a doc, so we turn straight into the patch
if patchErr == nil {
if mergeMerge {
doc = patch
} else {
doc = pruneDocNulls(patch)
}
} else {
patchAry := &partialArray{}
patchErr = json.Unmarshal(patchData, patchAry)
if patchErr != nil {
return nil, errBadJSONPatch
}
pruneAryNulls(patchAry)
out, patchErr := json.Marshal(patchAry)
if patchErr != nil {
return nil, errBadJSONPatch
}
return out, nil
}
} else {
mergeDocs(doc, patch, mergeMerge)
}
return json.Marshal(doc)
}
// resemblesJSONArray indicates whether the byte-slice "appears" to be
// a JSON array or not.
// False-positives are possible, as this function does not check the internal
// structure of the array. It only checks that the outer syntax is present and
// correct.
func resemblesJSONArray(input []byte) bool {
input = bytes.TrimSpace(input)
hasPrefix := bytes.HasPrefix(input, []byte("["))
hasSuffix := bytes.HasSuffix(input, []byte("]"))
return hasPrefix && hasSuffix
}
// CreateMergePatch will return a merge patch document capable of converting
// the original document(s) to the modified document(s).
// The parameters can be bytes of either two JSON Documents, or two arrays of
// JSON documents.
// The merge patch returned follows the specification defined at http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch-07
func CreateMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
originalResemblesArray := resemblesJSONArray(originalJSON)
modifiedResemblesArray := resemblesJSONArray(modifiedJSON)
// Do both byte-slices seem like JSON arrays?
if originalResemblesArray && modifiedResemblesArray {
return createArrayMergePatch(originalJSON, modifiedJSON)
}
// Are both byte-slices are not arrays? Then they are likely JSON objects...
if !originalResemblesArray && !modifiedResemblesArray {
return createObjectMergePatch(originalJSON, modifiedJSON)
}
// None of the above? Then return an error because of mismatched types.
return nil, errBadMergeTypes
}
// createObjectMergePatch will return a merge-patch document capable of
// converting the original document to the modified document.
func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
originalDoc := map[string]interface{}{}
modifiedDoc := map[string]interface{}{}
err := json.Unmarshal(originalJSON, &originalDoc)
if err != nil {
return nil, errBadJSONDoc
}
err = json.Unmarshal(modifiedJSON, &modifiedDoc)
if err != nil {
return nil, errBadJSONDoc
}
dest, err := getDiff(originalDoc, modifiedDoc)
if err != nil {
return nil, err
}
return json.Marshal(dest)
}
// createArrayMergePatch will return an array of merge-patch documents capable
// of converting the original document to the modified document for each
// pair of JSON documents provided in the arrays.
// Arrays of mismatched sizes will result in an error.
func createArrayMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
originalDocs := []json.RawMessage{}
modifiedDocs := []json.RawMessage{}
err := json.Unmarshal(originalJSON, &originalDocs)
if err != nil {
return nil, errBadJSONDoc
}
err = json.Unmarshal(modifiedJSON, &modifiedDocs)
if err != nil {
return nil, errBadJSONDoc
}
total := len(originalDocs)
if len(modifiedDocs) != total {
return nil, errBadJSONDoc
}
result := []json.RawMessage{}
for i := 0; i < len(originalDocs); i++ {
original := originalDocs[i]
modified := modifiedDocs[i]
patch, err := createObjectMergePatch(original, modified)
if err != nil {
return nil, err
}
result = append(result, json.RawMessage(patch))
}
return json.Marshal(result)
}
// Returns true if the array matches (must be json types).
// As is idiomatic for go, an empty array is not the same as a nil array.
func matchesArray(a, b []interface{}) bool {
if len(a) != len(b) {
return false
}
if (a == nil && b != nil) || (a != nil && b == nil) {
return false
}
for i := range a {
if !matchesValue(a[i], b[i]) {
return false
}
}
return true
}
// Returns true if the values matches (must be json types)
// The types of the values must match, otherwise it will always return false
// If two map[string]interface{} are given, all elements must match.
func matchesValue(av, bv interface{}) bool {
if reflect.TypeOf(av) != reflect.TypeOf(bv) {
return false
}
switch at := av.(type) {
case string:
bt := bv.(string)
if bt == at {
return true
}
case float64:
bt := bv.(float64)
if bt == at {
return true
}
case bool:
bt := bv.(bool)
if bt == at {
return true
}
case nil:
// Both nil, fine.
return true
case map[string]interface{}:
bt := bv.(map[string]interface{})
for key := range at {
if !matchesValue(at[key], bt[key]) {
return false
}
}
for key := range bt {
if !matchesValue(at[key], bt[key]) {
return false
}
}
return true
case []interface{}:
bt := bv.([]interface{})
return matchesArray(at, bt)
}
return false
}
// getDiff returns the (recursive) difference between a and b as a map[string]interface{}.
func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) {
into := map[string]interface{}{}
for key, bv := range b {
av, ok := a[key]
// value was added
if !ok {
into[key] = bv
continue
}
// If types have changed, replace completely
if reflect.TypeOf(av) != reflect.TypeOf(bv) {
into[key] = bv
continue
}
// Types are the same, compare values
switch at := av.(type) {
case map[string]interface{}:
bt := bv.(map[string]interface{})
dst := make(map[string]interface{}, len(bt))
dst, err := getDiff(at, bt)
if err != nil {
return nil, err
}
if len(dst) > 0 {
into[key] = dst
}
case string, float64, bool:
if !matchesValue(av, bv) {
into[key] = bv
}
case []interface{}:
bt := bv.([]interface{})
if !matchesArray(at, bt) {
into[key] = bv
}
case nil:
switch bv.(type) {
case nil:
// Both nil, fine.
default:
into[key] = bv
}
default:
panic(fmt.Sprintf("Unknown type:%T in key %s", av, key))
}
}
// Now add all deleted values as nil
for key := range a {
_, found := b[key]
if !found {
into[key] = nil
}
}
return into, nil
}

776
vendor/github.com/evanphx/json-patch/patch.go generated vendored Normal file
View File

@@ -0,0 +1,776 @@
package jsonpatch
import (
"bytes"
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/pkg/errors"
)
const (
eRaw = iota
eDoc
eAry
)
var (
// SupportNegativeIndices decides whether to support non-standard practice of
// allowing negative indices to mean indices starting at the end of an array.
// Default to true.
SupportNegativeIndices bool = true
// AccumulatedCopySizeLimit limits the total size increase in bytes caused by
// "copy" operations in a patch.
AccumulatedCopySizeLimit int64 = 0
)
var (
ErrTestFailed = errors.New("test failed")
ErrMissing = errors.New("missing value")
ErrUnknownType = errors.New("unknown object type")
ErrInvalid = errors.New("invalid state detected")
ErrInvalidIndex = errors.New("invalid index referenced")
)
type lazyNode struct {
raw *json.RawMessage
doc partialDoc
ary partialArray
which int
}
// Operation is a single JSON-Patch step, such as a single 'add' operation.
type Operation map[string]*json.RawMessage
// Patch is an ordered collection of Operations.
type Patch []Operation
type partialDoc map[string]*lazyNode
type partialArray []*lazyNode
type container interface {
get(key string) (*lazyNode, error)
set(key string, val *lazyNode) error
add(key string, val *lazyNode) error
remove(key string) error
}
func newLazyNode(raw *json.RawMessage) *lazyNode {
return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
}
func (n *lazyNode) MarshalJSON() ([]byte, error) {
switch n.which {
case eRaw:
return json.Marshal(n.raw)
case eDoc:
return json.Marshal(n.doc)
case eAry:
return json.Marshal(n.ary)
default:
return nil, ErrUnknownType
}
}
func (n *lazyNode) UnmarshalJSON(data []byte) error {
dest := make(json.RawMessage, len(data))
copy(dest, data)
n.raw = &dest
n.which = eRaw
return nil
}
func deepCopy(src *lazyNode) (*lazyNode, int, error) {
if src == nil {
return nil, 0, nil
}
a, err := src.MarshalJSON()
if err != nil {
return nil, 0, err
}
sz := len(a)
ra := make(json.RawMessage, sz)
copy(ra, a)
return newLazyNode(&ra), sz, nil
}
func (n *lazyNode) intoDoc() (*partialDoc, error) {
if n.which == eDoc {
return &n.doc, nil
}
if n.raw == nil {
return nil, ErrInvalid
}
err := json.Unmarshal(*n.raw, &n.doc)
if err != nil {
return nil, err
}
n.which = eDoc
return &n.doc, nil
}
func (n *lazyNode) intoAry() (*partialArray, error) {
if n.which == eAry {
return &n.ary, nil
}
if n.raw == nil {
return nil, ErrInvalid
}
err := json.Unmarshal(*n.raw, &n.ary)
if err != nil {
return nil, err
}
n.which = eAry
return &n.ary, nil
}
func (n *lazyNode) compact() []byte {
buf := &bytes.Buffer{}
if n.raw == nil {
return nil
}
err := json.Compact(buf, *n.raw)
if err != nil {
return *n.raw
}
return buf.Bytes()
}
func (n *lazyNode) tryDoc() bool {
if n.raw == nil {
return false
}
err := json.Unmarshal(*n.raw, &n.doc)
if err != nil {
return false
}
n.which = eDoc
return true
}
func (n *lazyNode) tryAry() bool {
if n.raw == nil {
return false
}
err := json.Unmarshal(*n.raw, &n.ary)
if err != nil {
return false
}
n.which = eAry
return true
}
func (n *lazyNode) equal(o *lazyNode) bool {
if n.which == eRaw {
if !n.tryDoc() && !n.tryAry() {
if o.which != eRaw {
return false
}
return bytes.Equal(n.compact(), o.compact())
}
}
if n.which == eDoc {
if o.which == eRaw {
if !o.tryDoc() {
return false
}
}
if o.which != eDoc {
return false
}
for k, v := range n.doc {
ov, ok := o.doc[k]
if !ok {
return false
}
if v == nil && ov == nil {
continue
}
if !v.equal(ov) {
return false
}
}
return true
}
if o.which != eAry && !o.tryAry() {
return false
}
if len(n.ary) != len(o.ary) {
return false
}
for idx, val := range n.ary {
if !val.equal(o.ary[idx]) {
return false
}
}
return true
}
// Kind reads the "op" field of the Operation.
func (o Operation) Kind() string {
if obj, ok := o["op"]; ok && obj != nil {
var op string
err := json.Unmarshal(*obj, &op)
if err != nil {
return "unknown"
}
return op
}
return "unknown"
}
// Path reads the "path" field of the Operation.
func (o Operation) Path() (string, error) {
if obj, ok := o["path"]; ok && obj != nil {
var op string
err := json.Unmarshal(*obj, &op)
if err != nil {
return "unknown", err
}
return op, nil
}
return "unknown", errors.Wrapf(ErrMissing, "operation missing path field")
}
// From reads the "from" field of the Operation.
func (o Operation) From() (string, error) {
if obj, ok := o["from"]; ok && obj != nil {
var op string
err := json.Unmarshal(*obj, &op)
if err != nil {
return "unknown", err
}
return op, nil
}
return "unknown", errors.Wrapf(ErrMissing, "operation, missing from field")
}
func (o Operation) value() *lazyNode {
if obj, ok := o["value"]; ok {
return newLazyNode(obj)
}
return nil
}
// ValueInterface decodes the operation value into an interface.
func (o Operation) ValueInterface() (interface{}, error) {
if obj, ok := o["value"]; ok && obj != nil {
var v interface{}
err := json.Unmarshal(*obj, &v)
if err != nil {
return nil, err
}
return v, nil
}
return nil, errors.Wrapf(ErrMissing, "operation, missing value field")
}
func isArray(buf []byte) bool {
Loop:
for _, c := range buf {
switch c {
case ' ':
case '\n':
case '\t':
continue
case '[':
return true
default:
break Loop
}
}
return false
}
func findObject(pd *container, path string) (container, string) {
doc := *pd
split := strings.Split(path, "/")
if len(split) < 2 {
return nil, ""
}
parts := split[1 : len(split)-1]
key := split[len(split)-1]
var err error
for _, part := range parts {
next, ok := doc.get(decodePatchKey(part))
if next == nil || ok != nil {
return nil, ""
}
if isArray(*next.raw) {
doc, err = next.intoAry()
if err != nil {
return nil, ""
}
} else {
doc, err = next.intoDoc()
if err != nil {
return nil, ""
}
}
}
return doc, decodePatchKey(key)
}
func (d *partialDoc) set(key string, val *lazyNode) error {
(*d)[key] = val
return nil
}
func (d *partialDoc) add(key string, val *lazyNode) error {
(*d)[key] = val
return nil
}
func (d *partialDoc) get(key string) (*lazyNode, error) {
return (*d)[key], nil
}
func (d *partialDoc) remove(key string) error {
_, ok := (*d)[key]
if !ok {
return errors.Wrapf(ErrMissing, "Unable to remove nonexistent key: %s", key)
}
delete(*d, key)
return nil
}
// set should only be used to implement the "replace" operation, so "key" must
// be an already existing index in "d".
func (d *partialArray) set(key string, val *lazyNode) error {
idx, err := strconv.Atoi(key)
if err != nil {
return err
}
(*d)[idx] = val
return nil
}
func (d *partialArray) add(key string, val *lazyNode) error {
if key == "-" {
*d = append(*d, val)
return nil
}
idx, err := strconv.Atoi(key)
if err != nil {
return errors.Wrapf(err, "value was not a proper array index: '%s'", key)
}
sz := len(*d) + 1
ary := make([]*lazyNode, sz)
cur := *d
if idx >= len(ary) {
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
if SupportNegativeIndices {
if idx < -len(ary) {
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
if idx < 0 {
idx += len(ary)
}
}
copy(ary[0:idx], cur[0:idx])
ary[idx] = val
copy(ary[idx+1:], cur[idx:])
*d = ary
return nil
}
func (d *partialArray) get(key string) (*lazyNode, error) {
idx, err := strconv.Atoi(key)
if err != nil {
return nil, err
}
if idx >= len(*d) {
return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
return (*d)[idx], nil
}
func (d *partialArray) remove(key string) error {
idx, err := strconv.Atoi(key)
if err != nil {
return err
}
cur := *d
if idx >= len(cur) {
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
if SupportNegativeIndices {
if idx < -len(cur) {
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
if idx < 0 {
idx += len(cur)
}
}
ary := make([]*lazyNode, len(cur)-1)
copy(ary[0:idx], cur[0:idx])
copy(ary[idx:], cur[idx+1:])
*d = ary
return nil
}
func (p Patch) add(doc *container, op Operation) error {
path, err := op.Path()
if err != nil {
return errors.Wrapf(ErrMissing, "add operation failed to decode path")
}
con, key := findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "add operation does not apply: doc is missing path: \"%s\"", path)
}
err = con.add(key, op.value())
if err != nil {
return errors.Wrapf(err, "error in add for path: '%s'", path)
}
return nil
}
func (p Patch) remove(doc *container, op Operation) error {
path, err := op.Path()
if err != nil {
return errors.Wrapf(ErrMissing, "remove operation failed to decode path")
}
con, key := findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "remove operation does not apply: doc is missing path: \"%s\"", path)
}
err = con.remove(key)
if err != nil {
return errors.Wrapf(err, "error in remove for path: '%s'", path)
}
return nil
}
func (p Patch) replace(doc *container, op Operation) error {
path, err := op.Path()
if err != nil {
return errors.Wrapf(err, "replace operation failed to decode path")
}
con, key := findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing path: %s", path)
}
_, ok := con.get(key)
if ok != nil {
return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing key: %s", path)
}
err = con.set(key, op.value())
if err != nil {
return errors.Wrapf(err, "error in remove for path: '%s'", path)
}
return nil
}
func (p Patch) move(doc *container, op Operation) error {
from, err := op.From()
if err != nil {
return errors.Wrapf(err, "move operation failed to decode from")
}
con, key := findObject(doc, from)
if con == nil {
return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing from path: %s", from)
}
val, err := con.get(key)
if err != nil {
return errors.Wrapf(err, "error in move for path: '%s'", key)
}
err = con.remove(key)
if err != nil {
return errors.Wrapf(err, "error in move for path: '%s'", key)
}
path, err := op.Path()
if err != nil {
return errors.Wrapf(err, "move operation failed to decode path")
}
con, key = findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing destination path: %s", path)
}
err = con.add(key, val)
if err != nil {
return errors.Wrapf(err, "error in move for path: '%s'", path)
}
return nil
}
func (p Patch) test(doc *container, op Operation) error {
path, err := op.Path()
if err != nil {
return errors.Wrapf(err, "test operation failed to decode path")
}
con, key := findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "test operation does not apply: is missing path: %s", path)
}
val, err := con.get(key)
if err != nil {
return errors.Wrapf(err, "error in test for path: '%s'", path)
}
if val == nil {
if op.value().raw == nil {
return nil
}
return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
} else if op.value() == nil {
return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
}
if val.equal(op.value()) {
return nil
}
return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
}
func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) error {
from, err := op.From()
if err != nil {
return errors.Wrapf(err, "copy operation failed to decode from")
}
con, key := findObject(doc, from)
if con == nil {
return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing from path: %s", from)
}
val, err := con.get(key)
if err != nil {
return errors.Wrapf(err, "error in copy for from: '%s'", from)
}
path, err := op.Path()
if err != nil {
return errors.Wrapf(ErrMissing, "copy operation failed to decode path")
}
con, key = findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing destination path: %s", path)
}
valCopy, sz, err := deepCopy(val)
if err != nil {
return errors.Wrapf(err, "error while performing deep copy")
}
(*accumulatedCopySize) += int64(sz)
if AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > AccumulatedCopySizeLimit {
return NewAccumulatedCopySizeError(AccumulatedCopySizeLimit, *accumulatedCopySize)
}
err = con.add(key, valCopy)
if err != nil {
return errors.Wrapf(err, "error while adding value during copy")
}
return nil
}
// Equal indicates if 2 JSON documents have the same structural equality.
func Equal(a, b []byte) bool {
ra := make(json.RawMessage, len(a))
copy(ra, a)
la := newLazyNode(&ra)
rb := make(json.RawMessage, len(b))
copy(rb, b)
lb := newLazyNode(&rb)
return la.equal(lb)
}
// DecodePatch decodes the passed JSON document as an RFC 6902 patch.
func DecodePatch(buf []byte) (Patch, error) {
var p Patch
err := json.Unmarshal(buf, &p)
if err != nil {
return nil, err
}
return p, nil
}
// Apply mutates a JSON document according to the patch, and returns the new
// document.
func (p Patch) Apply(doc []byte) ([]byte, error) {
return p.ApplyIndent(doc, "")
}
// ApplyIndent mutates a JSON document according to the patch, and returns the new
// document indented.
func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
var pd container
if doc[0] == '[' {
pd = &partialArray{}
} else {
pd = &partialDoc{}
}
err := json.Unmarshal(doc, pd)
if err != nil {
return nil, err
}
err = nil
var accumulatedCopySize int64
for _, op := range p {
switch op.Kind() {
case "add":
err = p.add(&pd, op)
case "remove":
err = p.remove(&pd, op)
case "replace":
err = p.replace(&pd, op)
case "move":
err = p.move(&pd, op)
case "test":
err = p.test(&pd, op)
case "copy":
err = p.copy(&pd, op, &accumulatedCopySize)
default:
err = fmt.Errorf("Unexpected kind: %s", op.Kind())
}
if err != nil {
return nil, err
}
}
if indent != "" {
return json.MarshalIndent(pd, "", indent)
}
return json.Marshal(pd)
}
// From http://tools.ietf.org/html/rfc6901#section-4 :
//
// Evaluation of each reference token begins by decoding any escaped
// character sequence. This is performed by first transforming any
// occurrence of the sequence '~1' to '/', and then transforming any
// occurrence of the sequence '~0' to '~'.
var (
rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
)
func decodePatchKey(k string) string {
return rfc6901Decoder.Replace(k)
}

View File

@@ -1,15 +1,10 @@
language: go
go_import_path: github.com/pkg/errors
go:
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- 1.13.x
- tip
script:
- go test -v ./...
- make check

44
vendor/github.com/pkg/errors/Makefile generated vendored Normal file
View File

@@ -0,0 +1,44 @@
PKGS := github.com/pkg/errors
SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
GO := go
check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
test:
$(GO) test $(PKGS)
vet: | test
$(GO) vet $(PKGS)
staticcheck:
$(GO) get honnef.co/go/tools/cmd/staticcheck
staticcheck -checks all $(PKGS)
misspell:
$(GO) get github.com/client9/misspell/cmd/misspell
misspell \
-locale GB \
-error \
*.md *.go
unconvert:
$(GO) get github.com/mdempsky/unconvert
unconvert -v $(PKGS)
ineffassign:
$(GO) get github.com/gordonklaus/ineffassign
find $(SRCDIRS) -name '*.go' | xargs ineffassign
pedantic: check errcheck
unparam:
$(GO) get mvdan.cc/unparam
unparam ./...
errcheck:
$(GO) get github.com/kisielk/errcheck
errcheck $(PKGS)
gofmt:
@echo Checking code is gofmted
@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"

View File

@@ -41,11 +41,18 @@ default:
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Roadmap
With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
- 1.0. Final release.
## Contributing
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
Before proposing a change, please discuss your change by raising an issue.
Before sending a PR, please discuss your change by raising an issue.
## License

View File

@@ -82,7 +82,7 @@
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d", f)
// fmt.Printf("%+s:%d\n", f, f)
// }
// }
//
@@ -159,6 +159,9 @@ type withStack struct {
func (w *withStack) Cause() error { return w.error }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withStack) Unwrap() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
@@ -241,6 +244,9 @@ type withMessage struct {
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withMessage) Unwrap() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':

38
vendor/github.com/pkg/errors/go113.go generated vendored Normal file
View File

@@ -0,0 +1,38 @@
// +build go1.13
package errors
import (
stderrors "errors"
)
// Is reports whether any error in err's chain matches target.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error is considered to match a target if it is equal to that target or if
// it implements a method Is(error) bool such that Is(target) returns true.
func Is(err, target error) bool { return stderrors.Is(err, target) }
// As finds the first error in err's chain that matches target, and if so, sets
// target to that error value and returns true.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error matches target if the error's concrete value is assignable to the value
// pointed to by target, or if the error has a method As(interface{}) bool such that
// As(target) returns true. In the latter case, the As method is responsible for
// setting target.
//
// As will panic if target is not a non-nil pointer to either a type that implements
// error, or to any interface type. As returns false if err is nil.
func As(err error, target interface{}) bool { return stderrors.As(err, target) }
// Unwrap returns the result of calling the Unwrap method on err, if err's
// type contains an Unwrap method returning error.
// Otherwise, Unwrap returns nil.
func Unwrap(err error) error {
return stderrors.Unwrap(err)
}

View File

@@ -5,10 +5,13 @@ import (
"io"
"path"
"runtime"
"strconv"
"strings"
)
// Frame represents a program counter inside a stack frame.
// For historical reasons if Frame is interpreted as a uintptr
// its value represents the program counter + 1.
type Frame uintptr
// pc returns the program counter for this frame;
@@ -37,6 +40,15 @@ func (f Frame) line() int {
return line
}
// name returns the name of this function, if known.
func (f Frame) name() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
return fn.Name()
}
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
@@ -54,22 +66,16 @@ func (f Frame) Format(s fmt.State, verb rune) {
case 's':
switch {
case s.Flag('+'):
pc := f.pc()
fn := runtime.FuncForPC(pc)
if fn == nil {
io.WriteString(s, "unknown")
} else {
file, _ := fn.FileLine(pc)
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
}
io.WriteString(s, f.name())
io.WriteString(s, "\n\t")
io.WriteString(s, f.file())
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
fmt.Fprintf(s, "%d", f.line())
io.WriteString(s, strconv.Itoa(f.line()))
case 'n':
name := runtime.FuncForPC(f.pc()).Name()
io.WriteString(s, funcname(name))
io.WriteString(s, funcname(f.name()))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
@@ -77,6 +83,16 @@ func (f Frame) Format(s fmt.State, verb rune) {
}
}
// MarshalText formats a stacktrace Frame as a text string. The output is the
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
func (f Frame) MarshalText() ([]byte, error) {
name := f.name()
if name == "unknown" {
return []byte(name), nil
}
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
@@ -94,18 +110,32 @@ func (st StackTrace) Format(s fmt.State, verb rune) {
switch {
case s.Flag('+'):
for _, f := range st {
fmt.Fprintf(s, "\n%+v", f)
io.WriteString(s, "\n")
f.Format(s, verb)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
fmt.Fprintf(s, "%v", []Frame(st))
st.formatSlice(s, verb)
}
case 's':
fmt.Fprintf(s, "%s", []Frame(st))
st.formatSlice(s, verb)
}
}
// formatSlice will format this StackTrace into the given buffer as a slice of
// Frame, only valid when called with '%s' or '%v'.
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
io.WriteString(s, "[")
for i, f := range st {
if i > 0 {
io.WriteString(s, " ")
}
f.Format(s, verb)
}
io.WriteString(s, "]")
}
// stack represents a stack of program counters.
type stack []uintptr

178
vendor/github.com/rancher/lasso/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,178 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

113
vendor/github.com/rancher/lasso/pkg/cache/cache.go generated vendored Normal file
View File

@@ -0,0 +1,113 @@
package cache
import (
"context"
"fmt"
"time"
"github.com/rancher/lasso/pkg/client"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/tools/cache"
)
type Options struct {
Namespace string
Resync time.Duration
TweakList TweakListOptionsFunc
}
func NewCache(obj, listObj runtime.Object, client *client.Client, opts *Options) cache.SharedIndexInformer {
indexers := cache.Indexers{}
if client.Namespaced {
indexers[cache.NamespaceIndex] = cache.MetaNamespaceIndexFunc
}
opts = applyDefaultCacheOptions(opts)
lw := &deferredListWatcher{
client: client,
tweakList: opts.TweakList,
namespace: opts.Namespace,
listObj: listObj,
}
return &deferredCache{
SharedIndexInformer: cache.NewSharedIndexInformer(
lw,
obj,
opts.Resync,
indexers,
),
deferredListWatcher: lw,
}
}
func applyDefaultCacheOptions(opts *Options) *Options {
var newOpts Options
if opts != nil {
newOpts = *opts
}
if newOpts.Resync == 0 {
newOpts.Resync = 10 * time.Hour
}
if newOpts.TweakList == nil {
newOpts.TweakList = func(*metav1.ListOptions) {}
}
return &newOpts
}
type deferredCache struct {
cache.SharedIndexInformer
deferredListWatcher *deferredListWatcher
}
type deferredListWatcher struct {
lw cache.ListerWatcher
client *client.Client
tweakList TweakListOptionsFunc
namespace string
listObj runtime.Object
}
func (d *deferredListWatcher) List(options metav1.ListOptions) (runtime.Object, error) {
if d.lw == nil {
return nil, fmt.Errorf("cache not started")
}
return d.lw.List(options)
}
func (d *deferredListWatcher) Watch(options metav1.ListOptions) (watch.Interface, error) {
if d.lw == nil {
return nil, fmt.Errorf("cache not started")
}
return d.lw.Watch(options)
}
func (d *deferredListWatcher) run(stopCh <-chan struct{}) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-stopCh
cancel()
}()
d.lw = &cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
d.tweakList(&options)
listObj := d.listObj.DeepCopyObject()
err := d.client.List(ctx, d.namespace, listObj, options)
return listObj, err
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
d.tweakList(&options)
return d.client.Watch(ctx, d.namespace, options)
},
}
}
func (d *deferredCache) Run(stopCh <-chan struct{}) {
d.deferredListWatcher.run(stopCh)
d.SharedIndexInformer.Run(stopCh)
}

View File

@@ -0,0 +1,208 @@
package cache
import (
"context"
"sync"
"time"
"github.com/rancher/lasso/pkg/client"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/tools/cache"
)
type TweakListOptionsFunc func(*v1.ListOptions)
type SharedCacheFactoryOptions struct {
DefaultResync time.Duration
DefaultNamespace string
DefaultTweakList TweakListOptionsFunc
KindResync map[schema.GroupVersionKind]time.Duration
KindNamespace map[schema.GroupVersionKind]string
KindTweakList map[schema.GroupVersionKind]TweakListOptionsFunc
}
type sharedCacheFactory struct {
lock sync.Mutex
tweakList TweakListOptionsFunc
defaultResync time.Duration
defaultNamespace string
customResync map[schema.GroupVersionKind]time.Duration
customNamespaces map[schema.GroupVersionKind]string
customTweakList map[schema.GroupVersionKind]TweakListOptionsFunc
sharedClientFactory client.SharedClientFactory
caches map[schema.GroupVersionKind]cache.SharedIndexInformer
startedCaches map[schema.GroupVersionKind]bool
}
// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options.
func NewSharedCachedFactory(sharedClientFactory client.SharedClientFactory, opts *SharedCacheFactoryOptions) SharedCacheFactory {
opts = applyDefaults(opts)
factory := &sharedCacheFactory{
lock: sync.Mutex{},
tweakList: opts.DefaultTweakList,
defaultResync: opts.DefaultResync,
defaultNamespace: opts.DefaultNamespace,
customResync: opts.KindResync,
customNamespaces: opts.KindNamespace,
customTweakList: opts.KindTweakList,
caches: map[schema.GroupVersionKind]cache.SharedIndexInformer{},
startedCaches: map[schema.GroupVersionKind]bool{},
sharedClientFactory: sharedClientFactory,
}
return factory
}
func applyDefaults(opts *SharedCacheFactoryOptions) *SharedCacheFactoryOptions {
var newOpts SharedCacheFactoryOptions
if opts != nil {
newOpts = *opts
}
return &newOpts
}
func (f *sharedCacheFactory) StartGVK(ctx context.Context, gvk schema.GroupVersionKind) error {
f.lock.Lock()
defer f.lock.Unlock()
informer, ok := f.caches[gvk]
if !ok {
return nil
}
if !f.startedCaches[gvk] {
go informer.Run(ctx.Done())
f.startedCaches[gvk] = true
}
return nil
}
func (f *sharedCacheFactory) Start(ctx context.Context) error {
f.lock.Lock()
defer f.lock.Unlock()
for informerType, informer := range f.caches {
if !f.startedCaches[informerType] {
go informer.Run(ctx.Done())
f.startedCaches[informerType] = true
}
}
return nil
}
func (f *sharedCacheFactory) WaitForCacheSync(ctx context.Context) map[schema.GroupVersionKind]bool {
informers := func() map[schema.GroupVersionKind]cache.SharedIndexInformer {
f.lock.Lock()
defer f.lock.Unlock()
informers := map[schema.GroupVersionKind]cache.SharedIndexInformer{}
for informerType, informer := range f.caches {
if f.startedCaches[informerType] {
informers[informerType] = informer
}
}
return informers
}()
res := map[schema.GroupVersionKind]bool{}
for informType, informer := range informers {
res[informType] = cache.WaitForCacheSync(ctx.Done(), informer.HasSynced)
}
return res
}
func (f *sharedCacheFactory) ForObject(obj runtime.Object) (cache.SharedIndexInformer, error) {
return f.ForKind(obj.GetObjectKind().GroupVersionKind())
}
func (f *sharedCacheFactory) ForResource(gvr schema.GroupVersionResource, namespaced bool) (cache.SharedIndexInformer, error) {
return f.ForResourceKind(gvr, "", namespaced)
}
func (f *sharedCacheFactory) ForKind(gvk schema.GroupVersionKind) (cache.SharedIndexInformer, error) {
gvr, namespaced, err := f.sharedClientFactory.ResourceForGVK(gvk)
if err != nil {
return nil, err
}
return f.ForResourceKind(gvr, gvk.Kind, namespaced)
}
func (f *sharedCacheFactory) ForResourceKind(gvr schema.GroupVersionResource, kind string, namespaced bool) (cache.SharedIndexInformer, error) {
var (
gvk schema.GroupVersionKind
err error
)
if kind == "" {
gvk, err = f.sharedClientFactory.GVKForResource(gvr)
if err != nil {
return nil, err
}
} else {
gvk = gvr.GroupVersion().WithKind(kind)
}
f.lock.Lock()
defer f.lock.Unlock()
informer, ok := f.caches[gvk]
if ok {
return informer, nil
}
resyncPeriod, ok := f.customResync[gvk]
if !ok {
resyncPeriod = f.defaultResync
}
namespace, ok := f.customNamespaces[gvk]
if !ok {
namespace = f.defaultNamespace
}
tweakList, ok := f.customTweakList[gvk]
if !ok {
tweakList = f.tweakList
}
obj, objList, err := f.sharedClientFactory.NewObjects(gvk)
if err != nil {
return nil, err
}
client := f.sharedClientFactory.ForResourceKind(gvr, kind, namespaced)
cache := NewCache(obj, objList, client, &Options{
Namespace: namespace,
Resync: resyncPeriod,
TweakList: tweakList,
})
f.caches[gvk] = cache
return cache, nil
}
func (f *sharedCacheFactory) SharedClientFactory() client.SharedClientFactory {
return f.sharedClientFactory
}
type SharedCacheFactory interface {
Start(ctx context.Context) error
StartGVK(ctx context.Context, gvk schema.GroupVersionKind) error
ForObject(obj runtime.Object) (cache.SharedIndexInformer, error)
ForKind(gvk schema.GroupVersionKind) (cache.SharedIndexInformer, error)
ForResource(gvr schema.GroupVersionResource, namespaced bool) (cache.SharedIndexInformer, error)
ForResourceKind(gvr schema.GroupVersionResource, kind string, namespaced bool) (cache.SharedIndexInformer, error)
WaitForCacheSync(ctx context.Context) map[schema.GroupVersionKind]bool
SharedClientFactory() client.SharedClientFactory
}

280
vendor/github.com/rancher/lasso/pkg/client/client.go generated vendored Normal file
View File

@@ -0,0 +1,280 @@
package client
import (
"context"
"time"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/rest"
)
type Client struct {
RESTClient rest.Interface
timeout time.Duration
Namespaced bool
GVR schema.GroupVersionResource
resource string
prefix []string
apiVersion string
kind string
}
func IsNamespaced(gvr schema.GroupVersionResource, mapper meta.RESTMapper) (bool, error) {
kind, err := mapper.KindFor(gvr)
if err != nil {
return false, err
}
mapping, err := mapper.RESTMapping(kind.GroupKind(), kind.Version)
if err != nil {
return false, err
}
return mapping.Scope.Name() == meta.RESTScopeNameNamespace, nil
}
func NewClient(gvr schema.GroupVersionResource, kind string, namespaced bool, client rest.Interface, defaultTimeout time.Duration) *Client {
var (
prefix []string
)
if gvr.Group == "" {
prefix = []string{
"api",
gvr.Version,
}
} else {
prefix = []string{
"apis",
gvr.Group,
gvr.Version,
}
}
c := &Client{
RESTClient: client,
timeout: defaultTimeout,
Namespaced: namespaced,
GVR: gvr,
prefix: prefix,
resource: gvr.Resource,
}
c.apiVersion, c.kind = gvr.GroupVersion().WithKind(kind).ToAPIVersionAndKind()
return c
}
func noop() {}
func (c *Client) setupCtx(ctx context.Context, minTimeout time.Duration) (context.Context, func()) {
if minTimeout == 0 && c.timeout == 0 {
return ctx, noop
}
timeout := c.timeout
if minTimeout > 0 && timeout < minTimeout {
timeout = minTimeout
}
return context.WithTimeout(ctx, timeout)
}
func (c *Client) Get(ctx context.Context, namespace, name string, result runtime.Object, options metav1.GetOptions) (err error) {
defer c.setKind(result)
ctx, cancel := c.setupCtx(ctx, 0)
defer cancel()
err = c.RESTClient.Get().
Prefix(c.prefix...).
NamespaceIfScoped(namespace, c.Namespaced).
Resource(c.resource).
Name(name).
VersionedParams(&options, metav1.ParameterCodec).
Do(ctx).
Into(result)
return
}
func (c *Client) List(ctx context.Context, namespace string, result runtime.Object, opts metav1.ListOptions) (err error) {
ctx, cancel := c.setupCtx(ctx, 0)
defer cancel()
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
r := c.RESTClient.Get()
if namespace != "" {
r = r.NamespaceIfScoped(namespace, c.Namespaced)
}
err = r.Resource(c.resource).
Prefix(c.prefix...).
VersionedParams(&opts, metav1.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
func (c *Client) Watch(ctx context.Context, namespace string, opts metav1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.injectKind(c.RESTClient.Get().
Prefix(c.prefix...).
NamespaceIfScoped(namespace, c.Namespaced).
Resource(c.resource).
VersionedParams(&opts, metav1.ParameterCodec).
Timeout(timeout).
Watch(ctx))
}
func (c *Client) Create(ctx context.Context, namespace string, obj, result runtime.Object, opts metav1.CreateOptions) (err error) {
defer c.setKind(result)
ctx, cancel := c.setupCtx(ctx, 0)
defer cancel()
err = c.RESTClient.Post().
Prefix(c.prefix...).
NamespaceIfScoped(namespace, c.Namespaced).
Resource(c.resource).
VersionedParams(&opts, metav1.ParameterCodec).
Body(obj).
Do(ctx).
Into(result)
return
}
func (c *Client) Update(ctx context.Context, namespace string, obj, result runtime.Object, opts metav1.UpdateOptions) (err error) {
defer c.setKind(result)
ctx, cancel := c.setupCtx(ctx, 0)
defer cancel()
m, err := meta.Accessor(obj)
if err != nil {
return err
}
err = c.RESTClient.Put().
Prefix(c.prefix...).
NamespaceIfScoped(namespace, c.Namespaced).
Resource(c.resource).
Name(m.GetName()).
VersionedParams(&opts, metav1.ParameterCodec).
Body(obj).
Do(ctx).
Into(result)
return
}
func (c *Client) UpdateStatus(ctx context.Context, namespace string, obj, result runtime.Object, opts metav1.UpdateOptions) (err error) {
defer c.setKind(result)
ctx, cancel := c.setupCtx(ctx, 0)
defer cancel()
m, err := meta.Accessor(obj)
if err != nil {
return err
}
err = c.RESTClient.Put().
Prefix(c.prefix...).
NamespaceIfScoped(namespace, c.Namespaced).
Resource(c.resource).
Name(m.GetName()).
SubResource("status").
VersionedParams(&opts, metav1.ParameterCodec).
Body(obj).
Do(ctx).
Into(result)
return
}
func (c *Client) Delete(ctx context.Context, namespace, name string, opts metav1.DeleteOptions) error {
ctx, cancel := c.setupCtx(ctx, 0)
defer cancel()
return c.RESTClient.Delete().
Prefix(c.prefix...).
NamespaceIfScoped(namespace, c.Namespaced).
Resource(c.resource).
Name(name).
Body(&opts).
Do(ctx).
Error()
}
func (c *Client) DeleteCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
ctx, cancel := c.setupCtx(ctx, 0)
defer cancel()
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.RESTClient.Delete().
Prefix(c.prefix...).
NamespaceIfScoped(namespace, c.Namespaced).
Resource(c.resource).
VersionedParams(&listOpts, metav1.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
func (c *Client) Patch(ctx context.Context, namespace, name string, pt types.PatchType, data []byte, result runtime.Object, opts metav1.PatchOptions, subresources ...string) (err error) {
defer c.setKind(result)
ctx, cancel := c.setupCtx(ctx, 0)
defer cancel()
err = c.RESTClient.Patch(pt).
Prefix(c.prefix...).
Namespace(namespace).
Resource(c.resource).
Name(name).
SubResource(subresources...).
VersionedParams(&opts, metav1.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}
func (c *Client) setKind(obj runtime.Object) {
if c.kind == "" {
return
}
if _, ok := obj.(*metav1.Status); !ok {
if meta, err := meta.TypeAccessor(obj); err == nil {
meta.SetKind(c.kind)
meta.SetAPIVersion(c.apiVersion)
}
}
}
func (c *Client) injectKind(w watch.Interface, err error) (watch.Interface, error) {
if c.kind == "" || err != nil {
return w, err
}
eventChan := make(chan watch.Event)
go func() {
defer close(eventChan)
for event := range w.ResultChan() {
c.setKind(event.Object)
eventChan <- event
}
}()
return &watcher{
Interface: w,
eventChan: eventChan,
}, nil
}
type watcher struct {
watch.Interface
eventChan chan watch.Event
}
func (w *watcher) ResultChan() <-chan watch.Event {
return w.eventChan
}

View File

@@ -0,0 +1,183 @@
package client
import (
"fmt"
"sync"
"time"
"github.com/rancher/lasso/pkg/mapper"
"github.com/rancher/lasso/pkg/scheme"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/rest"
)
type SharedClientFactoryOptions struct {
Mapper meta.RESTMapper
Scheme *runtime.Scheme
}
type SharedClientFactory interface {
ForKind(gvk schema.GroupVersionKind) (*Client, error)
ForResource(gvr schema.GroupVersionResource, namespaced bool) (*Client, error)
ForResourceKind(gvr schema.GroupVersionResource, kind string, namespaced bool) *Client
NewObjects(gvk schema.GroupVersionKind) (runtime.Object, runtime.Object, error)
GVKForObject(obj runtime.Object) (schema.GroupVersionKind, error)
GVKForResource(gvr schema.GroupVersionResource) (schema.GroupVersionKind, error)
ResourceForGVK(gvk schema.GroupVersionKind) (schema.GroupVersionResource, bool, error)
}
type sharedClientFactory struct {
createLock sync.RWMutex
clients map[schema.GroupVersionResource]*Client
timeout time.Duration
rest rest.Interface
Mapper meta.RESTMapper
Scheme *runtime.Scheme
}
func NewSharedClientFactoryForConfig(config *rest.Config) (SharedClientFactory, error) {
return NewSharedClientFactory(config, nil)
}
func NewSharedClientFactory(config *rest.Config, opts *SharedClientFactoryOptions) (_ SharedClientFactory, err error) {
opts, err = applyDefaults(config, opts)
if err != nil {
return nil, err
}
config, timeout := populateConfig(opts.Scheme, config)
rest, err := rest.UnversionedRESTClientFor(config)
if err != nil {
return nil, err
}
return &sharedClientFactory{
timeout: timeout,
clients: map[schema.GroupVersionResource]*Client{},
Scheme: opts.Scheme,
Mapper: opts.Mapper,
rest: rest,
}, nil
}
func applyDefaults(config *rest.Config, opts *SharedClientFactoryOptions) (*SharedClientFactoryOptions, error) {
var newOpts SharedClientFactoryOptions
if opts != nil {
newOpts = *opts
}
if newOpts.Scheme == nil {
newOpts.Scheme = scheme.All
}
if newOpts.Mapper == nil {
mapperOpt, err := mapper.New(config)
if err != nil {
return nil, err
}
newOpts.Mapper = mapperOpt
}
return &newOpts, nil
}
func (s *sharedClientFactory) GVKForResource(gvr schema.GroupVersionResource) (schema.GroupVersionKind, error) {
return s.Mapper.KindFor(gvr)
}
func (s *sharedClientFactory) ResourceForGVK(gvk schema.GroupVersionKind) (schema.GroupVersionResource, bool, error) {
mapping, err := s.Mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return schema.GroupVersionResource{}, false, err
}
nsed, err := IsNamespaced(mapping.Resource, s.Mapper)
if err != nil {
return schema.GroupVersionResource{}, false, err
}
return mapping.Resource, nsed, nil
}
func (s *sharedClientFactory) GVKForObject(obj runtime.Object) (schema.GroupVersionKind, error) {
gvks, _, err := s.Scheme.ObjectKinds(obj)
if err != nil {
return schema.GroupVersionKind{}, err
}
if len(gvks) == 0 {
return schema.GroupVersionKind{}, fmt.Errorf("failed to find schema.GroupVersionKind for %T", obj)
}
return gvks[0], nil
}
func (s *sharedClientFactory) NewObjects(gvk schema.GroupVersionKind) (runtime.Object, runtime.Object, error) {
obj, err := s.Scheme.New(gvk)
if err != nil {
return nil, nil, err
}
objList, err := s.Scheme.New(schema.GroupVersionKind{
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind + "List",
})
return obj, objList, err
}
func (s *sharedClientFactory) ForKind(gvk schema.GroupVersionKind) (*Client, error) {
gvr, nsed, err := s.ResourceForGVK(gvk)
if err != nil {
return nil, err
}
return s.ForResourceKind(gvr, gvk.Kind, nsed), nil
}
func (s *sharedClientFactory) ForResource(gvr schema.GroupVersionResource, namespaced bool) (*Client, error) {
gvk, err := s.GVKForResource(gvr)
if err != nil {
return nil, err
}
return s.ForResourceKind(gvr, gvk.Kind, namespaced), nil
}
func (s *sharedClientFactory) ForResourceKind(gvr schema.GroupVersionResource, kind string, namespaced bool) *Client {
client := s.getClient(gvr)
if client != nil {
return client
}
s.createLock.Lock()
defer s.createLock.Unlock()
client = s.clients[gvr]
if client != nil {
return client
}
client = NewClient(gvr, kind, namespaced, s.rest, s.timeout)
s.clients[gvr] = client
return client
}
func (s *sharedClientFactory) getClient(gvr schema.GroupVersionResource) *Client {
s.createLock.RLock()
defer s.createLock.RUnlock()
return s.clients[gvr]
}
func populateConfig(scheme *runtime.Scheme, config *rest.Config) (*rest.Config, time.Duration) {
config = rest.CopyConfig(config)
config.NegotiatedSerializer = serializer.NewCodecFactory(scheme).WithoutConversion()
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
timeout := config.Timeout
config.Timeout = 0
return config, timeout
}

View File

@@ -0,0 +1,288 @@
package controller
import (
"context"
"fmt"
"strings"
"sync"
"time"
"github.com/rancher/lasso/pkg/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
type Handler interface {
OnChange(key string, obj runtime.Object) error
}
type HandlerFunc func(key string, obj runtime.Object) error
func (h HandlerFunc) OnChange(key string, obj runtime.Object) error {
return h(key, obj)
}
type Controller interface {
Enqueue(namespace, name string)
EnqueueAfter(namespace, name string, delay time.Duration)
EnqueueKey(key string)
Informer() cache.SharedIndexInformer
Start(ctx context.Context, workers int) error
}
type controller struct {
startLock sync.Mutex
name string
workqueue workqueue.RateLimitingInterface
rateLimiter workqueue.RateLimiter
informer cache.SharedIndexInformer
handler Handler
gvk schema.GroupVersionKind
startKeys []startKey
started bool
startCache func(context.Context) error
}
type startKey struct {
key string
after time.Duration
}
type Options struct {
RateLimiter workqueue.RateLimiter
}
func New(name string, informer cache.SharedIndexInformer, startCache func(context.Context) error, handler Handler, opts *Options) Controller {
opts = applyDefaultOptions(opts)
controller := &controller{
name: name,
handler: handler,
informer: informer,
rateLimiter: opts.RateLimiter,
startCache: startCache,
}
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: controller.handleObject,
UpdateFunc: func(old, new interface{}) {
controller.handleObject(new)
},
DeleteFunc: controller.handleObject,
})
return controller
}
func applyDefaultOptions(opts *Options) *Options {
var newOpts Options
if opts != nil {
newOpts = *opts
}
if newOpts.RateLimiter == nil {
newOpts.RateLimiter = workqueue.DefaultControllerRateLimiter()
}
return &newOpts
}
func (c *controller) Informer() cache.SharedIndexInformer {
return c.informer
}
func (c *controller) GroupVersionKind() schema.GroupVersionKind {
return c.gvk
}
func (c *controller) run(workers int, stopCh <-chan struct{}) {
c.startLock.Lock()
// we have to defer queue creation until we have a stopCh available because a workqueue
// will create a goroutine under the hood. It we instantiate a workqueue we must have
// a mechanism to Shutdown it down. Without the stopCh we don't know when to shutdown
// the queue and release the goroutine
c.workqueue = workqueue.NewNamedRateLimitingQueue(c.rateLimiter, c.name)
for _, start := range c.startKeys {
if start.after == 0 {
c.workqueue.Add(start.key)
} else {
c.workqueue.AddAfter(start.key, start.after)
}
}
c.startKeys = nil
c.startLock.Unlock()
defer utilruntime.HandleCrash()
defer func() {
c.workqueue.ShutDown()
c.workqueue = nil
}()
// Start the informer factories to begin populating the informer caches
log.Infof("Starting %s controller", c.name)
// Launch two workers to process Foo resources
for i := 0; i < workers; i++ {
go wait.Until(c.runWorker, time.Second, stopCh)
}
<-stopCh
log.Infof("Shutting down %s workers", c.name)
}
func (c *controller) Start(ctx context.Context, workers int) error {
c.startLock.Lock()
defer c.startLock.Unlock()
if c.started {
return nil
}
if err := c.startCache(ctx); err != nil {
return err
}
if ok := cache.WaitForCacheSync(ctx.Done(), c.informer.HasSynced); !ok {
return fmt.Errorf("failed to wait for caches to sync")
}
go c.run(workers, ctx.Done())
c.started = true
return nil
}
func (c *controller) runWorker() {
for c.processNextWorkItem() {
}
}
func (c *controller) processNextWorkItem() bool {
obj, shutdown := c.workqueue.Get()
if shutdown {
return false
}
if err := c.processSingleItem(obj); err != nil {
if !strings.Contains(err.Error(), "please apply your changes to the latest version and try again") {
log.Errorf("%v", err)
}
return true
}
return true
}
func (c *controller) processSingleItem(obj interface{}) error {
var (
key string
ok bool
)
defer c.workqueue.Done(obj)
if key, ok = obj.(string); !ok {
c.workqueue.Forget(obj)
log.Errorf("expected string in workqueue but got %#v", obj)
return nil
}
if err := c.syncHandler(key); err != nil {
c.workqueue.AddRateLimited(key)
return fmt.Errorf("error syncing '%s': %s, requeuing", key, err.Error())
}
c.workqueue.Forget(obj)
return nil
}
func (c *controller) syncHandler(key string) error {
obj, exists, err := c.informer.GetStore().GetByKey(key)
if err != nil {
return err
}
if !exists {
return c.handler.OnChange(key, nil)
}
return c.handler.OnChange(key, obj.(runtime.Object))
}
func (c *controller) EnqueueKey(key string) {
c.startLock.Lock()
defer c.startLock.Unlock()
if c.workqueue == nil {
c.startKeys = append(c.startKeys, startKey{key: key})
} else {
c.workqueue.AddRateLimited(key)
}
}
func (c *controller) Enqueue(namespace, name string) {
key := keyFunc(namespace, name)
c.startLock.Lock()
defer c.startLock.Unlock()
if c.workqueue == nil {
c.startKeys = append(c.startKeys, startKey{key: key})
} else {
c.workqueue.AddRateLimited(key)
}
}
func (c *controller) EnqueueAfter(namespace, name string, duration time.Duration) {
key := keyFunc(namespace, name)
c.startLock.Lock()
defer c.startLock.Unlock()
if c.workqueue == nil {
c.startKeys = append(c.startKeys, startKey{key: key, after: duration})
} else {
c.workqueue.AddAfter(key, duration)
}
}
func keyFunc(namespace, name string) string {
if namespace == "" {
return name
}
return namespace + "/" + name
}
func (c *controller) enqueue(obj interface{}) {
var key string
var err error
if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
log.Errorf("%v", err)
return
}
c.startLock.Lock()
if c.workqueue == nil {
c.startKeys = append(c.startKeys, startKey{key: key})
} else {
c.workqueue.Add(key)
}
c.startLock.Unlock()
}
func (c *controller) handleObject(obj interface{}) {
if _, ok := obj.(metav1.Object); !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
log.Errorf("error decoding object, invalid type")
return
}
_, ok = tombstone.Obj.(metav1.Object)
if !ok {
log.Errorf("error decoding object tombstone, invalid type")
return
}
}
c.enqueue(obj)
}

View File

@@ -0,0 +1,35 @@
package controller
import (
"context"
"time"
"k8s.io/client-go/tools/cache"
)
type errorController struct {
informer cache.SharedIndexInformer
}
func newErrorController() *errorController {
return &errorController{
informer: cache.NewSharedIndexInformer(nil, nil, 0, cache.Indexers{}),
}
}
func (n *errorController) Enqueue(namespace, name string) {
}
func (n *errorController) EnqueueAfter(namespace, name string, delay time.Duration) {
}
func (n *errorController) EnqueueKey(key string) {
}
func (n *errorController) Informer() cache.SharedIndexInformer {
return n.informer
}
func (n *errorController) Start(ctx context.Context, workers int) error {
return nil
}

View File

@@ -0,0 +1,122 @@
package controller
import (
"context"
"sync"
"time"
"github.com/rancher/lasso/pkg/cache"
"github.com/rancher/lasso/pkg/client"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
cachetools "k8s.io/client-go/tools/cache"
)
type SharedControllerHandler interface {
OnChange(key string, obj runtime.Object) (runtime.Object, error)
}
type SharedController interface {
Controller
RegisterHandler(ctx context.Context, name string, handler SharedControllerHandler)
Client() *client.Client
}
type SharedControllerHandlerFunc func(key string, obj runtime.Object) (runtime.Object, error)
func (s SharedControllerHandlerFunc) OnChange(key string, obj runtime.Object) (runtime.Object, error) {
return s(key, obj)
}
type sharedController struct {
// this allows one to create a sharedcontroller but it will not actually be started
// unless some aspect of the controllers informer is accessed or needed to be used
deferredController func() (Controller, error)
sharedCacheFactory cache.SharedCacheFactory
controller Controller
gvk schema.GroupVersionKind
handler *sharedHandler
startLock sync.Mutex
started bool
startError error
client *client.Client
}
func (s *sharedController) Enqueue(namespace, name string) {
s.initController().Enqueue(namespace, name)
}
func (s *sharedController) EnqueueAfter(namespace, name string, delay time.Duration) {
s.initController().EnqueueAfter(namespace, name, delay)
}
func (s *sharedController) EnqueueKey(key string) {
s.initController().EnqueueKey(key)
}
func (s *sharedController) Informer() cachetools.SharedIndexInformer {
return s.initController().Informer()
}
func (s *sharedController) Client() *client.Client {
return s.client
}
func (s *sharedController) initController() Controller {
s.startLock.Lock()
defer s.startLock.Unlock()
if s.controller != nil {
return s.controller
}
controller, err := s.deferredController()
if err != nil {
controller = newErrorController()
}
s.startError = err
s.controller = controller
return s.controller
}
func (s *sharedController) Start(ctx context.Context, workers int) error {
s.startLock.Lock()
defer s.startLock.Unlock()
if s.startError != nil || s.controller == nil {
return s.startError
}
if err := s.controller.Start(ctx, workers); err != nil {
return err
}
s.started = true
go func() {
<-ctx.Done()
s.startLock.Lock()
defer s.startLock.Unlock()
s.started = false
}()
return nil
}
func (s *sharedController) RegisterHandler(ctx context.Context, name string, handler SharedControllerHandler) {
// Ensure that controller is initialized
c := s.initController()
getHandlerTransaction(ctx).do(func() {
s.handler.Register(ctx, name, handler)
s.startLock.Lock()
defer s.startLock.Unlock()
if s.started {
for _, key := range c.Informer().GetStore().ListKeys() {
c.EnqueueKey(key)
}
}
})
}

View File

@@ -0,0 +1,205 @@
package controller
import (
"context"
"sync"
"github.com/rancher/lasso/pkg/cache"
"github.com/rancher/lasso/pkg/client"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
"k8s.io/client-go/util/workqueue"
)
type SharedControllerFactory interface {
ForObject(obj runtime.Object) (SharedController, error)
ForKind(gvk schema.GroupVersionKind) (SharedController, error)
ForResource(gvr schema.GroupVersionResource, namespaced bool) SharedController
ForResourceKind(gvr schema.GroupVersionResource, kind string, namespaced bool) SharedController
SharedCacheFactory() cache.SharedCacheFactory
Start(ctx context.Context, workers int) error
}
type SharedControllerFactoryOptions struct {
DefaultRateLimiter workqueue.RateLimiter
DefaultWorkers int
KindRateLimiter map[schema.GroupVersionKind]workqueue.RateLimiter
KindWorkers map[schema.GroupVersionKind]int
}
type sharedControllerFactory struct {
controllerLock sync.RWMutex
sharedCacheFactory cache.SharedCacheFactory
controllers map[schema.GroupVersionResource]*sharedController
rateLimiter workqueue.RateLimiter
workers int
kindRateLimiter map[schema.GroupVersionKind]workqueue.RateLimiter
kindWorkers map[schema.GroupVersionKind]int
}
func NewSharedControllerFactoryFromConfig(config *rest.Config, scheme *runtime.Scheme) (SharedControllerFactory, error) {
cf, err := client.NewSharedClientFactory(config, &client.SharedClientFactoryOptions{
Scheme: scheme,
})
if err != nil {
return nil, err
}
return NewSharedControllerFactory(cache.NewSharedCachedFactory(cf, nil), nil), nil
}
func NewSharedControllerFactory(cacheFactory cache.SharedCacheFactory, opts *SharedControllerFactoryOptions) SharedControllerFactory {
opts = applyDefaultSharedOptions(opts)
return &sharedControllerFactory{
sharedCacheFactory: cacheFactory,
controllers: map[schema.GroupVersionResource]*sharedController{},
workers: opts.DefaultWorkers,
kindWorkers: opts.KindWorkers,
rateLimiter: opts.DefaultRateLimiter,
kindRateLimiter: opts.KindRateLimiter,
}
}
func applyDefaultSharedOptions(opts *SharedControllerFactoryOptions) *SharedControllerFactoryOptions {
var newOpts SharedControllerFactoryOptions
if opts != nil {
newOpts = *opts
}
if newOpts.DefaultWorkers == 0 {
newOpts.DefaultWorkers = 5
}
return &newOpts
}
func (s *sharedControllerFactory) Start(ctx context.Context, defaultWorkers int) error {
s.controllerLock.Lock()
defer s.controllerLock.Unlock()
if err := s.sharedCacheFactory.Start(ctx); err != nil {
return err
}
for gvr, controller := range s.controllers {
w, err := s.getWorkers(gvr, defaultWorkers)
if err != nil {
return err
}
if err := controller.Start(ctx, w); err != nil {
return err
}
}
return nil
}
func (s *sharedControllerFactory) ForObject(obj runtime.Object) (SharedController, error) {
gvk, err := s.sharedCacheFactory.SharedClientFactory().GVKForObject(obj)
if err != nil {
return nil, err
}
return s.ForKind(gvk)
}
func (s *sharedControllerFactory) ForKind(gvk schema.GroupVersionKind) (SharedController, error) {
gvr, nsed, err := s.sharedCacheFactory.SharedClientFactory().ResourceForGVK(gvk)
if err != nil {
return nil, err
}
return s.ForResourceKind(gvr, gvk.Kind, nsed), nil
}
func (s *sharedControllerFactory) ForResource(gvr schema.GroupVersionResource, namespaced bool) SharedController {
return s.ForResourceKind(gvr, "", namespaced)
}
func (s *sharedControllerFactory) ForResourceKind(gvr schema.GroupVersionResource, kind string, namespaced bool) SharedController {
controllerResult := s.byResource(gvr)
if controllerResult != nil {
return controllerResult
}
s.controllerLock.Lock()
defer s.controllerLock.Unlock()
controllerResult = s.controllers[gvr]
if controllerResult != nil {
return controllerResult
}
client := s.sharedCacheFactory.SharedClientFactory().ForResourceKind(gvr, kind, namespaced)
handler := &sharedHandler{}
controllerResult = &sharedController{
deferredController: func() (Controller, error) {
var (
gvk schema.GroupVersionKind
err error
)
if kind == "" {
gvk, err = s.sharedCacheFactory.SharedClientFactory().GVKForResource(gvr)
if err != nil {
return nil, err
}
} else {
gvk = gvr.GroupVersion().WithKind(kind)
}
cache, err := s.sharedCacheFactory.ForResourceKind(gvr, kind, namespaced)
if err != nil {
return nil, err
}
rateLimiter, ok := s.kindRateLimiter[gvk]
if !ok {
rateLimiter = s.rateLimiter
}
starter := func(ctx context.Context) error {
return s.sharedCacheFactory.StartGVK(ctx, gvk)
}
c := New(gvk.String(), cache, starter, handler, &Options{
RateLimiter: rateLimiter,
})
return c, err
},
handler: handler,
client: client,
}
s.controllers[gvr] = controllerResult
return controllerResult
}
func (s *sharedControllerFactory) getWorkers(gvr schema.GroupVersionResource, workers int) (int, error) {
gvk, err := s.sharedCacheFactory.SharedClientFactory().GVKForResource(gvr)
if err != nil {
return 0, err
}
w, ok := s.kindWorkers[gvk]
if ok {
return w, nil
}
if workers > 0 {
return workers, nil
}
return s.workers, nil
}
func (s *sharedControllerFactory) byResource(gvr schema.GroupVersionResource) *sharedController {
s.controllerLock.RLock()
defer s.controllerLock.RUnlock()
return s.controllers[gvr]
}
func (s *sharedControllerFactory) SharedCacheFactory() cache.SharedCacheFactory {
return s.sharedCacheFactory
}

View File

@@ -0,0 +1,122 @@
package controller
import (
"context"
"errors"
"fmt"
"reflect"
"strings"
"sync"
"sync/atomic"
"k8s.io/apimachinery/pkg/runtime"
)
var (
ErrIgnore = errors.New("ignore handler error")
)
type handlerEntry struct {
id int64
name string
handler SharedControllerHandler
}
type sharedHandler struct {
// keep first because arm32 needs atomic.AddInt64 target to be mem aligned
idCounter int64
lock sync.Mutex
handlers []handlerEntry
}
func (h *sharedHandler) Register(ctx context.Context, name string, handler SharedControllerHandler) {
h.lock.Lock()
defer h.lock.Unlock()
id := atomic.AddInt64(&h.idCounter, 1)
h.handlers = append(h.handlers, handlerEntry{
id: id,
name: name,
handler: handler,
})
go func() {
<-ctx.Done()
h.lock.Lock()
defer h.lock.Unlock()
for i := range h.handlers {
if h.handlers[i].id == id {
h.handlers = append(h.handlers[:i], h.handlers[i+1:]...)
break
}
}
}()
}
func (h *sharedHandler) OnChange(key string, obj runtime.Object) error {
var (
errs errorList
)
for _, handler := range h.handlers {
newObj, err := handler.handler.OnChange(key, obj)
if err != nil && !errors.Is(err, ErrIgnore) {
errs = append(errs, &handlerError{
HandlerName: handler.name,
Err: err,
})
}
if newObj != nil && !reflect.ValueOf(newObj).IsNil() {
obj = newObj
}
}
return errs.ToErr()
}
type errorList []error
func (e errorList) Error() string {
buf := strings.Builder{}
for _, err := range e {
if buf.Len() > 0 {
buf.WriteString(", ")
}
buf.WriteString(err.Error())
}
return buf.String()
}
func (e errorList) ToErr() error {
switch len(e) {
case 0:
return nil
case 1:
return e[0]
default:
return e
}
}
func (e errorList) Cause() error {
if len(e) > 0 {
return e[0]
}
return nil
}
type handlerError struct {
HandlerName string
Err error
}
func (h handlerError) Error() string {
return fmt.Sprintf("handler %s: %v", h.HandlerName, h.Err)
}
func (h handlerError) Cause() error {
return h.Err
}

View File

@@ -13,6 +13,18 @@ type HandlerTransaction struct {
result bool
}
func (h *HandlerTransaction) do(f func()) {
if h == nil {
f()
} else {
go func() {
if h.shouldContinue() {
f()
}
}()
}
}
func (h *HandlerTransaction) shouldContinue() bool {
select {
case <-h.parent.Done():

13
vendor/github.com/rancher/lasso/pkg/log/log.go generated vendored Normal file
View File

@@ -0,0 +1,13 @@
package log
import "log"
var (
// Stupid log abstraction
Infof = func(message string, obj ...interface{}) {
log.Printf("INFO: "+message+"\n", obj...)
}
Errorf = func(message string, obj ...interface{}) {
log.Printf("ERROR: "+message+"\n", obj...)
}
)

90
vendor/github.com/rancher/lasso/pkg/mapper/mapper.go generated vendored Normal file
View File

@@ -0,0 +1,90 @@
package mapper
import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"k8s.io/client-go/discovery/cached/memory"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
)
func New(config *rest.Config) (meta.RESTMapper, error) {
d, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
return nil, err
}
cached := memory.NewMemCacheClient(d)
return &retryMapper{
target: restmapper.NewDeferredDiscoveryRESTMapper(cached),
cache: cached,
}, nil
}
type retryMapper struct {
target meta.RESTMapper
cache discovery.CachedDiscoveryInterface
}
func (r *retryMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
result, err := r.target.KindFor(resource)
if err != nil {
r.cache.Invalidate()
return r.target.KindFor(resource)
}
return result, err
}
func (r *retryMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
result, err := r.target.KindsFor(resource)
if err != nil {
r.cache.Invalidate()
return r.target.KindsFor(resource)
}
return result, err
}
func (r *retryMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
result, err := r.target.ResourceFor(input)
if err != nil {
r.cache.Invalidate()
return r.target.ResourceFor(input)
}
return result, err
}
func (r *retryMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
result, err := r.target.ResourcesFor(input)
if err != nil {
r.cache.Invalidate()
return r.target.ResourcesFor(input)
}
return result, err
}
func (r *retryMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
result, err := r.target.RESTMapping(gk, versions...)
if err != nil {
r.cache.Invalidate()
return r.target.RESTMapping(gk, versions...)
}
return result, err
}
func (r *retryMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
result, err := r.target.RESTMappings(gk, versions...)
if err != nil {
r.cache.Invalidate()
return r.target.RESTMappings(gk, versions...)
}
return result, err
}
func (r *retryMapper) ResourceSingularizer(resource string) (singular string, err error) {
result, err := r.target.ResourceSingularizer(resource)
if err != nil {
r.cache.Invalidate()
return r.target.ResourceSingularizer(resource)
}
return result, err
}

5
vendor/github.com/rancher/lasso/pkg/scheme/all.go generated vendored Normal file
View File

@@ -0,0 +1,5 @@
package scheme
import "k8s.io/apimachinery/pkg/runtime"
var All = runtime.NewScheme()

View File

@@ -2,321 +2,69 @@ package controller
import (
"context"
"fmt"
"os"
"reflect"
"strings"
"sync"
"time"
"github.com/rancher/lasso/pkg/controller"
errors2 "github.com/pkg/errors"
"github.com/rancher/norman/metrics"
"github.com/rancher/norman/objectclient"
"github.com/rancher/norman/types"
"github.com/sirupsen/logrus"
"golang.org/x/time/rate"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
const MetricsQueueEnv = "NORMAN_QUEUE_METRICS"
const MetricsReflectorEnv = "NORMAN_REFLECTOR_METRICS"
var (
resyncPeriod = 2 * time.Hour
)
// Override the metrics providers
func init() {
if os.Getenv(MetricsQueueEnv) != "true" {
DisableControllerWorkqueuMetrics()
}
if os.Getenv(MetricsReflectorEnv) != "true" {
DisableControllerReflectorMetrics()
}
}
type HandlerFunc func(key string, obj interface{}) (interface{}, error)
type GenericController interface {
SetThreadinessOverride(count int)
Informer() cache.SharedIndexInformer
AddHandler(ctx context.Context, name string, handler HandlerFunc)
HandlerCount() int
Enqueue(namespace, name string)
EnqueueAfter(namespace, name string, after time.Duration)
Sync(ctx context.Context) error
Start(ctx context.Context, threadiness int) error
}
type Backend interface {
List(opts metav1.ListOptions) (runtime.Object, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
ObjectFactory() objectclient.ObjectFactory
}
type handlerDef struct {
name string
generation int
handler HandlerFunc
}
type generationKey struct {
generation int
key string
}
type genericController struct {
sync.Mutex
threadinessOverride int
generation int
informer cache.SharedIndexInformer
handlers []*handlerDef
preStart []string
queue workqueue.RateLimitingInterface
name string
running bool
synced bool
controller controller.SharedController
informer cache.SharedIndexInformer
name string
}
func NewGenericController(name string, genericClient Backend) GenericController {
informer := cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: genericClient.List,
WatchFunc: genericClient.Watch,
},
genericClient.ObjectFactory().Object(), resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
func NewGenericController(name string, controller controller.SharedController) GenericController {
return &genericController{
informer: informer,
name: name,
controller: controller,
informer: controller.Informer(),
name: name,
}
}
func (g *genericController) SetThreadinessOverride(count int) {
g.threadinessOverride = count
}
func (g *genericController) HandlerCount() int {
return len(g.handlers)
}
func (g *genericController) Informer() cache.SharedIndexInformer {
return g.informer
}
func (g *genericController) Enqueue(namespace, name string) {
key := name
if namespace != "" {
key = namespace + "/" + name
}
if g.queue == nil {
g.preStart = append(g.preStart, key)
} else {
g.queue.AddRateLimited(key)
}
g.controller.Enqueue(namespace, name)
}
func (g *genericController) EnqueueAfter(namespace, name string, after time.Duration) {
key := name
if namespace != "" {
key = namespace + "/" + name
}
if g.queue != nil {
g.queue.AddAfter(key, after)
}
g.controller.EnqueueAfter(namespace, name, after)
}
func (g *genericController) AddHandler(ctx context.Context, name string, handler HandlerFunc) {
t := getHandlerTransaction(ctx)
if t == nil {
g.addHandler(ctx, name, handler)
return
}
go func() {
if t.shouldContinue() {
g.addHandler(ctx, name, handler)
g.controller.RegisterHandler(ctx, name, controller.SharedControllerHandlerFunc(func(key string, obj runtime.Object) (runtime.Object, error) {
logrus.Tracef("%s calling handler %s %s", g.name, name, key)
metrics.IncTotalHandlerExecution(g.name, name)
result, err := handler(key, obj)
runtimeObject, _ := result.(runtime.Object)
if err != nil && !ignoreError(err, false) {
metrics.IncTotalHandlerFailure(g.name, name, key)
}
}()
}
func (g *genericController) addHandler(ctx context.Context, name string, handler HandlerFunc) {
g.Lock()
defer g.Unlock()
g.generation++
h := &handlerDef{
name: name,
generation: g.generation,
handler: handler,
}
go func(gen int) {
<-ctx.Done()
g.Lock()
defer g.Unlock()
var newHandlers []*handlerDef
for _, handler := range g.handlers {
if handler.generation == gen {
continue
}
newHandlers = append(newHandlers, handler)
}
g.handlers = newHandlers
}(h.generation)
g.handlers = append(g.handlers, h)
if g.synced {
for _, key := range g.informer.GetStore().ListKeys() {
g.queue.Add(key)
}
}
}
func (g *genericController) Sync(ctx context.Context) error {
g.Lock()
defer g.Unlock()
return g.sync(ctx)
}
func (g *genericController) sync(ctx context.Context) (retErr error) {
if g.synced {
return nil
}
if g.queue == nil {
rl := workqueue.NewMaxOfRateLimiter(
workqueue.NewItemExponentialFailureRateLimiter(500*time.Millisecond, 1000*time.Second),
// 10 qps, 100 bucket size. This is only for retry speed and its only the overall factor (not per item)
&workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
)
g.queue = workqueue.NewNamedRateLimitingQueue(rl, g.name)
for _, key := range g.preStart {
g.queue.Add(key)
}
g.preStart = nil
defer func() {
if retErr != nil {
g.queue.ShutDown()
}
}()
}
defer utilruntime.HandleCrash()
g.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: g.queueObject,
UpdateFunc: func(_, obj interface{}) {
g.queueObject(obj)
},
DeleteFunc: g.queueObject,
})
logrus.Tracef("Syncing %s Controller", g.name)
go g.informer.Run(ctx.Done())
if !cache.WaitForCacheSync(ctx.Done(), g.informer.HasSynced) {
return fmt.Errorf("failed to sync controller %s", g.name)
}
logrus.Tracef("Syncing %s Controller Done", g.name)
g.synced = true
return nil
}
func (g *genericController) Start(ctx context.Context, threadiness int) error {
g.Lock()
defer g.Unlock()
if err := g.sync(ctx); err != nil {
return err
}
if !g.running {
if g.threadinessOverride > 0 {
threadiness = g.threadinessOverride
}
go g.run(ctx, threadiness)
g.running = true
}
return nil
}
func (g *genericController) queueObject(obj interface{}) {
if _, ok := obj.(generationKey); ok {
g.queue.Add(obj)
return
}
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
if err == nil {
g.queue.Add(key)
}
}
func (g *genericController) run(ctx context.Context, threadiness int) {
defer utilruntime.HandleCrash()
defer g.queue.ShutDown()
for i := 0; i < threadiness; i++ {
go wait.Until(g.runWorker, time.Second, ctx.Done())
}
<-ctx.Done()
logrus.Infof("Shutting down %s controller", g.name)
}
func (g *genericController) runWorker() {
for g.processNextWorkItem() {
}
}
func (g *genericController) processNextWorkItem() bool {
key, quit := g.queue.Get()
if quit {
return false
}
defer g.queue.Done(key)
// do your work on the key. This method will contains your "do stuff" logic
err := g.syncHandler(key)
checkErr := err
if handlerErr, ok := checkErr.(*handlerError); ok {
checkErr = handlerErr.err
}
if _, ok := checkErr.(*ForgetError); err == nil || ok {
if ok {
if _, ok := err.(*ForgetError); ok {
logrus.Tracef("%v %v completed with dropped err: %v", g.name, key, err)
return runtimeObject, controller.ErrIgnore
}
g.queue.Forget(key)
return true
}
if err = filterConflictsError(err); err != nil {
logrus.Errorf("%v %v %v", g.name, key, err)
}
if gk, ok := key.(generationKey); ok {
g.queue.AddRateLimited(gk.key)
} else {
g.queue.AddRateLimited(key)
}
return true
return runtimeObject, err
}))
}
func ignoreError(err error, checkString bool) bool {
@@ -324,6 +72,9 @@ func ignoreError(err error, checkString bool) bool {
if errors.IsConflict(err) {
return true
}
if err == controller.ErrIgnore {
return true
}
if _, ok := err.(*ForgetError); ok {
return true
}
@@ -332,83 +83,3 @@ func ignoreError(err error, checkString bool) bool {
}
return false
}
func filterConflictsError(err error) error {
if ignoreError(err, false) {
return nil
}
if errs, ok := errors2.Cause(err).(*types.MultiErrors); ok {
var newErrors []error
for _, newError := range errs.Errors {
if !ignoreError(newError, true) {
newErrors = append(newErrors, newError)
}
}
return types.NewErrors(newErrors...)
}
return err
}
func (g *genericController) syncHandler(key interface{}) (err error) {
defer utilruntime.RecoverFromPanic(&err)
generation := -1
var s string
var obj interface{}
switch v := key.(type) {
case string:
s = v
case generationKey:
generation = v.generation
s = v.key
default:
return nil
}
obj, exists, err := g.informer.GetStore().GetByKey(s)
if err != nil {
return err
} else if !exists {
obj = nil
}
var errs []error
for _, handler := range g.handlers {
if generation > -1 && handler.generation != generation {
continue
}
logrus.Tracef("%s calling handler %s %s", g.name, handler.name, s)
metrics.IncTotalHandlerExecution(g.name, handler.name)
var newObj interface{}
if newObj, err = handler.handler(s, obj); err != nil {
if !ignoreError(err, false) {
metrics.IncTotalHandlerFailure(g.name, handler.name, s)
}
errs = append(errs, &handlerError{
name: handler.name,
err: err,
})
} else if newObj != nil && !reflect.ValueOf(newObj).IsNil() {
obj = newObj
}
}
err = types.NewErrors(errs...)
return
}
type handlerError struct {
name string
err error
}
func (h *handlerError) Error() string {
return fmt.Sprintf("[%s] failed with : %v", h.name, h.err)
}
func (h *handlerError) Cause() error {
return h.err
}

View File

@@ -1,107 +0,0 @@
package controller
import (
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
type noopMetric struct{}
func (noopMetric) Inc() {}
func (noopMetric) Dec() {}
func (noopMetric) Observe(float64) {}
func (noopMetric) Set(float64) {}
type noopWorkqueueMetricsProvider struct{}
func (noopWorkqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewDeprecatedAddsMetric(name string) workqueue.CounterMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewDeprecatedLatencyMetric(name string) workqueue.SummaryMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewDeprecatedWorkDurationMetric(name string) workqueue.SummaryMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewDeprecatedUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewDeprecatedLongestRunningProcessorMicrosecondsMetric(name string) workqueue.SettableGaugeMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewDeprecatedRetriesMetric(name string) workqueue.CounterMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewDeprecatedDepthMetric(name string) workqueue.GaugeMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric {
return noopMetric{}
}
func (noopWorkqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric {
return noopMetric{}
}
type noopCacheMetricsProvider struct{}
func (noopCacheMetricsProvider) NewListsMetric(name string) cache.CounterMetric { return noopMetric{} }
func (noopCacheMetricsProvider) NewListDurationMetric(name string) cache.SummaryMetric {
return noopMetric{}
}
func (noopCacheMetricsProvider) NewItemsInListMetric(name string) cache.SummaryMetric {
return noopMetric{}
}
func (noopCacheMetricsProvider) NewWatchesMetric(name string) cache.CounterMetric { return noopMetric{} }
func (noopCacheMetricsProvider) NewShortWatchesMetric(name string) cache.CounterMetric {
return noopMetric{}
}
func (noopCacheMetricsProvider) NewWatchDurationMetric(name string) cache.SummaryMetric {
return noopMetric{}
}
func (noopCacheMetricsProvider) NewItemsInWatchMetric(name string) cache.SummaryMetric {
return noopMetric{}
}
func (noopCacheMetricsProvider) NewLastResourceVersionMetric(name string) cache.GaugeMetric {
return noopMetric{}
}
func DisableAllControllerMetrics() {
DisableControllerReflectorMetrics()
DisableControllerWorkqueuMetrics()
}
func DisableControllerWorkqueuMetrics() {
workqueue.SetProvider(noopWorkqueueMetricsProvider{})
}
func DisableControllerReflectorMetrics() {
cache.SetReflectorMetricsProvider(noopCacheMetricsProvider{})
}

View File

@@ -1,40 +0,0 @@
package controller
import (
"context"
"golang.org/x/sync/errgroup"
)
type Starter interface {
Sync(ctx context.Context) error
Start(ctx context.Context, threadiness int) error
}
func SyncThenStart(ctx context.Context, threadiness int, starters ...Starter) error {
if err := Sync(ctx, starters...); err != nil {
return err
}
return Start(ctx, threadiness, starters...)
}
func Sync(ctx context.Context, starters ...Starter) error {
eg, _ := errgroup.WithContext(ctx)
for _, starter := range starters {
func(starter Starter) {
eg.Go(func() error {
return starter.Sync(ctx)
})
}(starter)
}
return eg.Wait()
}
func Start(ctx context.Context, threadiness int, starters ...Starter) error {
for _, starter := range starters {
if err := starter.Start(ctx, threadiness); err != nil {
return err
}
}
return nil
}

View File

@@ -28,7 +28,7 @@ var (
}
{{.schema.CodeName}}Resource = metav1.APIResource{
Name: "{{.schema.PluralName | toLower}}",
SingularName: "{{.schema.ID | toLower}}",
SingularName: "{{.schema.CodeName | toLower}}",
{{- if eq .schema.Scope "namespace" }}
Namespaced: true,
{{ else }}
@@ -55,11 +55,13 @@ func New{{.schema.CodeName}}(namespace, name string, obj {{.prefix}}{{.schema.Co
return &obj
}
{{ if eq .prefix "" }}
type {{.schema.CodeName}}List struct {
metav1.TypeMeta %BACK%json:",inline"%BACK%
metav1.ListMeta %BACK%json:"metadata,omitempty"%BACK%
Items []{{.prefix}}{{.schema.CodeName}} %BACK%json:"items"%BACK%
}
{{- end }}
type {{.schema.CodeName}}HandlerFunc func(key string, obj *{{.prefix}}{{.schema.CodeName}}) (runtime.Object, error)
@@ -80,8 +82,6 @@ type {{.schema.CodeName}}Controller interface {
AddClusterScopedFeatureHandler(ctx context.Context, enabled func() bool, name, clusterName string, handler {{.schema.CodeName}}HandlerFunc)
Enqueue(namespace, name string)
EnqueueAfter(namespace, name string, after time.Duration)
Sync(ctx context.Context) error
Start(ctx context.Context, threadiness int) error
}
type {{.schema.CodeName}}Interface interface {
@@ -92,8 +92,8 @@ type {{.schema.CodeName}}Interface interface {
Update(*{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error)
Delete(name string, options *metav1.DeleteOptions) error
DeleteNamespaced(namespace, name string, options *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (*{{.schema.CodeName}}List, error)
ListNamespaced(namespace string, opts metav1.ListOptions) (*{{.schema.CodeName}}List, error)
List(opts metav1.ListOptions) (*{{.prefix}}{{.schema.CodeName}}List, error)
ListNamespaced(namespace string, opts metav1.ListOptions) (*{{.prefix}}{{.schema.CodeName}}List, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error
Controller() {{.schema.CodeName}}Controller
@@ -132,7 +132,7 @@ func (l *{{.schema.ID}}Lister) Get(namespace, name string) (*{{.prefix}}{{.schem
if !exists {
return nil, errors.NewNotFound(schema.GroupResource{
Group: {{.schema.CodeName}}GroupVersionKind.Group,
Resource: "{{.schema.ID}}",
Resource: {{.schema.CodeName}}GroupVersionResource.Resource,
}, key)
}
return obj.(*{{.prefix}}{{.schema.CodeName}}), nil
@@ -213,29 +213,16 @@ func (c {{.schema.ID}}Factory) Object() runtime.Object {
}
func (c {{.schema.ID}}Factory) List() runtime.Object {
return &{{.schema.CodeName}}List{}
return &{{.prefix}}{{.schema.CodeName}}List{}
}
func (s *{{.schema.ID}}Client) Controller() {{.schema.CodeName}}Controller {
s.client.Lock()
defer s.client.Unlock()
c, ok := s.client.{{.schema.ID}}Controllers[s.ns]
if ok {
return c
}
genericController := controller.NewGenericController({{.schema.CodeName}}GroupVersionKind.Kind+"Controller",
s.objectClient)
s.client.controllerFactory.ForResourceKind({{.schema.CodeName}}GroupVersionResource, {{.schema.CodeName}}GroupVersionKind.Kind, {{.schema | namespaced}}))
c = &{{.schema.ID}}Controller{
return &{{.schema.ID}}Controller{
GenericController: genericController,
}
s.client.{{.schema.ID}}Controllers[s.ns] = c
s.client.starters = append(s.client.starters, c)
return c
}
type {{.schema.ID}}Client struct {
@@ -269,6 +256,11 @@ func (s *{{.schema.ID}}Client) Update(o *{{.prefix}}{{.schema.CodeName}}) (*{{.p
return obj.(*{{.prefix}}{{.schema.CodeName}}), err
}
func (s *{{.schema.ID}}Client) UpdateStatus(o *{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error) {
obj, err := s.objectClient.UpdateStatus(o.Name, o)
return obj.(*{{.prefix}}{{.schema.CodeName}}), err
}
func (s *{{.schema.ID}}Client) Delete(name string, options *metav1.DeleteOptions) error {
return s.objectClient.Delete(name, options)
}
@@ -277,14 +269,14 @@ func (s *{{.schema.ID}}Client) DeleteNamespaced(namespace, name string, options
return s.objectClient.DeleteNamespaced(namespace, name, options)
}
func (s *{{.schema.ID}}Client) List(opts metav1.ListOptions) (*{{.schema.CodeName}}List, error) {
func (s *{{.schema.ID}}Client) List(opts metav1.ListOptions) (*{{.prefix}}{{.schema.CodeName}}List, error) {
obj, err := s.objectClient.List(opts)
return obj.(*{{.schema.CodeName}}List), err
return obj.(*{{.prefix}}{{.schema.CodeName}}List), err
}
func (s *{{.schema.ID}}Client) ListNamespaced(namespace string, opts metav1.ListOptions) (*{{.schema.CodeName}}List, error) {
func (s *{{.schema.ID}}Client) ListNamespaced(namespace string, opts metav1.ListOptions) (*{{.prefix}}{{.schema.CodeName}}List, error) {
obj, err := s.objectClient.ListNamespaced(namespace, opts)
return obj.(*{{.schema.CodeName}}List), err
return obj.(*{{.prefix}}{{.schema.CodeName}}List), err
}
func (s *{{.schema.ID}}Client) Watch(opts metav1.ListOptions) (watch.Interface, error) {

View File

@@ -1,66 +0,0 @@
package generator
import (
"fmt"
"path"
"strings"
"github.com/rancher/norman/types"
"k8s.io/apimachinery/pkg/runtime/schema"
)
var (
baseCattle = "client"
baseK8s = "apis"
)
func DefaultGenerate(schemas *types.Schemas, pkgPath string, publicAPI bool, privateTypes map[string]bool) error {
version := getVersion(schemas)
group := strings.Split(version.Group, ".")[0]
cattleOutputPackage := path.Join(pkgPath, baseCattle, group, version.Version)
if !publicAPI {
cattleOutputPackage = ""
}
k8sOutputPackage := path.Join(pkgPath, baseK8s, version.Group, version.Version)
if err := Generate(schemas, privateTypes, cattleOutputPackage, k8sOutputPackage); err != nil {
return err
}
return nil
}
func ControllersForForeignTypes(baseOutputPackage string, gv schema.GroupVersion, nsObjs []interface{}, objs []interface{}) error {
version := gv.Version
group := gv.Group
groupPath := group
if groupPath == "" {
groupPath = "core"
}
k8sOutputPackage := path.Join(baseOutputPackage, baseK8s, groupPath, version)
return GenerateControllerForTypes(&types.APIVersion{
Version: version,
Group: group,
Path: fmt.Sprintf("/k8s/%s-%s", groupPath, version),
}, k8sOutputPackage, nsObjs, objs)
}
func getVersion(schemas *types.Schemas) *types.APIVersion {
var version types.APIVersion
for _, schema := range schemas.Schemas() {
if version.Group == "" {
version = schema.Version
continue
}
if version.Group != schema.Version.Group ||
version.Version != schema.Version.Version {
panic("schema set contains two APIVersions")
}
}
return &version
}

View File

@@ -18,6 +18,7 @@ func funcs() template.FuncMap {
"hasGet": hasGet,
"hasPost": hasPost,
"getCollectionOutput": getCollectionOutput,
"namespaced": namespaced,
}
}
@@ -29,6 +30,10 @@ func hasGet(schema *types.Schema) bool {
return contains(schema.CollectionMethods, http.MethodGet)
}
func namespaced(schema *types.Schema) bool {
return schema.Scope == types.NamespaceScope
}
func hasPost(schema *types.Schema) bool {
return contains(schema.CollectionMethods, http.MethodPost)
}

View File

@@ -251,20 +251,21 @@ func generateScheme(external bool, outputDir string, version *types.APIVersion,
for _, schema := range schemas {
if !external {
names = append(names, schema.CodeName)
}
if schema.CanList(nil) == nil {
names = append(names, schema.CodeName+"List")
} else if schema.CanList(nil) == nil {
names = append(names, schema.CodeName+"List")
}
}
return typeTemplate.Execute(output, map[string]interface{}{
"version": version,
"schemas": schemas,
"names": names,
"external": external,
"version": version,
"schemas": schemas,
"names": names,
})
}
func generateK8sClient(outputDir string, version *types.APIVersion, schemas []*types.Schema) error {
func generateK8sClient(external bool, outputDir string, version *types.APIVersion, schemas []*types.Schema) error {
filePath := strings.ToLower("zz_generated_k8s_client.go")
output, err := os.Create(path.Join(outputDir, filePath))
if err != nil {
@@ -280,8 +281,9 @@ func generateK8sClient(outputDir string, version *types.APIVersion, schemas []*t
}
return typeTemplate.Execute(output, map[string]interface{}{
"version": version,
"schemas": schemas,
"external": external,
"version": version,
"schemas": schemas,
})
}
@@ -350,11 +352,7 @@ func GenerateControllerForTypes(version *types.APIVersion, k8sOutputPackage stri
}
}
if err := deepCopyGen(baseDir, k8sOutputPackage); err != nil {
return err
}
if err := generateK8sClient(k8sDir, version, controllers); err != nil {
if err := generateK8sClient(true, k8sDir, version, controllers); err != nil {
return err
}
@@ -429,7 +427,7 @@ func Generate(schemas *types.Schemas, privateTypes map[string]bool, cattleOutput
return err
}
if err := generateK8sClient(k8sDir, &controllers[0].Version, controllers); err != nil {
if err := generateK8sClient(false, k8sDir, &controllers[0].Version, controllers); err != nil {
return err
}
@@ -481,6 +479,7 @@ func prepareDirs(dirs ...string) error {
func gofmt(workDir, pkg string) error {
cmd := exec.Command("goimports", "-w", "-l", "./"+pkg)
fmt.Println(cmd.Args)
cmd.Dir = workDir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

View File

@@ -6,69 +6,52 @@ import (
"sync"
"context"
"github.com/rancher/lasso/pkg/client"
"github.com/rancher/lasso/pkg/controller"
"github.com/rancher/norman/objectclient"
"github.com/rancher/norman/objectclient/dynamic"
"github.com/rancher/norman/controller"
"github.com/rancher/norman/restwatch"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"
)
type (
contextKeyType struct{}
contextClientsKeyType struct{}
)
type Interface interface {
RESTClient() rest.Interface
controller.Starter
{{range .schemas}}
{{.CodeNamePlural}}Getter{{end}}
}
type Client struct {
sync.Mutex
restClient rest.Interface
starters []controller.Starter
{{range .schemas}}
{{.ID}}Controllers map[string]{{.CodeName}}Controller{{end}}
controllerFactory controller.SharedControllerFactory
clientFactory client.SharedClientFactory
}
func NewForConfig(config rest.Config) (Interface, error) {
if config.NegotiatedSerializer == nil {
config.NegotiatedSerializer = dynamic.NegotiatedSerializer
{{ if not .external }}
func NewForConfig(cfg rest.Config) (Interface, error) {
scheme := runtime.NewScheme()
if err := AddToScheme(scheme); err != nil {
return nil, err
}
restClient, err := restwatch.UnversionedRESTClientFor(&config)
controllerFactory, err := controller.NewSharedControllerFactoryFromConfig(&cfg, scheme)
if err != nil {
return nil, err
}
return NewFromControllerFactory(controllerFactory)
}
{{ end }}
func NewFromControllerFactory(factory controller.SharedControllerFactory) (Interface, error) {
return &Client{
restClient: restClient,
{{range .schemas}}
{{.ID}}Controllers: map[string]{{.CodeName}}Controller{},{{end}}
controllerFactory: factory,
clientFactory: factory.SharedCacheFactory().SharedClientFactory(),
}, nil
}
func (c *Client) RESTClient() rest.Interface {
return c.restClient
}
func (c *Client) Sync(ctx context.Context) error {
return controller.Sync(ctx, c.starters...)
}
func (c *Client) Start(ctx context.Context, threadiness int) error {
return controller.Start(ctx, threadiness, c.starters...)
}
{{range .schemas}}
type {{.CodeNamePlural}}Getter interface {
{{.CodeNamePlural}}(namespace string) {{.CodeName}}Interface
}
func (c *Client) {{.CodeNamePlural}}(namespace string) {{.CodeName}}Interface {
objectClient := objectclient.NewObjectClient(namespace, c.restClient, &{{.CodeName}}Resource, {{.CodeName}}GroupVersionKind, {{.ID}}Factory{})
sharedClient := c.clientFactory.ForResourceKind({{.CodeName}}GroupVersionResource, {{.CodeName}}GroupVersionKind.Kind, {{ . | namespaced }})
objectClient := objectclient.NewObjectClient(namespace, sharedClient, &{{.CodeName}}Resource, {{.CodeName}}GroupVersionKind, {{.ID}}Factory{})
return &{{.ID}}Client{
ns: namespace,
client: c,

View File

@@ -26,6 +26,7 @@ func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
{{- if not .external }}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
@@ -41,4 +42,5 @@ func addKnownTypes(scheme *runtime.Scheme) error {
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
{{- end }}
`

View File

@@ -2,25 +2,16 @@ package objectclient
import (
"context"
"encoding/json"
"net/http"
"strings"
"github.com/pkg/errors"
"github.com/rancher/norman/restwatch"
"github.com/rancher/lasso/pkg/client"
"github.com/sirupsen/logrus"
k8sError "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
json2 "k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/rest"
restclientwatch "k8s.io/client-go/rest/watch"
)
type ObjectFactory interface {
@@ -46,6 +37,7 @@ type GenericClient interface {
GetNamespaced(namespace, name string, opts metav1.GetOptions) (runtime.Object, error)
Get(name string, opts metav1.GetOptions) (runtime.Object, error)
Update(name string, o runtime.Object) (runtime.Object, error)
UpdateStatus(name string, o runtime.Object) (runtime.Object, error)
DeleteNamespaced(namespace, name string, opts *metav1.DeleteOptions) error
Delete(name string, opts *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (runtime.Object, error)
@@ -57,30 +49,33 @@ type GenericClient interface {
}
type ObjectClient struct {
restClient rest.Interface
resource *metav1.APIResource
gvk schema.GroupVersionKind
ns string
Factory ObjectFactory
ctx context.Context
client *client.Client
resource *metav1.APIResource
gvk schema.GroupVersionKind
ns string
Factory ObjectFactory
}
func NewObjectClient(namespace string, restClient rest.Interface, apiResource *metav1.APIResource, gvk schema.GroupVersionKind, factory ObjectFactory) *ObjectClient {
func NewObjectClient(namespace string, client *client.Client, apiResource *metav1.APIResource, gvk schema.GroupVersionKind, factory ObjectFactory) *ObjectClient {
return &ObjectClient{
restClient: restClient,
resource: apiResource,
gvk: gvk,
ns: namespace,
Factory: factory,
ctx: context.TODO(),
client: client,
resource: apiResource,
gvk: gvk,
ns: namespace,
Factory: factory,
}
}
func (p *ObjectClient) UnstructuredClient() GenericClient {
return &ObjectClient{
restClient: p.restClient,
resource: p.resource,
gvk: p.gvk,
ns: p.ns,
Factory: &UnstructuredObjectFactory{},
ctx: p.ctx,
client: p.client,
resource: p.resource,
gvk: p.gvk,
ns: p.ns,
Factory: &UnstructuredObjectFactory{},
}
}
@@ -97,78 +92,24 @@ func (p *ObjectClient) getAPIPrefix() string {
func (p *ObjectClient) Create(o runtime.Object) (runtime.Object, error) {
ns := p.ns
obj, ok := o.(metav1.Object)
if ok && obj.GetNamespace() != "" {
if obj, ok := o.(metav1.Object); ok && obj.GetNamespace() != "" {
ns = obj.GetNamespace()
}
if ok {
labels := obj.GetLabels()
if labels == nil {
labels = make(map[string]string)
} else {
ls := make(map[string]string)
for k, v := range labels {
ls[k] = v
}
labels = ls
}
labels["cattle.io/creator"] = "norman"
obj.SetLabels(labels)
}
if t, err := meta.TypeAccessor(o); err == nil {
if t.GetKind() == "" {
t.SetKind(p.gvk.Kind)
}
if t.GetAPIVersion() == "" {
apiVersion, _ := p.gvk.ToAPIVersionAndKind()
t.SetAPIVersion(apiVersion)
}
}
result := p.Factory.Object()
logrus.Tracef("REST CREATE %s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, ns, p.resource.Name)
err := p.restClient.Post().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
NamespaceIfScoped(ns, p.resource.Namespaced).
Resource(p.resource.Name).
Body(o).
Do(context.TODO()).
Into(result)
return result, err
result := p.ObjectFactory().Object()
return result, p.client.Create(p.ctx, ns, o, result, metav1.CreateOptions{})
}
func (p *ObjectClient) GetNamespaced(namespace, name string, opts metav1.GetOptions) (runtime.Object, error) {
result := p.Factory.Object()
req := p.restClient.Get().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version)
if namespace != "" {
req = req.Namespace(namespace)
}
err := req.
Resource(p.resource.Name).
VersionedParams(&opts, metav1.ParameterCodec).
Name(name).
Do(context.TODO()).
Into(result)
logrus.Tracef("REST GET %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, namespace, p.resource.Name, name)
return result, err
result := p.Factory.Object()
return result, p.client.Get(p.ctx, namespace, name, result, opts)
}
func (p *ObjectClient) Get(name string, opts metav1.GetOptions) (runtime.Object, error) {
result := p.Factory.Object()
err := p.restClient.Get().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
NamespaceIfScoped(p.ns, p.resource.Namespaced).
Resource(p.resource.Name).
VersionedParams(&opts, metav1.ParameterCodec).
Name(name).
Do(context.TODO()).
Into(result)
logrus.Tracef("REST GET %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, p.ns, p.resource.Name, name)
return result, err
result := p.Factory.Object()
return result, p.client.Get(p.ctx, p.ns, name, result, opts)
}
func (p *ObjectClient) Update(name string, o runtime.Object) (runtime.Object, error) {
@@ -181,130 +122,59 @@ func (p *ObjectClient) Update(name string, o runtime.Object) (runtime.Object, er
return result, errors.New("object missing name")
}
logrus.Tracef("REST UPDATE %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, ns, p.resource.Name, name)
err := p.restClient.Put().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
NamespaceIfScoped(ns, p.resource.Namespaced).
Resource(p.resource.Name).
Name(name).
Body(o).
Do(context.TODO()).
Into(result)
return result, err
return result, p.client.Update(p.ctx, ns, o, result, metav1.UpdateOptions{})
}
func (p *ObjectClient) UpdateStatus(name string, o runtime.Object) (runtime.Object, error) {
ns := p.ns
if obj, ok := o.(metav1.Object); ok && obj.GetNamespace() != "" {
ns = obj.GetNamespace()
}
result := p.Factory.Object()
if len(name) == 0 {
return result, errors.New("object missing name")
}
logrus.Tracef("REST UPDATE %s/%s/%s/%s/status/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, ns, p.resource.Name, name)
return result, p.client.UpdateStatus(p.ctx, ns, o, result, metav1.UpdateOptions{})
}
func (p *ObjectClient) DeleteNamespaced(namespace, name string, opts *metav1.DeleteOptions) error {
req := p.restClient.Delete().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version)
if namespace != "" {
req = req.Namespace(namespace)
}
logrus.Tracef("REST DELETE %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, namespace, p.resource.Name, name)
return req.Resource(p.resource.Name).
Name(name).
Body(opts).
Do(context.TODO()).
Error()
if opts == nil {
opts = &metav1.DeleteOptions{}
}
return p.client.Delete(p.ctx, namespace, name, *opts)
}
func (p *ObjectClient) Delete(name string, opts *metav1.DeleteOptions) error {
logrus.Tracef("REST DELETE %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, p.ns, p.resource.Name, name)
return p.restClient.Delete().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
NamespaceIfScoped(p.ns, p.resource.Namespaced).
Resource(p.resource.Name).
Name(name).
Body(opts).
Do(context.TODO()).
Error()
if opts == nil {
opts = &metav1.DeleteOptions{}
}
return p.client.Delete(p.ctx, p.ns, name, *opts)
}
func (p *ObjectClient) List(opts metav1.ListOptions) (runtime.Object, error) {
result := p.Factory.List()
logrus.Tracef("REST LIST %s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, p.ns, p.resource.Name)
return result, p.restClient.Get().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
NamespaceIfScoped(p.ns, p.resource.Namespaced).
Resource(p.resource.Name).
VersionedParams(&opts, metav1.ParameterCodec).
Do(context.TODO()).
Into(result)
return result, p.client.List(p.ctx, p.ns, result, opts)
}
func (p *ObjectClient) ListNamespaced(namespace string, opts metav1.ListOptions) (runtime.Object, error) {
result := p.Factory.List()
logrus.Tracef("REST LIST %s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, namespace, p.resource.Name)
return result, p.restClient.Get().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
NamespaceIfScoped(namespace, p.resource.Namespaced).
Resource(p.resource.Name).
VersionedParams(&opts, metav1.ParameterCodec).
Do(context.TODO()).
Into(result)
return result, p.client.List(p.ctx, namespace, result, opts)
}
func (p *ObjectClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
restClient := p.restClient
if watchClient, ok := restClient.(restwatch.WatchClient); ok {
restClient = watchClient.WatchClient()
}
r, err := restClient.Get().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
Prefix("watch").
NamespaceIfScoped(p.ns, p.resource.Namespaced).
Resource(p.resource.Name).
VersionedParams(&opts, metav1.ParameterCodec).
Stream(context.TODO())
if err != nil {
return nil, err
}
embeddedDecoder := &structuredDecoder{
factory: p.Factory,
}
streamDecoder := streaming.NewDecoder(json2.Framer.NewFrameReader(r), embeddedDecoder)
decoder := restclientwatch.NewDecoder(streamDecoder, embeddedDecoder)
return watch.NewStreamWatcher(decoder, k8sError.NewClientErrorReporter(http.StatusInternalServerError, "watch", "ClientWatchDecoding")), nil
}
type structuredDecoder struct {
factory ObjectFactory
}
func (d *structuredDecoder) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
if into == nil {
into = d.factory.Object()
}
err := json.Unmarshal(data, &into)
if err != nil {
status := &metav1.Status{}
if err := json.Unmarshal(data, status); err == nil && strings.ToLower(status.Kind) == "status" {
return status, defaults, nil
}
return nil, nil, err
}
if _, ok := into.(*metav1.Status); !ok && strings.ToLower(into.GetObjectKind().GroupVersionKind().Kind) == "status" {
into = &metav1.Status{}
err := json.Unmarshal(data, into)
if err != nil {
return nil, nil, err
}
}
return into, defaults, err
return p.client.Watch(p.ctx, p.ns, opts)
}
func (p *ObjectClient) DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
return p.restClient.Delete().
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
NamespaceIfScoped(p.ns, p.resource.Namespaced).
Resource(p.resource.Name).
VersionedParams(&listOptions, metav1.ParameterCodec).
Body(deleteOptions).
Do(context.TODO()).
Error()
if deleteOptions == nil {
deleteOptions = &metav1.DeleteOptions{}
}
return p.client.DeleteCollection(p.ctx, p.ns, *deleteOptions, listOptions)
}
func (p *ObjectClient) Patch(name string, o runtime.Object, patchType types.PatchType, data []byte, subresources ...string) (runtime.Object, error) {
@@ -316,16 +186,7 @@ func (p *ObjectClient) Patch(name string, o runtime.Object, patchType types.Patc
if len(name) == 0 {
return result, errors.New("object missing name")
}
err := p.restClient.Patch(patchType).
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
NamespaceIfScoped(ns, p.resource.Namespaced).
Resource(p.resource.Name).
SubResource(subresources...).
Name(name).
Body(data).
Do(context.TODO()).
Into(result)
return result, err
return result, p.client.Patch(p.ctx, ns, name, patchType, data, result, metav1.PatchOptions{}, subresources...)
}
func (p *ObjectClient) ObjectFactory() ObjectFactory {

View File

@@ -19,28 +19,12 @@ limitations under the License.
package rbac
import (
"context"
"time"
"github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/schemes"
"k8s.io/apimachinery/pkg/runtime/schema"
informers "k8s.io/client-go/informers"
clientset "k8s.io/client-go/kubernetes"
scheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
)
func init() {
scheme.AddToScheme(schemes.All)
}
type Factory struct {
synced bool
informerFactory informers.SharedInformerFactory
clientset clientset.Interface
controllerManager *generic.ControllerManager
threadiness map[schema.GroupVersionKind]int
*generic.Factory
}
func NewFactoryFromConfigOrDie(config *rest.Config) *Factory {
@@ -52,60 +36,24 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory {
}
func NewFactoryFromConfig(config *rest.Config) (*Factory, error) {
cs, err := clientset.NewForConfig(config)
if err != nil {
return nil, err
}
informerFactory := informers.NewSharedInformerFactory(cs, 2*time.Hour)
return NewFactory(cs, informerFactory), nil
return NewFactoryFromConfigWithOptions(config, nil)
}
func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) {
if namespace == "" {
return NewFactoryFromConfig(config)
}
cs, err := clientset.NewForConfig(config)
if err != nil {
return nil, err
}
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, 2*time.Hour, informers.WithNamespace(namespace))
return NewFactory(cs, informerFactory), nil
return NewFactoryFromConfigWithOptions(config, &FactoryOptions{
Namespace: namespace,
})
}
func NewFactory(clientset clientset.Interface, informerFactory informers.SharedInformerFactory) *Factory {
type FactoryOptions = generic.FactoryOptions
func NewFactoryFromConfigWithOptions(config *rest.Config, opts *FactoryOptions) (*Factory, error) {
f, err := generic.NewFactoryFromConfigWithOptions(config, opts)
return &Factory{
threadiness: map[schema.GroupVersionKind]int{},
controllerManager: &generic.ControllerManager{},
clientset: clientset,
informerFactory: informerFactory,
}
}
func (c *Factory) Controllers() map[schema.GroupVersionKind]*generic.Controller {
return c.controllerManager.Controllers()
}
func (c *Factory) SetThreadiness(gvk schema.GroupVersionKind, threadiness int) {
c.threadiness[gvk] = threadiness
}
func (c *Factory) Sync(ctx context.Context) error {
c.informerFactory.Start(ctx.Done())
c.informerFactory.WaitForCacheSync(ctx.Done())
return nil
}
func (c *Factory) Start(ctx context.Context, defaultThreadiness int) error {
if err := c.Sync(ctx); err != nil {
return err
}
return c.controllerManager.Start(ctx, defaultThreadiness, c.threadiness)
Factory: f,
}, err
}
func (c *Factory) Rbac() Interface {
return New(c.controllerManager, c.informerFactory.Rbac(), c.clientset)
return New(c.ControllerFactory())
}

View File

@@ -19,10 +19,8 @@ limitations under the License.
package rbac
import (
"github.com/rancher/lasso/pkg/controller"
v1 "github.com/rancher/wrangler-api/pkg/generated/controllers/rbac/v1"
"github.com/rancher/wrangler/pkg/generic"
informers "k8s.io/client-go/informers/rbac"
clientset "k8s.io/client-go/kubernetes"
)
type Interface interface {
@@ -30,21 +28,16 @@ type Interface interface {
}
type group struct {
controllerManager *generic.ControllerManager
informers informers.Interface
client clientset.Interface
controllerFactory controller.SharedControllerFactory
}
// New returns a new Interface.
func New(controllerManager *generic.ControllerManager, informers informers.Interface,
client clientset.Interface) Interface {
func New(controllerFactory controller.SharedControllerFactory) Interface {
return &group{
controllerManager: controllerManager,
informers: informers,
client: client,
controllerFactory: controllerFactory,
}
}
func (g *group) V1() v1.Interface {
return v1.New(g.controllerManager, g.client.RbacV1(), g.informers.V1())
return v1.New(g.controllerFactory)
}

View File

@@ -22,9 +22,12 @@ import (
"context"
"time"
"github.com/rancher/lasso/pkg/client"
"github.com/rancher/lasso/pkg/controller"
"github.com/rancher/wrangler/pkg/generic"
v1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
@@ -32,9 +35,6 @@ import (
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/watch"
informers "k8s.io/client-go/informers/rbac/v1"
clientset "k8s.io/client-go/kubernetes/typed/rbac/v1"
listers "k8s.io/client-go/listers/rbac/v1"
"k8s.io/client-go/tools/cache"
)
@@ -74,18 +74,22 @@ type ClusterRoleCache interface {
type ClusterRoleIndexer func(obj *v1.ClusterRole) ([]string, error)
type clusterRoleController struct {
controllerManager *generic.ControllerManager
clientGetter clientset.ClusterRolesGetter
informer informers.ClusterRoleInformer
gvk schema.GroupVersionKind
controller controller.SharedController
client *client.Client
gvk schema.GroupVersionKind
groupResource schema.GroupResource
}
func NewClusterRoleController(gvk schema.GroupVersionKind, controllerManager *generic.ControllerManager, clientGetter clientset.ClusterRolesGetter, informer informers.ClusterRoleInformer) ClusterRoleController {
func NewClusterRoleController(gvk schema.GroupVersionKind, resource string, namespaced bool, controller controller.SharedControllerFactory) ClusterRoleController {
c := controller.ForResourceKind(gvk.GroupVersion().WithResource(resource), gvk.Kind, namespaced)
return &clusterRoleController{
controllerManager: controllerManager,
clientGetter: clientGetter,
informer: informer,
gvk: gvk,
controller: c,
client: c.Client(),
gvk: gvk,
groupResource: schema.GroupResource{
Group: gvk.Group,
Resource: resource,
},
}
}
@@ -132,12 +136,11 @@ func UpdateClusterRoleDeepCopyOnChange(client ClusterRoleClient, obj *v1.Cluster
}
func (c *clusterRoleController) AddGenericHandler(ctx context.Context, name string, handler generic.Handler) {
c.controllerManager.AddHandler(ctx, c.gvk, c.informer.Informer(), name, handler)
c.controller.RegisterHandler(ctx, name, controller.SharedControllerHandlerFunc(handler))
}
func (c *clusterRoleController) AddGenericRemoveHandler(ctx context.Context, name string, handler generic.Handler) {
removeHandler := generic.NewRemoveHandler(name, c.Updater(), handler)
c.controllerManager.AddHandler(ctx, c.gvk, c.informer.Informer(), name, removeHandler)
c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), handler))
}
func (c *clusterRoleController) OnChange(ctx context.Context, name string, sync ClusterRoleHandler) {
@@ -145,20 +148,19 @@ func (c *clusterRoleController) OnChange(ctx context.Context, name string, sync
}
func (c *clusterRoleController) OnRemove(ctx context.Context, name string, sync ClusterRoleHandler) {
removeHandler := generic.NewRemoveHandler(name, c.Updater(), FromClusterRoleHandlerToHandler(sync))
c.AddGenericHandler(ctx, name, removeHandler)
c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), FromClusterRoleHandlerToHandler(sync)))
}
func (c *clusterRoleController) Enqueue(name string) {
c.controllerManager.Enqueue(c.gvk, c.informer.Informer(), "", name)
c.controller.Enqueue("", name)
}
func (c *clusterRoleController) EnqueueAfter(name string, duration time.Duration) {
c.controllerManager.EnqueueAfter(c.gvk, c.informer.Informer(), "", name, duration)
c.controller.EnqueueAfter("", name, duration)
}
func (c *clusterRoleController) Informer() cache.SharedIndexInformer {
return c.informer.Informer()
return c.controller.Informer()
}
func (c *clusterRoleController) GroupVersionKind() schema.GroupVersionKind {
@@ -167,53 +169,70 @@ func (c *clusterRoleController) GroupVersionKind() schema.GroupVersionKind {
func (c *clusterRoleController) Cache() ClusterRoleCache {
return &clusterRoleCache{
lister: c.informer.Lister(),
indexer: c.informer.Informer().GetIndexer(),
indexer: c.Informer().GetIndexer(),
resource: c.groupResource,
}
}
func (c *clusterRoleController) Create(obj *v1.ClusterRole) (*v1.ClusterRole, error) {
return c.clientGetter.ClusterRoles().Create(context.TODO(), obj, metav1.CreateOptions{})
result := &v1.ClusterRole{}
return result, c.client.Create(context.TODO(), "", obj, result, metav1.CreateOptions{})
}
func (c *clusterRoleController) Update(obj *v1.ClusterRole) (*v1.ClusterRole, error) {
return c.clientGetter.ClusterRoles().Update(context.TODO(), obj, metav1.UpdateOptions{})
result := &v1.ClusterRole{}
return result, c.client.Update(context.TODO(), "", obj, result, metav1.UpdateOptions{})
}
func (c *clusterRoleController) Delete(name string, options *metav1.DeleteOptions) error {
if options == nil {
options = &metav1.DeleteOptions{}
}
return c.clientGetter.ClusterRoles().Delete(context.TODO(), name, *options)
return c.client.Delete(context.TODO(), "", name, *options)
}
func (c *clusterRoleController) Get(name string, options metav1.GetOptions) (*v1.ClusterRole, error) {
return c.clientGetter.ClusterRoles().Get(context.TODO(), name, options)
result := &v1.ClusterRole{}
return result, c.client.Get(context.TODO(), "", name, result, options)
}
func (c *clusterRoleController) List(opts metav1.ListOptions) (*v1.ClusterRoleList, error) {
return c.clientGetter.ClusterRoles().List(context.TODO(), opts)
result := &v1.ClusterRoleList{}
return result, c.client.List(context.TODO(), "", result, opts)
}
func (c *clusterRoleController) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return c.clientGetter.ClusterRoles().Watch(context.TODO(), opts)
return c.client.Watch(context.TODO(), "", opts)
}
func (c *clusterRoleController) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ClusterRole, err error) {
return c.clientGetter.ClusterRoles().Patch(context.TODO(), name, pt, data, metav1.PatchOptions{}, subresources...)
func (c *clusterRoleController) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v1.ClusterRole, error) {
result := &v1.ClusterRole{}
return result, c.client.Patch(context.TODO(), "", name, pt, data, result, metav1.PatchOptions{}, subresources...)
}
type clusterRoleCache struct {
lister listers.ClusterRoleLister
indexer cache.Indexer
indexer cache.Indexer
resource schema.GroupResource
}
func (c *clusterRoleCache) Get(name string) (*v1.ClusterRole, error) {
return c.lister.Get(name)
obj, exists, err := c.indexer.GetByKey(name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(c.resource, name)
}
return obj.(*v1.ClusterRole), nil
}
func (c *clusterRoleCache) List(selector labels.Selector) ([]*v1.ClusterRole, error) {
return c.lister.List(selector)
func (c *clusterRoleCache) List(selector labels.Selector) (ret []*v1.ClusterRole, err error) {
err = cache.ListAll(c.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1.ClusterRole))
})
return ret, err
}
func (c *clusterRoleCache) AddIndexer(indexName string, indexer ClusterRoleIndexer) {

View File

@@ -22,9 +22,12 @@ import (
"context"
"time"
"github.com/rancher/lasso/pkg/client"
"github.com/rancher/lasso/pkg/controller"
"github.com/rancher/wrangler/pkg/generic"
v1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
@@ -32,9 +35,6 @@ import (
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/watch"
informers "k8s.io/client-go/informers/rbac/v1"
clientset "k8s.io/client-go/kubernetes/typed/rbac/v1"
listers "k8s.io/client-go/listers/rbac/v1"
"k8s.io/client-go/tools/cache"
)
@@ -74,18 +74,22 @@ type ClusterRoleBindingCache interface {
type ClusterRoleBindingIndexer func(obj *v1.ClusterRoleBinding) ([]string, error)
type clusterRoleBindingController struct {
controllerManager *generic.ControllerManager
clientGetter clientset.ClusterRoleBindingsGetter
informer informers.ClusterRoleBindingInformer
gvk schema.GroupVersionKind
controller controller.SharedController
client *client.Client
gvk schema.GroupVersionKind
groupResource schema.GroupResource
}
func NewClusterRoleBindingController(gvk schema.GroupVersionKind, controllerManager *generic.ControllerManager, clientGetter clientset.ClusterRoleBindingsGetter, informer informers.ClusterRoleBindingInformer) ClusterRoleBindingController {
func NewClusterRoleBindingController(gvk schema.GroupVersionKind, resource string, namespaced bool, controller controller.SharedControllerFactory) ClusterRoleBindingController {
c := controller.ForResourceKind(gvk.GroupVersion().WithResource(resource), gvk.Kind, namespaced)
return &clusterRoleBindingController{
controllerManager: controllerManager,
clientGetter: clientGetter,
informer: informer,
gvk: gvk,
controller: c,
client: c.Client(),
gvk: gvk,
groupResource: schema.GroupResource{
Group: gvk.Group,
Resource: resource,
},
}
}
@@ -132,12 +136,11 @@ func UpdateClusterRoleBindingDeepCopyOnChange(client ClusterRoleBindingClient, o
}
func (c *clusterRoleBindingController) AddGenericHandler(ctx context.Context, name string, handler generic.Handler) {
c.controllerManager.AddHandler(ctx, c.gvk, c.informer.Informer(), name, handler)
c.controller.RegisterHandler(ctx, name, controller.SharedControllerHandlerFunc(handler))
}
func (c *clusterRoleBindingController) AddGenericRemoveHandler(ctx context.Context, name string, handler generic.Handler) {
removeHandler := generic.NewRemoveHandler(name, c.Updater(), handler)
c.controllerManager.AddHandler(ctx, c.gvk, c.informer.Informer(), name, removeHandler)
c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), handler))
}
func (c *clusterRoleBindingController) OnChange(ctx context.Context, name string, sync ClusterRoleBindingHandler) {
@@ -145,20 +148,19 @@ func (c *clusterRoleBindingController) OnChange(ctx context.Context, name string
}
func (c *clusterRoleBindingController) OnRemove(ctx context.Context, name string, sync ClusterRoleBindingHandler) {
removeHandler := generic.NewRemoveHandler(name, c.Updater(), FromClusterRoleBindingHandlerToHandler(sync))
c.AddGenericHandler(ctx, name, removeHandler)
c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), FromClusterRoleBindingHandlerToHandler(sync)))
}
func (c *clusterRoleBindingController) Enqueue(name string) {
c.controllerManager.Enqueue(c.gvk, c.informer.Informer(), "", name)
c.controller.Enqueue("", name)
}
func (c *clusterRoleBindingController) EnqueueAfter(name string, duration time.Duration) {
c.controllerManager.EnqueueAfter(c.gvk, c.informer.Informer(), "", name, duration)
c.controller.EnqueueAfter("", name, duration)
}
func (c *clusterRoleBindingController) Informer() cache.SharedIndexInformer {
return c.informer.Informer()
return c.controller.Informer()
}
func (c *clusterRoleBindingController) GroupVersionKind() schema.GroupVersionKind {
@@ -167,53 +169,70 @@ func (c *clusterRoleBindingController) GroupVersionKind() schema.GroupVersionKin
func (c *clusterRoleBindingController) Cache() ClusterRoleBindingCache {
return &clusterRoleBindingCache{
lister: c.informer.Lister(),
indexer: c.informer.Informer().GetIndexer(),
indexer: c.Informer().GetIndexer(),
resource: c.groupResource,
}
}
func (c *clusterRoleBindingController) Create(obj *v1.ClusterRoleBinding) (*v1.ClusterRoleBinding, error) {
return c.clientGetter.ClusterRoleBindings().Create(context.TODO(), obj, metav1.CreateOptions{})
result := &v1.ClusterRoleBinding{}
return result, c.client.Create(context.TODO(), "", obj, result, metav1.CreateOptions{})
}
func (c *clusterRoleBindingController) Update(obj *v1.ClusterRoleBinding) (*v1.ClusterRoleBinding, error) {
return c.clientGetter.ClusterRoleBindings().Update(context.TODO(), obj, metav1.UpdateOptions{})
result := &v1.ClusterRoleBinding{}
return result, c.client.Update(context.TODO(), "", obj, result, metav1.UpdateOptions{})
}
func (c *clusterRoleBindingController) Delete(name string, options *metav1.DeleteOptions) error {
if options == nil {
options = &metav1.DeleteOptions{}
}
return c.clientGetter.ClusterRoleBindings().Delete(context.TODO(), name, *options)
return c.client.Delete(context.TODO(), "", name, *options)
}
func (c *clusterRoleBindingController) Get(name string, options metav1.GetOptions) (*v1.ClusterRoleBinding, error) {
return c.clientGetter.ClusterRoleBindings().Get(context.TODO(), name, options)
result := &v1.ClusterRoleBinding{}
return result, c.client.Get(context.TODO(), "", name, result, options)
}
func (c *clusterRoleBindingController) List(opts metav1.ListOptions) (*v1.ClusterRoleBindingList, error) {
return c.clientGetter.ClusterRoleBindings().List(context.TODO(), opts)
result := &v1.ClusterRoleBindingList{}
return result, c.client.List(context.TODO(), "", result, opts)
}
func (c *clusterRoleBindingController) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return c.clientGetter.ClusterRoleBindings().Watch(context.TODO(), opts)
return c.client.Watch(context.TODO(), "", opts)
}
func (c *clusterRoleBindingController) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ClusterRoleBinding, err error) {
return c.clientGetter.ClusterRoleBindings().Patch(context.TODO(), name, pt, data, metav1.PatchOptions{}, subresources...)
func (c *clusterRoleBindingController) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v1.ClusterRoleBinding, error) {
result := &v1.ClusterRoleBinding{}
return result, c.client.Patch(context.TODO(), "", name, pt, data, result, metav1.PatchOptions{}, subresources...)
}
type clusterRoleBindingCache struct {
lister listers.ClusterRoleBindingLister
indexer cache.Indexer
indexer cache.Indexer
resource schema.GroupResource
}
func (c *clusterRoleBindingCache) Get(name string) (*v1.ClusterRoleBinding, error) {
return c.lister.Get(name)
obj, exists, err := c.indexer.GetByKey(name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(c.resource, name)
}
return obj.(*v1.ClusterRoleBinding), nil
}
func (c *clusterRoleBindingCache) List(selector labels.Selector) ([]*v1.ClusterRoleBinding, error) {
return c.lister.List(selector)
func (c *clusterRoleBindingCache) List(selector labels.Selector) (ret []*v1.ClusterRoleBinding, err error) {
err = cache.ListAll(c.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1.ClusterRoleBinding))
})
return ret, err
}
func (c *clusterRoleBindingCache) AddIndexer(indexName string, indexer ClusterRoleBindingIndexer) {

View File

@@ -19,12 +19,16 @@ limitations under the License.
package v1
import (
"github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/lasso/pkg/controller"
"github.com/rancher/wrangler/pkg/schemes"
v1 "k8s.io/api/rbac/v1"
informers "k8s.io/client-go/informers/rbac/v1"
clientset "k8s.io/client-go/kubernetes/typed/rbac/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func init() {
schemes.Register(v1.AddToScheme)
}
type Interface interface {
ClusterRole() ClusterRoleController
ClusterRoleBinding() ClusterRoleBindingController
@@ -32,30 +36,25 @@ type Interface interface {
RoleBinding() RoleBindingController
}
func New(controllerManager *generic.ControllerManager, client clientset.RbacV1Interface,
informers informers.Interface) Interface {
func New(controllerFactory controller.SharedControllerFactory) Interface {
return &version{
controllerManager: controllerManager,
client: client,
informers: informers,
controllerFactory: controllerFactory,
}
}
type version struct {
controllerManager *generic.ControllerManager
informers informers.Interface
client clientset.RbacV1Interface
controllerFactory controller.SharedControllerFactory
}
func (c *version) ClusterRole() ClusterRoleController {
return NewClusterRoleController(v1.SchemeGroupVersion.WithKind("ClusterRole"), c.controllerManager, c.client, c.informers.ClusterRoles())
return NewClusterRoleController(schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"}, "clusterroles", false, c.controllerFactory)
}
func (c *version) ClusterRoleBinding() ClusterRoleBindingController {
return NewClusterRoleBindingController(v1.SchemeGroupVersion.WithKind("ClusterRoleBinding"), c.controllerManager, c.client, c.informers.ClusterRoleBindings())
return NewClusterRoleBindingController(schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}, "clusterrolebindings", false, c.controllerFactory)
}
func (c *version) Role() RoleController {
return NewRoleController(v1.SchemeGroupVersion.WithKind("Role"), c.controllerManager, c.client, c.informers.Roles())
return NewRoleController(schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "Role"}, "roles", true, c.controllerFactory)
}
func (c *version) RoleBinding() RoleBindingController {
return NewRoleBindingController(v1.SchemeGroupVersion.WithKind("RoleBinding"), c.controllerManager, c.client, c.informers.RoleBindings())
return NewRoleBindingController(schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"}, "rolebindings", true, c.controllerFactory)
}

View File

@@ -22,9 +22,12 @@ import (
"context"
"time"
"github.com/rancher/lasso/pkg/client"
"github.com/rancher/lasso/pkg/controller"
"github.com/rancher/wrangler/pkg/generic"
v1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
@@ -32,9 +35,6 @@ import (
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/watch"
informers "k8s.io/client-go/informers/rbac/v1"
clientset "k8s.io/client-go/kubernetes/typed/rbac/v1"
listers "k8s.io/client-go/listers/rbac/v1"
"k8s.io/client-go/tools/cache"
)
@@ -74,18 +74,22 @@ type RoleCache interface {
type RoleIndexer func(obj *v1.Role) ([]string, error)
type roleController struct {
controllerManager *generic.ControllerManager
clientGetter clientset.RolesGetter
informer informers.RoleInformer
gvk schema.GroupVersionKind
controller controller.SharedController
client *client.Client
gvk schema.GroupVersionKind
groupResource schema.GroupResource
}
func NewRoleController(gvk schema.GroupVersionKind, controllerManager *generic.ControllerManager, clientGetter clientset.RolesGetter, informer informers.RoleInformer) RoleController {
func NewRoleController(gvk schema.GroupVersionKind, resource string, namespaced bool, controller controller.SharedControllerFactory) RoleController {
c := controller.ForResourceKind(gvk.GroupVersion().WithResource(resource), gvk.Kind, namespaced)
return &roleController{
controllerManager: controllerManager,
clientGetter: clientGetter,
informer: informer,
gvk: gvk,
controller: c,
client: c.Client(),
gvk: gvk,
groupResource: schema.GroupResource{
Group: gvk.Group,
Resource: resource,
},
}
}
@@ -132,12 +136,11 @@ func UpdateRoleDeepCopyOnChange(client RoleClient, obj *v1.Role, handler func(ob
}
func (c *roleController) AddGenericHandler(ctx context.Context, name string, handler generic.Handler) {
c.controllerManager.AddHandler(ctx, c.gvk, c.informer.Informer(), name, handler)
c.controller.RegisterHandler(ctx, name, controller.SharedControllerHandlerFunc(handler))
}
func (c *roleController) AddGenericRemoveHandler(ctx context.Context, name string, handler generic.Handler) {
removeHandler := generic.NewRemoveHandler(name, c.Updater(), handler)
c.controllerManager.AddHandler(ctx, c.gvk, c.informer.Informer(), name, removeHandler)
c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), handler))
}
func (c *roleController) OnChange(ctx context.Context, name string, sync RoleHandler) {
@@ -145,20 +148,19 @@ func (c *roleController) OnChange(ctx context.Context, name string, sync RoleHan
}
func (c *roleController) OnRemove(ctx context.Context, name string, sync RoleHandler) {
removeHandler := generic.NewRemoveHandler(name, c.Updater(), FromRoleHandlerToHandler(sync))
c.AddGenericHandler(ctx, name, removeHandler)
c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), FromRoleHandlerToHandler(sync)))
}
func (c *roleController) Enqueue(namespace, name string) {
c.controllerManager.Enqueue(c.gvk, c.informer.Informer(), namespace, name)
c.controller.Enqueue(namespace, name)
}
func (c *roleController) EnqueueAfter(namespace, name string, duration time.Duration) {
c.controllerManager.EnqueueAfter(c.gvk, c.informer.Informer(), namespace, name, duration)
c.controller.EnqueueAfter(namespace, name, duration)
}
func (c *roleController) Informer() cache.SharedIndexInformer {
return c.informer.Informer()
return c.controller.Informer()
}
func (c *roleController) GroupVersionKind() schema.GroupVersionKind {
@@ -167,53 +169,70 @@ func (c *roleController) GroupVersionKind() schema.GroupVersionKind {
func (c *roleController) Cache() RoleCache {
return &roleCache{
lister: c.informer.Lister(),
indexer: c.informer.Informer().GetIndexer(),
indexer: c.Informer().GetIndexer(),
resource: c.groupResource,
}
}
func (c *roleController) Create(obj *v1.Role) (*v1.Role, error) {
return c.clientGetter.Roles(obj.Namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
result := &v1.Role{}
return result, c.client.Create(context.TODO(), obj.Namespace, obj, result, metav1.CreateOptions{})
}
func (c *roleController) Update(obj *v1.Role) (*v1.Role, error) {
return c.clientGetter.Roles(obj.Namespace).Update(context.TODO(), obj, metav1.UpdateOptions{})
result := &v1.Role{}
return result, c.client.Update(context.TODO(), obj.Namespace, obj, result, metav1.UpdateOptions{})
}
func (c *roleController) Delete(namespace, name string, options *metav1.DeleteOptions) error {
if options == nil {
options = &metav1.DeleteOptions{}
}
return c.clientGetter.Roles(namespace).Delete(context.TODO(), name, *options)
return c.client.Delete(context.TODO(), namespace, name, *options)
}
func (c *roleController) Get(namespace, name string, options metav1.GetOptions) (*v1.Role, error) {
return c.clientGetter.Roles(namespace).Get(context.TODO(), name, options)
result := &v1.Role{}
return result, c.client.Get(context.TODO(), namespace, name, result, options)
}
func (c *roleController) List(namespace string, opts metav1.ListOptions) (*v1.RoleList, error) {
return c.clientGetter.Roles(namespace).List(context.TODO(), opts)
result := &v1.RoleList{}
return result, c.client.List(context.TODO(), namespace, result, opts)
}
func (c *roleController) Watch(namespace string, opts metav1.ListOptions) (watch.Interface, error) {
return c.clientGetter.Roles(namespace).Watch(context.TODO(), opts)
return c.client.Watch(context.TODO(), namespace, opts)
}
func (c *roleController) Patch(namespace, name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Role, err error) {
return c.clientGetter.Roles(namespace).Patch(context.TODO(), name, pt, data, metav1.PatchOptions{}, subresources...)
func (c *roleController) Patch(namespace, name string, pt types.PatchType, data []byte, subresources ...string) (*v1.Role, error) {
result := &v1.Role{}
return result, c.client.Patch(context.TODO(), namespace, name, pt, data, result, metav1.PatchOptions{}, subresources...)
}
type roleCache struct {
lister listers.RoleLister
indexer cache.Indexer
indexer cache.Indexer
resource schema.GroupResource
}
func (c *roleCache) Get(namespace, name string) (*v1.Role, error) {
return c.lister.Roles(namespace).Get(name)
obj, exists, err := c.indexer.GetByKey(namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(c.resource, name)
}
return obj.(*v1.Role), nil
}
func (c *roleCache) List(namespace string, selector labels.Selector) ([]*v1.Role, error) {
return c.lister.Roles(namespace).List(selector)
func (c *roleCache) List(namespace string, selector labels.Selector) (ret []*v1.Role, err error) {
err = cache.ListAllByNamespace(c.indexer, namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1.Role))
})
return ret, err
}
func (c *roleCache) AddIndexer(indexName string, indexer RoleIndexer) {

View File

@@ -22,9 +22,12 @@ import (
"context"
"time"
"github.com/rancher/lasso/pkg/client"
"github.com/rancher/lasso/pkg/controller"
"github.com/rancher/wrangler/pkg/generic"
v1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
@@ -32,9 +35,6 @@ import (
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/watch"
informers "k8s.io/client-go/informers/rbac/v1"
clientset "k8s.io/client-go/kubernetes/typed/rbac/v1"
listers "k8s.io/client-go/listers/rbac/v1"
"k8s.io/client-go/tools/cache"
)
@@ -74,18 +74,22 @@ type RoleBindingCache interface {
type RoleBindingIndexer func(obj *v1.RoleBinding) ([]string, error)
type roleBindingController struct {
controllerManager *generic.ControllerManager
clientGetter clientset.RoleBindingsGetter
informer informers.RoleBindingInformer
gvk schema.GroupVersionKind
controller controller.SharedController
client *client.Client
gvk schema.GroupVersionKind
groupResource schema.GroupResource
}
func NewRoleBindingController(gvk schema.GroupVersionKind, controllerManager *generic.ControllerManager, clientGetter clientset.RoleBindingsGetter, informer informers.RoleBindingInformer) RoleBindingController {
func NewRoleBindingController(gvk schema.GroupVersionKind, resource string, namespaced bool, controller controller.SharedControllerFactory) RoleBindingController {
c := controller.ForResourceKind(gvk.GroupVersion().WithResource(resource), gvk.Kind, namespaced)
return &roleBindingController{
controllerManager: controllerManager,
clientGetter: clientGetter,
informer: informer,
gvk: gvk,
controller: c,
client: c.Client(),
gvk: gvk,
groupResource: schema.GroupResource{
Group: gvk.Group,
Resource: resource,
},
}
}
@@ -132,12 +136,11 @@ func UpdateRoleBindingDeepCopyOnChange(client RoleBindingClient, obj *v1.RoleBin
}
func (c *roleBindingController) AddGenericHandler(ctx context.Context, name string, handler generic.Handler) {
c.controllerManager.AddHandler(ctx, c.gvk, c.informer.Informer(), name, handler)
c.controller.RegisterHandler(ctx, name, controller.SharedControllerHandlerFunc(handler))
}
func (c *roleBindingController) AddGenericRemoveHandler(ctx context.Context, name string, handler generic.Handler) {
removeHandler := generic.NewRemoveHandler(name, c.Updater(), handler)
c.controllerManager.AddHandler(ctx, c.gvk, c.informer.Informer(), name, removeHandler)
c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), handler))
}
func (c *roleBindingController) OnChange(ctx context.Context, name string, sync RoleBindingHandler) {
@@ -145,20 +148,19 @@ func (c *roleBindingController) OnChange(ctx context.Context, name string, sync
}
func (c *roleBindingController) OnRemove(ctx context.Context, name string, sync RoleBindingHandler) {
removeHandler := generic.NewRemoveHandler(name, c.Updater(), FromRoleBindingHandlerToHandler(sync))
c.AddGenericHandler(ctx, name, removeHandler)
c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), FromRoleBindingHandlerToHandler(sync)))
}
func (c *roleBindingController) Enqueue(namespace, name string) {
c.controllerManager.Enqueue(c.gvk, c.informer.Informer(), namespace, name)
c.controller.Enqueue(namespace, name)
}
func (c *roleBindingController) EnqueueAfter(namespace, name string, duration time.Duration) {
c.controllerManager.EnqueueAfter(c.gvk, c.informer.Informer(), namespace, name, duration)
c.controller.EnqueueAfter(namespace, name, duration)
}
func (c *roleBindingController) Informer() cache.SharedIndexInformer {
return c.informer.Informer()
return c.controller.Informer()
}
func (c *roleBindingController) GroupVersionKind() schema.GroupVersionKind {
@@ -167,53 +169,70 @@ func (c *roleBindingController) GroupVersionKind() schema.GroupVersionKind {
func (c *roleBindingController) Cache() RoleBindingCache {
return &roleBindingCache{
lister: c.informer.Lister(),
indexer: c.informer.Informer().GetIndexer(),
indexer: c.Informer().GetIndexer(),
resource: c.groupResource,
}
}
func (c *roleBindingController) Create(obj *v1.RoleBinding) (*v1.RoleBinding, error) {
return c.clientGetter.RoleBindings(obj.Namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
result := &v1.RoleBinding{}
return result, c.client.Create(context.TODO(), obj.Namespace, obj, result, metav1.CreateOptions{})
}
func (c *roleBindingController) Update(obj *v1.RoleBinding) (*v1.RoleBinding, error) {
return c.clientGetter.RoleBindings(obj.Namespace).Update(context.TODO(), obj, metav1.UpdateOptions{})
result := &v1.RoleBinding{}
return result, c.client.Update(context.TODO(), obj.Namespace, obj, result, metav1.UpdateOptions{})
}
func (c *roleBindingController) Delete(namespace, name string, options *metav1.DeleteOptions) error {
if options == nil {
options = &metav1.DeleteOptions{}
}
return c.clientGetter.RoleBindings(namespace).Delete(context.TODO(), name, *options)
return c.client.Delete(context.TODO(), namespace, name, *options)
}
func (c *roleBindingController) Get(namespace, name string, options metav1.GetOptions) (*v1.RoleBinding, error) {
return c.clientGetter.RoleBindings(namespace).Get(context.TODO(), name, options)
result := &v1.RoleBinding{}
return result, c.client.Get(context.TODO(), namespace, name, result, options)
}
func (c *roleBindingController) List(namespace string, opts metav1.ListOptions) (*v1.RoleBindingList, error) {
return c.clientGetter.RoleBindings(namespace).List(context.TODO(), opts)
result := &v1.RoleBindingList{}
return result, c.client.List(context.TODO(), namespace, result, opts)
}
func (c *roleBindingController) Watch(namespace string, opts metav1.ListOptions) (watch.Interface, error) {
return c.clientGetter.RoleBindings(namespace).Watch(context.TODO(), opts)
return c.client.Watch(context.TODO(), namespace, opts)
}
func (c *roleBindingController) Patch(namespace, name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.RoleBinding, err error) {
return c.clientGetter.RoleBindings(namespace).Patch(context.TODO(), name, pt, data, metav1.PatchOptions{}, subresources...)
func (c *roleBindingController) Patch(namespace, name string, pt types.PatchType, data []byte, subresources ...string) (*v1.RoleBinding, error) {
result := &v1.RoleBinding{}
return result, c.client.Patch(context.TODO(), namespace, name, pt, data, result, metav1.PatchOptions{}, subresources...)
}
type roleBindingCache struct {
lister listers.RoleBindingLister
indexer cache.Indexer
indexer cache.Indexer
resource schema.GroupResource
}
func (c *roleBindingCache) Get(namespace, name string) (*v1.RoleBinding, error) {
return c.lister.RoleBindings(namespace).Get(name)
obj, exists, err := c.indexer.GetByKey(namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(c.resource, name)
}
return obj.(*v1.RoleBinding), nil
}
func (c *roleBindingCache) List(namespace string, selector labels.Selector) ([]*v1.RoleBinding, error) {
return c.lister.RoleBindings(namespace).List(selector)
func (c *roleBindingCache) List(namespace string, selector labels.Selector) (ret []*v1.RoleBinding, err error) {
err = cache.ListAllByNamespace(c.indexer, namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1.RoleBinding))
})
return ret, err
}
func (c *roleBindingCache) AddIndexer(indexName string, indexer RoleBindingIndexer) {

283
vendor/github.com/rancher/wrangler/pkg/apply/apply.go generated vendored Normal file
View File

@@ -0,0 +1,283 @@
package apply
import (
"context"
"fmt"
"sync"
"github.com/rancher/wrangler/pkg/apply/injectors"
"github.com/rancher/wrangler/pkg/objectset"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
)
const (
defaultNamespace = "default"
)
type Patcher func(namespace, name string, pt types.PatchType, data []byte) (runtime.Object, error)
// return false if the Reconciler did not handler this object
type Reconciler func(oldObj runtime.Object, newObj runtime.Object) (bool, error)
type ClientFactory func(gvr schema.GroupVersionResource) (dynamic.NamespaceableResourceInterface, error)
type InformerFactory interface {
Get(gvk schema.GroupVersionKind, gvr schema.GroupVersionResource) (cache.SharedIndexInformer, error)
}
type InformerGetter interface {
Informer() cache.SharedIndexInformer
GroupVersionKind() schema.GroupVersionKind
}
type PatchByGVK map[schema.GroupVersionKind]map[objectset.ObjectKey]string
func (p PatchByGVK) Add(gvk schema.GroupVersionKind, namespace, name, patch string) {
d, ok := p[gvk]
if !ok {
d = map[objectset.ObjectKey]string{}
p[gvk] = d
}
d[objectset.ObjectKey{
Name: name,
Namespace: namespace,
}] = patch
}
type Plan struct {
Create objectset.ObjectKeyByGVK
Delete objectset.ObjectKeyByGVK
Update PatchByGVK
Objects []runtime.Object
}
type Apply interface {
Apply(set *objectset.ObjectSet) error
ApplyObjects(objs ...runtime.Object) error
WithContext(ctx context.Context) Apply
WithCacheTypes(igs ...InformerGetter) Apply
WithCacheTypeFactory(factory InformerFactory) Apply
WithSetID(id string) Apply
WithOwner(obj runtime.Object) Apply
WithOwnerKey(key string, gvk schema.GroupVersionKind) Apply
WithInjector(injs ...injectors.ConfigInjector) Apply
WithInjectorName(injs ...string) Apply
WithPatcher(gvk schema.GroupVersionKind, patchers Patcher) Apply
WithReconciler(gvk schema.GroupVersionKind, reconciler Reconciler) Apply
WithStrictCaching() Apply
WithDynamicLookup() Apply
WithRestrictClusterScoped() Apply
WithDefaultNamespace(ns string) Apply
WithListerNamespace(ns string) Apply
WithRateLimiting(ratelimitingQps float32) Apply
WithNoDelete() Apply
WithGVK(gvks ...schema.GroupVersionKind) Apply
WithSetOwnerReference(controller, block bool) Apply
FindOwner(obj runtime.Object) (runtime.Object, error)
PurgeOrphan(obj runtime.Object) error
DryRun(objs ...runtime.Object) (Plan, error)
}
func NewForConfig(cfg *rest.Config) (Apply, error) {
k8s, err := kubernetes.NewForConfig(cfg)
if err != nil {
return nil, err
}
return New(k8s.Discovery(), NewClientFactory(cfg)), nil
}
func New(discovery discovery.DiscoveryInterface, cf ClientFactory, igs ...InformerGetter) Apply {
a := &apply{
clients: &clients{
clientFactory: cf,
discovery: discovery,
namespaced: map[schema.GroupVersionKind]bool{},
gvkToGVR: map[schema.GroupVersionKind]schema.GroupVersionResource{},
clients: map[schema.GroupVersionKind]dynamic.NamespaceableResourceInterface{},
},
informers: map[schema.GroupVersionKind]cache.SharedIndexInformer{},
}
for _, ig := range igs {
a.informers[ig.GroupVersionKind()] = ig.Informer()
}
return a
}
type apply struct {
clients *clients
informers map[schema.GroupVersionKind]cache.SharedIndexInformer
}
type clients struct {
sync.Mutex
clientFactory ClientFactory
discovery discovery.DiscoveryInterface
namespaced map[schema.GroupVersionKind]bool
gvkToGVR map[schema.GroupVersionKind]schema.GroupVersionResource
clients map[schema.GroupVersionKind]dynamic.NamespaceableResourceInterface
}
func (c *clients) IsNamespaced(gvk schema.GroupVersionKind) bool {
c.Lock()
defer c.Unlock()
return c.namespaced[gvk]
}
func (c *clients) gvr(gvk schema.GroupVersionKind) schema.GroupVersionResource {
c.Lock()
defer c.Unlock()
return c.gvkToGVR[gvk]
}
func (c *clients) client(gvk schema.GroupVersionKind) (dynamic.NamespaceableResourceInterface, error) {
c.Lock()
defer c.Unlock()
if client, ok := c.clients[gvk]; ok {
return client, nil
}
resources, err := c.discovery.ServerResourcesForGroupVersion(gvk.GroupVersion().String())
if err != nil {
return nil, err
}
for _, resource := range resources.APIResources {
if resource.Kind != gvk.Kind {
continue
}
client, err := c.clientFactory(gvk.GroupVersion().WithResource(resource.Name))
if err != nil {
return nil, err
}
c.namespaced[gvk] = resource.Namespaced
c.clients[gvk] = client
c.gvkToGVR[gvk] = gvk.GroupVersion().WithResource(resource.Name)
return client, nil
}
return nil, fmt.Errorf("failed to discover client for %s", gvk)
}
func (a *apply) newDesiredSet() desiredSet {
return desiredSet{
a: a,
defaultNamespace: defaultNamespace,
ctx: context.Background(),
ratelimitingQps: 1,
reconcilers: defaultReconcilers,
strictCaching: true,
}
}
func (a *apply) DryRun(objs ...runtime.Object) (Plan, error) {
return a.newDesiredSet().DryRun(objs...)
}
func (a *apply) Apply(set *objectset.ObjectSet) error {
return a.newDesiredSet().Apply(set)
}
func (a *apply) ApplyObjects(objs ...runtime.Object) error {
os := objectset.NewObjectSet()
os.Add(objs...)
return a.newDesiredSet().Apply(os)
}
func (a *apply) WithSetID(id string) Apply {
return a.newDesiredSet().WithSetID(id)
}
func (a *apply) WithOwner(obj runtime.Object) Apply {
return a.newDesiredSet().WithOwner(obj)
}
func (a *apply) WithOwnerKey(key string, gvk schema.GroupVersionKind) Apply {
return a.newDesiredSet().WithOwnerKey(key, gvk)
}
func (a *apply) WithInjector(injs ...injectors.ConfigInjector) Apply {
return a.newDesiredSet().WithInjector(injs...)
}
func (a *apply) WithInjectorName(injs ...string) Apply {
return a.newDesiredSet().WithInjectorName(injs...)
}
func (a *apply) WithCacheTypes(igs ...InformerGetter) Apply {
return a.newDesiredSet().WithCacheTypes(igs...)
}
func (a *apply) WithCacheTypeFactory(factory InformerFactory) Apply {
return a.newDesiredSet().WithCacheTypeFactory(factory)
}
func (a *apply) WithGVK(gvks ...schema.GroupVersionKind) Apply {
return a.newDesiredSet().WithGVK(gvks...)
}
func (a *apply) WithPatcher(gvk schema.GroupVersionKind, patcher Patcher) Apply {
return a.newDesiredSet().WithPatcher(gvk, patcher)
}
func (a *apply) WithReconciler(gvk schema.GroupVersionKind, reconciler Reconciler) Apply {
return a.newDesiredSet().WithReconciler(gvk, reconciler)
}
func (a *apply) WithStrictCaching() Apply {
return a.newDesiredSet().WithStrictCaching()
}
func (a *apply) WithDynamicLookup() Apply {
return a.newDesiredSet().WithDynamicLookup()
}
func (a *apply) WithRestrictClusterScoped() Apply {
return a.newDesiredSet().WithRestrictClusterScoped()
}
func (a *apply) WithDefaultNamespace(ns string) Apply {
return a.newDesiredSet().WithDefaultNamespace(ns)
}
func (a *apply) WithListerNamespace(ns string) Apply {
return a.newDesiredSet().WithListerNamespace(ns)
}
func (a *apply) WithRateLimiting(ratelimitingQps float32) Apply {
return a.newDesiredSet().WithRateLimiting(ratelimitingQps)
}
func (a *apply) WithNoDelete() Apply {
return a.newDesiredSet().WithNoDelete()
}
func (a *apply) WithSetOwnerReference(controller, block bool) Apply {
return a.newDesiredSet().WithSetOwnerReference(controller, block)
}
func (a *apply) WithContext(ctx context.Context) Apply {
return a.newDesiredSet().WithContext(ctx)
}
func (a *apply) FindOwner(obj runtime.Object) (runtime.Object, error) {
return a.newDesiredSet().FindOwner(obj)
}
func (a *apply) PurgeOrphan(obj runtime.Object) error {
return a.newDesiredSet().PurgeOrphan(obj)
}

View File

@@ -0,0 +1,18 @@
package apply
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
)
func NewClientFactory(config *rest.Config) ClientFactory {
return func(gvr schema.GroupVersionResource) (dynamic.NamespaceableResourceInterface, error) {
client, err := dynamic.NewForConfig(config)
if err != nil {
return nil, err
}
return client.Resource(gvr), nil
}
}

View File

@@ -0,0 +1,201 @@
package apply
import (
"context"
"github.com/rancher/wrangler/pkg/apply/injectors"
"github.com/rancher/wrangler/pkg/kv"
"github.com/rancher/wrangler/pkg/merr"
"github.com/rancher/wrangler/pkg/objectset"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/tools/cache"
)
type desiredSet struct {
a *apply
ctx context.Context
defaultNamespace string
listerNamespace string
setOwnerReference bool
ownerReferenceController bool
ownerReferenceBlock bool
strictCaching bool
restrictClusterScoped bool
pruneTypes map[schema.GroupVersionKind]cache.SharedIndexInformer
patchers map[schema.GroupVersionKind]Patcher
reconcilers map[schema.GroupVersionKind]Reconciler
informerFactory InformerFactory
remove bool
noDelete bool
setID string
objs *objectset.ObjectSet
codeVersion string
owner runtime.Object
injectors []injectors.ConfigInjector
ratelimitingQps float32
injectorNames []string
errs []error
createPlan bool
plan Plan
}
func (o *desiredSet) err(err error) error {
o.errs = append(o.errs, err)
return o.Err()
}
func (o desiredSet) Err() error {
return merr.NewErrors(append(o.errs, o.objs.Err())...)
}
func (o desiredSet) DryRun(objs ...runtime.Object) (Plan, error) {
o.objs = objectset.NewObjectSet()
o.objs.Add(objs...)
return o.dryRun()
}
func (o desiredSet) Apply(set *objectset.ObjectSet) error {
if set == nil {
set = objectset.NewObjectSet()
}
o.objs = set
return o.apply()
}
func (o desiredSet) ApplyObjects(objs ...runtime.Object) error {
os := objectset.NewObjectSet()
os.Add(objs...)
return o.Apply(os)
}
// WithGVK uses a known listing of existing gvks to modify the the prune types to allow for deletion of objects
func (o desiredSet) WithGVK(gvks ...schema.GroupVersionKind) Apply {
pruneTypes := make(map[schema.GroupVersionKind]cache.SharedIndexInformer, len(gvks))
for k, v := range o.pruneTypes {
pruneTypes[k] = v
}
for _, gvk := range gvks {
pruneTypes[gvk] = nil
}
o.pruneTypes = pruneTypes
return o
}
func (o desiredSet) WithSetID(id string) Apply {
o.setID = id
return o
}
func (o desiredSet) WithOwnerKey(key string, gvk schema.GroupVersionKind) Apply {
obj := &v1.PartialObjectMetadata{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
obj.SetGroupVersionKind(gvk)
o.owner = obj
return o
}
func (o desiredSet) WithOwner(obj runtime.Object) Apply {
o.owner = obj
return o
}
func (o desiredSet) WithSetOwnerReference(controller, block bool) Apply {
o.setOwnerReference = true
o.ownerReferenceController = controller
o.ownerReferenceBlock = block
return o
}
func (o desiredSet) WithInjector(injs ...injectors.ConfigInjector) Apply {
o.injectors = append(o.injectors, injs...)
return o
}
func (o desiredSet) WithInjectorName(injs ...string) Apply {
o.injectorNames = append(o.injectorNames, injs...)
return o
}
func (o desiredSet) WithCacheTypeFactory(factory InformerFactory) Apply {
o.informerFactory = factory
return o
}
func (o desiredSet) WithCacheTypes(igs ...InformerGetter) Apply {
pruneTypes := make(map[schema.GroupVersionKind]cache.SharedIndexInformer, len(igs))
for k, v := range o.pruneTypes {
pruneTypes[k] = v
}
for _, ig := range igs {
pruneTypes[ig.GroupVersionKind()] = ig.Informer()
}
o.pruneTypes = pruneTypes
return o
}
func (o desiredSet) WithPatcher(gvk schema.GroupVersionKind, patcher Patcher) Apply {
patchers := map[schema.GroupVersionKind]Patcher{}
for k, v := range o.patchers {
patchers[k] = v
}
patchers[gvk] = patcher
o.patchers = patchers
return o
}
func (o desiredSet) WithReconciler(gvk schema.GroupVersionKind, reconciler Reconciler) Apply {
reconcilers := map[schema.GroupVersionKind]Reconciler{}
for k, v := range o.reconcilers {
reconcilers[k] = v
}
reconcilers[gvk] = reconciler
o.reconcilers = reconcilers
return o
}
func (o desiredSet) WithStrictCaching() Apply {
o.strictCaching = true
return o
}
func (o desiredSet) WithDynamicLookup() Apply {
o.strictCaching = false
return o
}
func (o desiredSet) WithRestrictClusterScoped() Apply {
o.restrictClusterScoped = true
return o
}
func (o desiredSet) WithDefaultNamespace(ns string) Apply {
if ns == "" {
o.defaultNamespace = defaultNamespace
} else {
o.defaultNamespace = ns
}
return o
}
func (o desiredSet) WithListerNamespace(ns string) Apply {
o.listerNamespace = ns
return o
}
func (o desiredSet) WithRateLimiting(ratelimitingQps float32) Apply {
o.ratelimitingQps = ratelimitingQps
return o
}
func (o desiredSet) WithNoDelete() Apply {
o.noDelete = true
return o
}
func (o desiredSet) WithContext(ctx context.Context) Apply {
o.ctx = ctx
return o
}

View File

@@ -0,0 +1,264 @@
package apply
import (
"crypto/sha1"
"encoding/hex"
"fmt"
"sync"
"time"
"github.com/sirupsen/logrus"
gvk2 "github.com/rancher/wrangler/pkg/gvk"
"github.com/pkg/errors"
"github.com/rancher/wrangler/pkg/apply/injectors"
"github.com/rancher/wrangler/pkg/objectset"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/client-go/util/flowcontrol"
)
const (
LabelID = "objectset.rio.cattle.io/id"
LabelGVK = "objectset.rio.cattle.io/owner-gvk"
LabelName = "objectset.rio.cattle.io/owner-name"
LabelNamespace = "objectset.rio.cattle.io/owner-namespace"
LabelHash = "objectset.rio.cattle.io/hash"
LabelPrefix = "objectset.rio.cattle.io/"
)
var (
hashOrder = []string{
LabelID,
LabelGVK,
LabelName,
LabelNamespace,
}
rls = map[string]flowcontrol.RateLimiter{}
rlsLock sync.Mutex
)
func (o *desiredSet) getRateLimit(labelHash string) flowcontrol.RateLimiter {
var rl flowcontrol.RateLimiter
rlsLock.Lock()
defer rlsLock.Unlock()
if o.remove {
delete(rls, labelHash)
} else {
rl = rls[labelHash]
if rl == nil {
rl = flowcontrol.NewTokenBucketRateLimiter(o.ratelimitingQps, 10)
rls[labelHash] = rl
}
}
return rl
}
func (o *desiredSet) dryRun() (Plan, error) {
o.createPlan = true
o.plan.Create = objectset.ObjectKeyByGVK{}
o.plan.Update = PatchByGVK{}
o.plan.Delete = objectset.ObjectKeyByGVK{}
err := o.apply()
return o.plan, err
}
func (o *desiredSet) apply() error {
if o.objs == nil || o.objs.Len() == 0 {
o.remove = true
}
if err := o.Err(); err != nil {
return err
}
labelSet, annotationSet, err := GetLabelsAndAnnotations(o.setID, o.owner)
if err != nil {
return o.err(err)
}
rl := o.getRateLimit(labelSet[LabelHash])
if rl != nil {
t := time.Now()
rl.Accept()
if d := time.Now().Sub(t); d.Seconds() > 1 {
logrus.Infof("rate limited %s(%s) %s", o.setID, labelSet, d)
}
}
objList, err := o.injectLabelsAndAnnotations(labelSet, annotationSet)
if err != nil {
return o.err(err)
}
objList, err = o.runInjectors(objList)
if err != nil {
return o.err(err)
}
objs := o.collect(objList)
debugID := o.debugID()
sel, err := GetSelector(labelSet)
if err != nil {
return o.err(err)
}
for _, gvk := range o.objs.GVKOrder(o.knownGVK()...) {
o.process(debugID, sel, gvk, objs[gvk])
}
return o.Err()
}
func (o *desiredSet) knownGVK() (ret []schema.GroupVersionKind) {
for k := range o.pruneTypes {
ret = append(ret, k)
}
return
}
func (o *desiredSet) debugID() string {
if o.owner == nil {
return o.setID
}
metadata, err := meta.Accessor(o.owner)
if err != nil {
return o.setID
}
return fmt.Sprintf("%s %s", o.setID, objectset.ObjectKey{
Namespace: metadata.GetNamespace(),
Name: metadata.GetName(),
})
}
func (o *desiredSet) collect(objList []runtime.Object) objectset.ObjectByGVK {
result := objectset.ObjectByGVK{}
for _, obj := range objList {
result.Add(obj)
}
return result
}
func (o *desiredSet) runInjectors(objList []runtime.Object) ([]runtime.Object, error) {
var err error
for _, inj := range o.injectors {
if inj == nil {
continue
}
objList, err = inj(objList)
if err != nil {
return nil, err
}
}
for _, name := range o.injectorNames {
inj := injectors.Get(name)
if inj == nil {
continue
}
objList, err = inj(objList)
if err != nil {
return nil, err
}
}
return objList, nil
}
func GetSelector(labelSet map[string]string) (labels.Selector, error) {
req, err := labels.NewRequirement(LabelHash, selection.Equals, []string{labelSet[LabelHash]})
if err != nil {
return nil, err
}
return labels.NewSelector().Add(*req), nil
}
func GetLabelsAndAnnotations(setID string, owner runtime.Object) (map[string]string, map[string]string, error) {
annotations := map[string]string{
LabelID: setID,
}
if owner != nil {
gvk, err := gvk2.Get(owner)
if err != nil {
return nil, nil, err
}
annotations[LabelGVK] = gvk.String()
metadata, err := meta.Accessor(owner)
if err != nil {
return nil, nil, fmt.Errorf("failed to get metadata for %s", gvk)
}
annotations[LabelName] = metadata.GetName()
annotations[LabelNamespace] = metadata.GetNamespace()
}
labels := map[string]string{
LabelHash: objectSetHash(annotations),
}
return labels, annotations, nil
}
func (o *desiredSet) injectLabelsAndAnnotations(labels, annotations map[string]string) ([]runtime.Object, error) {
var result []runtime.Object
for _, objMap := range o.objs.ObjectsByGVK() {
for key, obj := range objMap {
obj = obj.DeepCopyObject()
meta, err := meta.Accessor(obj)
if err != nil {
return nil, errors.Wrapf(err, "failed to get metadata for %s", key)
}
setLabels(meta, labels)
setAnnotations(meta, annotations)
result = append(result, obj)
}
}
return result, nil
}
func setAnnotations(meta metav1.Object, annotations map[string]string) {
objAnn := meta.GetAnnotations()
if objAnn == nil {
objAnn = map[string]string{}
}
delete(objAnn, LabelApplied)
for k, v := range annotations {
objAnn[k] = v
}
meta.SetAnnotations(objAnn)
}
func setLabels(meta metav1.Object, labels map[string]string) {
objLabels := meta.GetLabels()
if objLabels == nil {
objLabels = map[string]string{}
}
for k, v := range labels {
objLabels[k] = v
}
meta.SetLabels(objLabels)
}
func objectSetHash(labels map[string]string) string {
dig := sha1.New()
for _, key := range hashOrder {
dig.Write([]byte(labels[key]))
}
return hex.EncodeToString(dig.Sum(nil))
}

View File

@@ -0,0 +1,336 @@
package apply
import (
"bytes"
"compress/gzip"
"encoding/base64"
"io/ioutil"
"strings"
data2 "github.com/rancher/wrangler/pkg/data"
"github.com/pkg/errors"
"github.com/rancher/wrangler/pkg/data/convert"
patch2 "github.com/rancher/wrangler/pkg/patch"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/meta"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/jsonmergepatch"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/client-go/dynamic"
)
const (
LabelApplied = "objectset.rio.cattle.io/applied"
)
func prepareObjectForCreate(gvk schema.GroupVersionKind, obj runtime.Object) (runtime.Object, error) {
serialized, err := json.Marshal(obj)
if err != nil {
return nil, err
}
obj = obj.DeepCopyObject()
m, err := meta.Accessor(obj)
if err != nil {
return nil, err
}
annotations := m.GetAnnotations()
if annotations == nil {
annotations = map[string]string{}
}
annotations[LabelApplied] = appliedToAnnotation(serialized)
m.SetAnnotations(annotations)
typed, err := meta.TypeAccessor(obj)
if err != nil {
return nil, err
}
apiVersion, kind := gvk.ToAPIVersionAndKind()
typed.SetAPIVersion(apiVersion)
typed.SetKind(kind)
return obj, nil
}
func originalAndModified(gvk schema.GroupVersionKind, oldMetadata v1.Object, newObject runtime.Object) ([]byte, []byte, error) {
original, err := getOriginalBytes(gvk, oldMetadata)
if err != nil {
return nil, nil, err
}
newObject, err = prepareObjectForCreate(gvk, newObject)
if err != nil {
return nil, nil, err
}
modified, err := json.Marshal(newObject)
return original, modified, err
}
func emptyMaps(data map[string]interface{}, keys ...string) bool {
for _, key := range append(keys, "__invalid_key__") {
if len(data) == 0 {
// map is empty so all children are empty too
return true
} else if len(data) > 1 {
// map has more than one key so not empty
return false
}
value, ok := data[key]
if !ok {
// map has one key but not what we are expecting so not considered empty
return false
}
data = convert.ToMapInterface(value)
}
return true
}
func sanitizePatch(patch []byte, removeObjectSetAnnotation bool) ([]byte, error) {
mod := false
data := map[string]interface{}{}
err := json.Unmarshal(patch, &data)
if err != nil {
return nil, err
}
if _, ok := data["kind"]; ok {
mod = true
delete(data, "kind")
}
if _, ok := data["apiVersion"]; ok {
mod = true
delete(data, "apiVersion")
}
if deleted := removeCreationTimestamp(data); deleted {
mod = true
}
if removeObjectSetAnnotation {
metadata := convert.ToMapInterface(data2.GetValueN(data, "metadata"))
annotations := convert.ToMapInterface(data2.GetValueN(data, "metadata", "annotations"))
for k := range annotations {
if strings.HasPrefix(k, LabelPrefix) {
mod = true
delete(annotations, k)
}
}
if mod && len(annotations) == 0 {
delete(metadata, "annotations")
if len(metadata) == 0 {
delete(data, "metadata")
}
}
}
if emptyMaps(data, "metadata", "annotations") {
return []byte("{}"), nil
}
if !mod {
return patch, nil
}
return json.Marshal(data)
}
func applyPatch(gvk schema.GroupVersionKind, reconciler Reconciler, patcher Patcher, debugID string, oldObject, newObject runtime.Object) (bool, error) {
oldMetadata, err := meta.Accessor(oldObject)
if err != nil {
return false, err
}
original, modified, err := originalAndModified(gvk, oldMetadata, newObject)
if err != nil {
return false, err
}
current, err := json.Marshal(oldObject)
if err != nil {
return false, err
}
patchType, patch, err := doPatch(gvk, original, modified, current)
if err != nil {
return false, errors.Wrap(err, "patch generation")
}
if string(patch) == "{}" {
return false, nil
}
patch, err = sanitizePatch(patch, false)
if err != nil {
return false, err
}
if string(patch) == "{}" {
return false, nil
}
logrus.Debugf("DesiredSet - Patch %s %s/%s for %s -- [%s, %s, %s, %s]", gvk, oldMetadata.GetNamespace(), oldMetadata.GetName(), debugID, patch, original, modified, current)
if reconciler != nil {
newObject, err := prepareObjectForCreate(gvk, newObject)
if err != nil {
return false, err
}
originalObject, err := getOriginalObject(gvk, oldMetadata)
if err != nil {
return false, err
}
if originalObject == nil {
originalObject = oldObject
}
handled, err := reconciler(originalObject, newObject)
if err != nil {
return false, err
}
if handled {
return true, nil
}
}
logrus.Debugf("DesiredSet - Updated %s %s/%s for %s -- %s %s", gvk, oldMetadata.GetNamespace(), oldMetadata.GetName(), debugID, patchType, patch)
_, err = patcher(oldMetadata.GetNamespace(), oldMetadata.GetName(), patchType, patch)
return true, err
}
func (o *desiredSet) compareObjects(gvk schema.GroupVersionKind, reconciler Reconciler, patcher Patcher, client dynamic.NamespaceableResourceInterface, debugID string, oldObject, newObject runtime.Object, force bool) error {
oldMetadata, err := meta.Accessor(oldObject)
if err != nil {
return err
}
if o.createPlan {
o.plan.Objects = append(o.plan.Objects, oldObject)
}
if ran, err := applyPatch(gvk, reconciler, patcher, debugID, oldObject, newObject); err != nil {
return err
} else if !ran {
logrus.Debugf("DesiredSet - No change(2) %s %s/%s for %s", gvk, oldMetadata.GetNamespace(), oldMetadata.GetName(), debugID)
}
return nil
}
func removeCreationTimestamp(data map[string]interface{}) bool {
metadata, ok := data["metadata"]
if !ok {
return false
}
data = convert.ToMapInterface(metadata)
if _, ok := data["creationTimestamp"]; ok {
delete(data, "creationTimestamp")
return true
}
return false
}
func getOriginalObject(gvk schema.GroupVersionKind, obj v1.Object) (runtime.Object, error) {
original := appliedFromAnnotation(obj.GetAnnotations()[LabelApplied])
if len(original) == 0 {
return nil, nil
}
mapObj := map[string]interface{}{}
err := json.Unmarshal(original, &mapObj)
if err != nil {
return nil, err
}
removeCreationTimestamp(mapObj)
return prepareObjectForCreate(gvk, &unstructured.Unstructured{
Object: mapObj,
})
}
func getOriginalBytes(gvk schema.GroupVersionKind, obj v1.Object) ([]byte, error) {
objCopy, err := getOriginalObject(gvk, obj)
if err != nil {
return nil, err
}
if objCopy == nil {
return []byte("{}"), nil
}
return json.Marshal(objCopy)
}
func appliedFromAnnotation(str string) []byte {
if len(str) == 0 || str[0] == '{' {
return []byte(str)
}
b, err := base64.RawStdEncoding.DecodeString(str)
if err != nil {
return nil
}
r, err := gzip.NewReader(bytes.NewBuffer(b))
if err != nil {
return nil
}
b, err = ioutil.ReadAll(r)
if err != nil {
return nil
}
return b
}
func appliedToAnnotation(b []byte) string {
if len(b) < 1024 {
return string(b)
}
buf := &bytes.Buffer{}
w := gzip.NewWriter(buf)
if _, err := w.Write(b); err != nil {
return string(b)
}
if err := w.Close(); err != nil {
return string(b)
}
return base64.RawStdEncoding.EncodeToString(buf.Bytes())
}
// doPatch is adapted from "kubectl apply"
func doPatch(gvk schema.GroupVersionKind, original, modified, current []byte) (types.PatchType, []byte, error) {
var patchType types.PatchType
var patch []byte
var lookupPatchMeta strategicpatch.LookupPatchMeta
patchType, lookupPatchMeta, err := patch2.GetMergeStyle(gvk)
if err != nil {
return patchType, nil, err
}
if patchType == types.StrategicMergePatchType {
patch, err = strategicpatch.CreateThreeWayMergePatch(original, modified, current, lookupPatchMeta, true)
} else {
patch, err = jsonmergepatch.CreateThreeWayJSONMergePatch(original, modified, current)
}
if err != nil {
logrus.Errorf("Failed to calcuated patch: %v", err)
}
return patchType, patch, err
}

View File

@@ -0,0 +1,66 @@
package apply
import (
"bytes"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/client-go/dynamic"
)
var (
deletePolicy = v1.DeletePropagationBackground
)
func (o *desiredSet) toUnstructured(obj runtime.Object) (*unstructured.Unstructured, error) {
unstruct, ok := obj.(*unstructured.Unstructured)
if ok {
return unstruct, nil
}
buf := &bytes.Buffer{}
if err := json.NewEncoder(buf).Encode(obj); err != nil {
return nil, err
}
unstruct = &unstructured.Unstructured{
Object: map[string]interface{}{},
}
return unstruct, json.Unmarshal(buf.Bytes(), &unstruct.Object)
}
func (o *desiredSet) create(nsed bool, namespace string, client dynamic.NamespaceableResourceInterface, obj runtime.Object) (runtime.Object, error) {
unstr, err := o.toUnstructured(obj)
if err != nil {
return nil, err
}
if nsed {
return client.Namespace(namespace).Create(o.ctx, unstr, v1.CreateOptions{})
}
return client.Create(o.ctx, unstr, v1.CreateOptions{})
}
func (o *desiredSet) get(nsed bool, namespace, name string, client dynamic.NamespaceableResourceInterface) (runtime.Object, error) {
if nsed {
return client.Namespace(namespace).Get(o.ctx, name, v1.GetOptions{})
}
return client.Get(o.ctx, name, v1.GetOptions{})
}
func (o *desiredSet) delete(nsed bool, namespace, name string, client dynamic.NamespaceableResourceInterface, force bool) error {
if o.noDelete && !force {
return nil
}
opts := v1.DeleteOptions{
PropagationPolicy: &deletePolicy,
}
if nsed {
return client.Namespace(namespace).Delete(o.ctx, name, opts)
}
return client.Delete(o.ctx, name, opts)
}

View File

@@ -0,0 +1,152 @@
package apply
import (
"fmt"
"strings"
"github.com/rancher/wrangler/pkg/gvk"
"github.com/rancher/wrangler/pkg/kv"
"github.com/pkg/errors"
namer "github.com/rancher/wrangler/pkg/name"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/cache"
)
var (
ErrOwnerNotFound = errors.New("owner not found")
)
func notFound(name string, gvk schema.GroupVersionKind) error {
// this is not proper, but does it really matter that much? If you find this
// line while researching a bug, then the answer is probably yes.
resource := namer.GuessPluralName(strings.ToLower(gvk.Kind))
return apierrors.NewNotFound(schema.GroupResource{
Group: gvk.Group,
Resource: resource,
}, name)
}
func getGVK(gvkLabel string, gvk *schema.GroupVersionKind) error {
parts := strings.Split(gvkLabel, ", Kind=")
if len(parts) != 2 {
return fmt.Errorf("invalid GVK format: %s", gvkLabel)
}
gvk.Group, gvk.Version = kv.Split(parts[0], "/")
gvk.Kind = parts[1]
return nil
}
func (o desiredSet) FindOwner(obj runtime.Object) (runtime.Object, error) {
if obj == nil {
return nil, ErrOwnerNotFound
}
meta, err := meta.Accessor(obj)
if err != nil {
return nil, err
}
var (
debugID = fmt.Sprintf("%s/%s", meta.GetNamespace(), meta.GetName())
gvkLabel = meta.GetAnnotations()[LabelGVK]
namespace = meta.GetAnnotations()[LabelNamespace]
name = meta.GetAnnotations()[LabelName]
gvk schema.GroupVersionKind
)
if gvkLabel == "" {
return nil, ErrOwnerNotFound
}
if err := getGVK(gvkLabel, &gvk); err != nil {
return nil, err
}
cache, client, err := o.getControllerAndClient(debugID, gvk)
if err != nil {
return nil, err
}
if cache != nil {
return o.fromCache(cache, namespace, name, gvk)
}
return o.fromClient(client, namespace, name, gvk)
}
func (o *desiredSet) fromClient(client dynamic.NamespaceableResourceInterface, namespace, name string, gvk schema.GroupVersionKind) (runtime.Object, error) {
var (
err error
obj interface{}
)
if namespace == "" {
obj, err = client.Get(o.ctx, name, metav1.GetOptions{})
} else {
obj, err = client.Namespace(namespace).Get(o.ctx, name, metav1.GetOptions{})
}
if err != nil {
return nil, err
}
if ro, ok := obj.(runtime.Object); ok {
return ro, nil
}
return nil, notFound(name, gvk)
}
func (o *desiredSet) fromCache(cache cache.SharedInformer, namespace, name string, gvk schema.GroupVersionKind) (runtime.Object, error) {
var key string
if namespace == "" {
key = name
} else {
key = namespace + "/" + name
}
item, ok, err := cache.GetStore().GetByKey(key)
if err != nil {
return nil, err
} else if !ok {
return nil, notFound(name, gvk)
} else if ro, ok := item.(runtime.Object); ok {
return ro, nil
}
return nil, notFound(name, gvk)
}
func (o desiredSet) PurgeOrphan(obj runtime.Object) error {
if obj == nil {
return nil
}
meta, err := meta.Accessor(obj)
if err != nil {
return err
}
if _, err := o.FindOwner(obj); apierrors.IsNotFound(err) {
gvk, err := gvk.Get(obj)
if err != nil {
return err
}
o.strictCaching = false
_, client, err := o.getControllerAndClient(meta.GetName(), gvk)
if err != nil {
return err
}
if meta.GetNamespace() == "" {
return client.Delete(o.ctx, meta.GetName(), metav1.DeleteOptions{})
} else {
return client.Namespace(meta.GetNamespace()).Delete(o.ctx, meta.GetName(), metav1.DeleteOptions{})
}
} else if err == ErrOwnerNotFound {
return nil
} else if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,386 @@
package apply
import (
"fmt"
"sort"
"github.com/pkg/errors"
gvk2 "github.com/rancher/wrangler/pkg/gvk"
"github.com/rancher/wrangler/pkg/merr"
"github.com/rancher/wrangler/pkg/objectset"
"github.com/sirupsen/logrus"
errors2 "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
types2 "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/cache"
)
var (
ErrReplace = errors.New("replace object with changes")
ReplaceOnChange = func(name string, o runtime.Object, patchType types2.PatchType, data []byte, subresources ...string) (runtime.Object, error) {
return nil, ErrReplace
}
)
func (o *desiredSet) getControllerAndClient(debugID string, gvk schema.GroupVersionKind) (cache.SharedIndexInformer, dynamic.NamespaceableResourceInterface, error) {
// client needs to be accessed first so that the gvk->gvr mapping gets cached
client, err := o.a.clients.client(gvk)
if err != nil {
return nil, nil, err
}
informer, ok := o.pruneTypes[gvk]
if !ok {
informer = o.a.informers[gvk]
}
if informer == nil && o.informerFactory != nil {
newInformer, err := o.informerFactory.Get(gvk, o.a.clients.gvr(gvk))
if err != nil {
return nil, nil, errors.Wrapf(err, "failed to construct informer for %v for %s", gvk, debugID)
}
informer = newInformer
}
if informer == nil && o.strictCaching {
return nil, nil, fmt.Errorf("failed to find informer for %s for %s", gvk, debugID)
}
return informer, client, nil
}
func (o *desiredSet) assignOwnerReference(gvk schema.GroupVersionKind, objs map[objectset.ObjectKey]runtime.Object) error {
if o.owner == nil {
return fmt.Errorf("no owner set to assign owner reference")
}
ownerMeta, err := meta.Accessor(o.owner)
if err != nil {
return err
}
ownerGVK, err := gvk2.Get(o.owner)
ownerNSed := o.a.clients.IsNamespaced(ownerGVK)
for k, v := range objs {
// can't set owners across boundaries
if ownerNSed && !o.a.clients.IsNamespaced(gvk) {
continue
}
assignNS := false
assignOwner := true
if o.a.clients.IsNamespaced(gvk) {
if k.Namespace == "" {
assignNS = true
} else if k.Namespace != ownerMeta.GetNamespace() && ownerNSed {
assignOwner = false
}
}
if !assignOwner {
continue
}
v = v.DeepCopyObject()
meta, err := meta.Accessor(v)
if err != nil {
return err
}
if assignNS {
meta.SetNamespace(ownerMeta.GetNamespace())
}
shouldSet := true
for _, of := range meta.GetOwnerReferences() {
if ownerMeta.GetUID() == of.UID {
shouldSet = false
break
}
}
if shouldSet {
meta.SetOwnerReferences(append(meta.GetOwnerReferences(), v1.OwnerReference{
APIVersion: ownerGVK.GroupVersion().String(),
Kind: ownerGVK.Kind,
Name: ownerMeta.GetName(),
UID: ownerMeta.GetUID(),
Controller: &o.ownerReferenceController,
BlockOwnerDeletion: &o.ownerReferenceBlock,
}))
}
objs[k] = v
if assignNS {
delete(objs, k)
k.Namespace = ownerMeta.GetNamespace()
objs[k] = v
}
}
return nil
}
func (o *desiredSet) adjustNamespace(gvk schema.GroupVersionKind, objs map[objectset.ObjectKey]runtime.Object) error {
for k, v := range objs {
if k.Namespace != "" {
continue
}
v = v.DeepCopyObject()
meta, err := meta.Accessor(v)
if err != nil {
return err
}
meta.SetNamespace(o.defaultNamespace)
delete(objs, k)
k.Namespace = o.defaultNamespace
objs[k] = v
}
return nil
}
func (o *desiredSet) clearNamespace(objs map[objectset.ObjectKey]runtime.Object) error {
for k, v := range objs {
if k.Namespace == "" {
continue
}
v = v.DeepCopyObject()
meta, err := meta.Accessor(v)
if err != nil {
return err
}
meta.SetNamespace("")
delete(objs, k)
k.Namespace = ""
objs[k] = v
}
return nil
}
func (o *desiredSet) createPatcher(client dynamic.NamespaceableResourceInterface) Patcher {
return func(namespace, name string, pt types2.PatchType, data []byte) (object runtime.Object, e error) {
if namespace != "" {
return client.Namespace(namespace).Patch(o.ctx, name, pt, data, v1.PatchOptions{})
}
return client.Patch(o.ctx, name, pt, data, v1.PatchOptions{})
}
}
func (o *desiredSet) process(debugID string, set labels.Selector, gvk schema.GroupVersionKind, objs map[objectset.ObjectKey]runtime.Object) {
controller, client, err := o.getControllerAndClient(debugID, gvk)
if err != nil {
o.err(err)
return
}
nsed := o.a.clients.IsNamespaced(gvk)
if !nsed && o.restrictClusterScoped {
o.err(fmt.Errorf("invalid cluster scoped gvk: %v", gvk))
return
}
if o.setOwnerReference {
if err := o.assignOwnerReference(gvk, objs); err != nil {
o.err(err)
return
}
}
if nsed {
if err := o.adjustNamespace(gvk, objs); err != nil {
o.err(err)
return
}
} else {
if err := o.clearNamespace(objs); err != nil {
o.err(err)
return
}
}
patcher, ok := o.patchers[gvk]
if !ok {
patcher = o.createPatcher(client)
}
reconciler := o.reconcilers[gvk]
existing, err := o.list(controller, client, set)
if err != nil {
o.err(errors.Wrapf(err, "failed to list %s for %s", gvk, debugID))
return
}
toCreate, toDelete, toUpdate := compareSets(existing, objs)
if o.createPlan {
o.plan.Create[gvk] = toCreate
o.plan.Delete[gvk] = toDelete
reconciler = nil
patcher = func(namespace, name string, pt types2.PatchType, data []byte) (runtime.Object, error) {
data, err := sanitizePatch(data, true)
if err != nil {
return nil, err
}
if string(data) != "{}" {
o.plan.Update.Add(gvk, namespace, name, string(data))
}
return nil, nil
}
toCreate = nil
toDelete = nil
}
createF := func(k objectset.ObjectKey) {
obj := objs[k]
obj, err := prepareObjectForCreate(gvk, obj)
if err != nil {
o.err(errors.Wrapf(err, "failed to prepare create %s %s for %s", k, gvk, debugID))
return
}
_, err = o.create(nsed, k.Namespace, client, obj)
if errors2.IsAlreadyExists(err) {
// Taking over an object that wasn't previously managed by us
existingObj, err := o.get(nsed, k.Namespace, k.Name, client)
if err == nil {
toUpdate = append(toUpdate, k)
existing[k] = existingObj
return
}
}
if err != nil {
o.err(errors.Wrapf(err, "failed to create %s %s for %s", k, gvk, debugID))
return
}
logrus.Debugf("DesiredSet - Created %s %s for %s", gvk, k, debugID)
}
deleteF := func(k objectset.ObjectKey, force bool) {
if err := o.delete(nsed, k.Namespace, k.Name, client, force); err != nil {
o.err(errors.Wrapf(err, "failed to delete %s %s for %s", k, gvk, debugID))
return
}
logrus.Debugf("DesiredSet - Delete %s %s for %s", gvk, k, debugID)
}
updateF := func(k objectset.ObjectKey) {
err := o.compareObjects(gvk, reconciler, patcher, client, debugID, existing[k], objs[k], len(toCreate) > 0 || len(toDelete) > 0)
if err == ErrReplace {
deleteF(k, true)
o.err(fmt.Errorf("DesiredSet - Replace Wait %s %s for %s", gvk, k, debugID))
} else if err != nil {
o.err(errors.Wrapf(err, "failed to update %s %s for %s", k, gvk, debugID))
}
}
for _, k := range toCreate {
createF(k)
}
for _, k := range toUpdate {
updateF(k)
}
for _, k := range toDelete {
deleteF(k, false)
}
}
func (o *desiredSet) list(informer cache.SharedIndexInformer, client dynamic.NamespaceableResourceInterface, selector labels.Selector) (map[objectset.ObjectKey]runtime.Object, error) {
var (
errs []error
objs = map[objectset.ObjectKey]runtime.Object{}
)
if informer == nil {
var c dynamic.ResourceInterface
if o.listerNamespace != "" {
c = client.Namespace(o.listerNamespace)
} else {
c = client
}
list, err := c.List(o.ctx, v1.ListOptions{
LabelSelector: selector.String(),
})
if err != nil {
return nil, err
}
for _, obj := range list.Items {
copy := obj
if err := addObjectToMap(objs, &copy); err != nil {
errs = append(errs, err)
}
}
return objs, merr.NewErrors(errs...)
}
err := cache.ListAllByNamespace(informer.GetIndexer(), "", selector, func(obj interface{}) {
if err := addObjectToMap(objs, obj); err != nil {
errs = append(errs, err)
}
})
if err != nil {
errs = append(errs, err)
}
return objs, merr.NewErrors(errs...)
}
func compareSets(existingSet, newSet map[objectset.ObjectKey]runtime.Object) (toCreate, toDelete, toUpdate []objectset.ObjectKey) {
for k := range newSet {
if _, ok := existingSet[k]; ok {
toUpdate = append(toUpdate, k)
} else {
toCreate = append(toCreate, k)
}
}
for k := range existingSet {
if _, ok := newSet[k]; !ok {
toDelete = append(toDelete, k)
}
}
sortObjectKeys(toCreate)
sortObjectKeys(toDelete)
sortObjectKeys(toUpdate)
return
}
func sortObjectKeys(keys []objectset.ObjectKey) {
sort.Slice(keys, func(i, j int) bool {
return keys[i].String() < keys[j].String()
})
}
func addObjectToMap(objs map[objectset.ObjectKey]runtime.Object, obj interface{}) error {
metadata, err := meta.Accessor(obj)
if err != nil {
return err
}
objs[objectset.ObjectKey{
Namespace: metadata.GetNamespace(),
Name: metadata.GetName(),
}] = obj.(runtime.Object)
return nil
}

View File

@@ -0,0 +1,21 @@
package injectors
import "k8s.io/apimachinery/pkg/runtime"
var (
injectors = map[string]ConfigInjector{}
order []string
)
type ConfigInjector func(config []runtime.Object) ([]runtime.Object, error)
func Register(name string, injector ConfigInjector) {
if _, ok := injectors[name]; !ok {
order = append(order, name)
}
injectors[name] = injector
}
func Get(name string) ConfigInjector {
return injectors[name]
}

View File

@@ -0,0 +1,130 @@
package apply
import (
"encoding/json"
"fmt"
"reflect"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
var (
defaultReconcilers = map[schema.GroupVersionKind]Reconciler{
v1.SchemeGroupVersion.WithKind("Service"): reconcileService,
batchv1.SchemeGroupVersion.WithKind("Job"): reconcileJob,
appsv1.SchemeGroupVersion.WithKind("Deployment"): reconcileDeployment,
appsv1.SchemeGroupVersion.WithKind("DaemonSet"): reconcileDaemonSet,
}
)
func reconcileDaemonSet(oldObj, newObj runtime.Object) (bool, error) {
oldSvc, ok := oldObj.(*appsv1.DaemonSet)
if !ok {
oldSvc = &appsv1.DaemonSet{}
if err := convertObj(oldObj, oldSvc); err != nil {
return false, err
}
}
newSvc, ok := newObj.(*appsv1.DaemonSet)
if !ok {
newSvc = &appsv1.DaemonSet{}
if err := convertObj(newObj, newSvc); err != nil {
return false, err
}
}
if !equality.Semantic.DeepEqual(oldSvc.Spec.Selector, newSvc.Spec.Selector) {
return false, ErrReplace
}
return false, nil
}
func reconcileDeployment(oldObj, newObj runtime.Object) (bool, error) {
oldSvc, ok := oldObj.(*appsv1.Deployment)
if !ok {
oldSvc = &appsv1.Deployment{}
if err := convertObj(oldObj, oldSvc); err != nil {
return false, err
}
}
newSvc, ok := newObj.(*appsv1.Deployment)
if !ok {
newSvc = &appsv1.Deployment{}
if err := convertObj(newObj, newSvc); err != nil {
return false, err
}
}
if !equality.Semantic.DeepEqual(oldSvc.Spec.Selector, newSvc.Spec.Selector) {
return false, ErrReplace
}
return false, nil
}
func reconcileService(oldObj, newObj runtime.Object) (bool, error) {
oldSvc, ok := oldObj.(*v1.Service)
if !ok {
oldSvc = &v1.Service{}
if err := convertObj(oldObj, oldSvc); err != nil {
return false, err
}
}
newSvc, ok := newObj.(*v1.Service)
if !ok {
newSvc = &v1.Service{}
if err := convertObj(newObj, newSvc); err != nil {
return false, err
}
}
if newSvc.Spec.Type != "" && oldSvc.Spec.Type != newSvc.Spec.Type {
return false, ErrReplace
}
return false, nil
}
func reconcileJob(oldObj, newObj runtime.Object) (bool, error) {
oldSvc, ok := oldObj.(*batchv1.Job)
if !ok {
oldSvc = &batchv1.Job{}
if err := convertObj(oldObj, oldSvc); err != nil {
return false, err
}
}
newSvc, ok := newObj.(*batchv1.Job)
if !ok {
newSvc = &batchv1.Job{}
if err := convertObj(newObj, newSvc); err != nil {
return false, err
}
}
if !equality.Semantic.DeepEqual(oldSvc.Spec.Template, newSvc.Spec.Template) {
return false, ErrReplace
}
return false, nil
}
func convertObj(src interface{}, obj interface{}) error {
uObj, ok := src.(*unstructured.Unstructured)
if !ok {
return fmt.Errorf("expected unstructured but got %v", reflect.TypeOf(src))
}
bytes, err := uObj.MarshalJSON()
if err != nil {
return err
}
return json.Unmarshal(bytes, obj)
}

24
vendor/github.com/rancher/wrangler/pkg/data/merge.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
package data
func MergeMaps(base, overlay map[string]interface{}) map[string]interface{} {
result := map[string]interface{}{}
for k, v := range base {
result[k] = v
}
for k, v := range overlay {
if baseMap, overlayMap, bothMaps := bothMaps(result[k], v); bothMaps {
v = MergeMaps(baseMap, overlayMap)
}
result[k] = v
}
return result
}
func bothMaps(left, right interface{}) (map[string]interface{}, map[string]interface{}, bool) {
leftMap, ok := left.(map[string]interface{})
if !ok {
return nil, nil, false
}
rightMap, ok := right.(map[string]interface{})
return leftMap, rightMap, ok
}

View File

@@ -1,53 +1,19 @@
/*
Copyright 2017 The Kubernetes Authors.
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 generic
import (
"context"
errors2 "errors"
"fmt"
"strings"
"time"
errors3 "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/rancher/lasso/pkg/controller"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
var ErrSkip = errors2.New("skip processing")
var ErrSkip = controller.ErrIgnore
type Handler func(key string, obj runtime.Object) (runtime.Object, error)
// Controller is the controller implementation for Foo resources
type Controller struct {
name string
workqueue workqueue.RateLimitingInterface
informer cache.SharedIndexInformer
handler Handler
gvk schema.GroupVersionKind
}
type ControllerMeta interface {
Informer() cache.SharedIndexInformer
GroupVersionKind() schema.GroupVersionKind
@@ -56,164 +22,3 @@ type ControllerMeta interface {
AddGenericRemoveHandler(ctx context.Context, name string, handler Handler)
Updater() Updater
}
// NewController returns a new sample controller
func NewController(gvk schema.GroupVersionKind, informer cache.SharedIndexInformer, workqueue workqueue.RateLimitingInterface, handler Handler) *Controller {
controller := &Controller{
name: gvk.String(),
handler: handler,
informer: informer,
workqueue: workqueue,
}
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: controller.handleObject,
UpdateFunc: func(old, new interface{}) {
newMeta, err := meta.Accessor(new)
utilruntime.Must(err)
oldMeta, err := meta.Accessor(old)
utilruntime.Must(err)
if newMeta.GetResourceVersion() == oldMeta.GetResourceVersion() {
return
}
controller.handleObject(new)
},
DeleteFunc: controller.handleObject,
})
return controller
}
func (c *Controller) Informer() cache.SharedIndexInformer {
return c.informer
}
func (c *Controller) GroupVersionKind() schema.GroupVersionKind {
return c.gvk
}
func (c *Controller) run(threadiness int, stopCh <-chan struct{}) {
defer utilruntime.HandleCrash()
defer c.workqueue.ShutDown()
// Start the informer factories to begin populating the informer caches
logrus.Infof("Starting %s controller", c.name)
// Launch two workers to process Foo resources
for i := 0; i < threadiness; i++ {
go wait.Until(c.runWorker, time.Second, stopCh)
}
<-stopCh
logrus.Infof("Shutting down %s workers", c.name)
}
func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error {
if ok := cache.WaitForCacheSync(stopCh, c.informer.HasSynced); !ok {
c.workqueue.ShutDown()
return fmt.Errorf("failed to wait for caches to sync")
}
go c.run(threadiness, stopCh)
return nil
}
func (c *Controller) runWorker() {
for c.processNextWorkItem() {
}
}
func (c *Controller) processNextWorkItem() bool {
obj, shutdown := c.workqueue.Get()
if shutdown {
return false
}
if err := c.processSingleItem(obj); err != nil {
if !strings.Contains(err.Error(), "please apply your changes to the latest version and try again") {
utilruntime.HandleError(err)
}
return true
}
return true
}
func (c *Controller) processSingleItem(obj interface{}) error {
var (
key string
ok bool
)
defer c.workqueue.Done(obj)
if key, ok = obj.(string); !ok {
c.workqueue.Forget(obj)
utilruntime.HandleError(fmt.Errorf("expected string in workqueue but got %#v", obj))
return nil
}
if err := c.syncHandler(key); err != nil && errors3.Cause(err) != ErrSkip {
c.workqueue.AddRateLimited(key)
return fmt.Errorf("error syncing '%s': %s, requeuing", key, err.Error())
}
c.workqueue.Forget(obj)
return nil
}
func (c *Controller) syncHandler(key string) error {
obj, exists, err := c.informer.GetStore().GetByKey(key)
if err != nil {
return err
}
if !exists {
_, err := c.handler(key, nil)
return err
}
_, err = c.handler(key, obj.(runtime.Object))
return err
}
func (c *Controller) Enqueue(namespace, name string) {
if namespace == "" {
c.workqueue.AddRateLimited(name)
} else {
c.workqueue.AddRateLimited(namespace + "/" + name)
}
}
func (c *Controller) EnqueueAfter(namespace, name string, duration time.Duration) {
if namespace == "" {
c.workqueue.AddAfter(name, duration)
} else {
c.workqueue.AddAfter(namespace+"/"+name, duration)
}
}
func (c *Controller) enqueue(obj interface{}) {
var key string
var err error
if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
utilruntime.HandleError(err)
return
}
c.workqueue.Add(key)
}
func (c *Controller) handleObject(obj interface{}) {
if _, ok := obj.(metav1.Object); !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
utilruntime.HandleError(fmt.Errorf("error decoding object, invalid type"))
return
}
_, ok = tombstone.Obj.(metav1.Object)
if !ok {
utilruntime.HandleError(fmt.Errorf("error decoding object tombstone, invalid type"))
return
}
}
c.enqueue(obj)
}

View File

@@ -1,195 +0,0 @@
package generic
import (
"context"
"strings"
"sync"
"time"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
type ControllerManager struct {
lock sync.Mutex
generation int
started map[schema.GroupVersionKind]bool
controllers map[schema.GroupVersionKind]*Controller
handlers map[schema.GroupVersionKind]*Handlers
}
func (g *ControllerManager) Controllers() map[schema.GroupVersionKind]*Controller {
return g.controllers
}
func (g *ControllerManager) EnsureStart(ctx context.Context, gvk schema.GroupVersionKind, threadiness int) error {
g.lock.Lock()
defer g.lock.Unlock()
return g.startController(ctx, gvk, threadiness)
}
func (g *ControllerManager) startController(ctx context.Context, gvk schema.GroupVersionKind, threadiness int) error {
if g.started[gvk] {
return nil
}
controller, ok := g.controllers[gvk]
if !ok {
return nil
}
if err := controller.Run(threadiness, ctx.Done()); err != nil {
return err
}
if g.started == nil {
g.started = map[schema.GroupVersionKind]bool{}
}
g.started[gvk] = true
go func() {
<-ctx.Done()
g.lock.Lock()
defer g.lock.Unlock()
delete(g.started, gvk)
delete(g.controllers, gvk)
}()
return nil
}
func (g *ControllerManager) Start(ctx context.Context, defaultThreadiness int, threadiness map[schema.GroupVersionKind]int) error {
g.lock.Lock()
defer g.lock.Unlock()
for gvk := range g.controllers {
threadiness, ok := threadiness[gvk]
if !ok {
threadiness = defaultThreadiness
}
if err := g.startController(ctx, gvk, threadiness); err != nil {
return err
}
}
return nil
}
func (g *ControllerManager) Enqueue(gvk schema.GroupVersionKind, informer cache.SharedIndexInformer, namespace, name string) {
_, controller, _ := g.getController(gvk, informer, true)
if namespace == "*" || name == "*" {
for _, key := range informer.GetStore().ListKeys() {
if namespace != "" && namespace != "*" && !strings.HasPrefix(key, namespace+"/") {
continue
}
if name != "*" && !nameMatches(key, name) {
continue
}
controller.workqueue.AddRateLimited(key)
}
} else {
controller.Enqueue(namespace, name)
}
}
func nameMatches(key, name string) bool {
return key == name || strings.HasSuffix(key, "/"+name)
}
func (g *ControllerManager) EnqueueAfter(gvk schema.GroupVersionKind, informer cache.SharedIndexInformer, namespace, name string, duration time.Duration) {
_, controller, _ := g.getController(gvk, informer, true)
controller.EnqueueAfter(namespace, name, duration)
}
func (g *ControllerManager) removeHandler(gvk schema.GroupVersionKind, generation int) {
g.lock.Lock()
defer g.lock.Unlock()
handlers, ok := g.handlers[gvk]
if !ok {
return
}
var newHandlers []handlerEntry
for _, h := range handlers.handlers {
if h.generation == generation {
continue
}
newHandlers = append(newHandlers, h)
}
handlers.handlers = newHandlers
}
func (g *ControllerManager) getController(gvk schema.GroupVersionKind, informer cache.SharedIndexInformer, lock bool) (*Handlers, *Controller, bool) {
if lock {
g.lock.Lock()
defer g.lock.Unlock()
}
if controller, ok := g.controllers[gvk]; ok {
return g.handlers[gvk], controller, true
}
handlers := &Handlers{}
queue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), gvk.String())
controller := NewController(gvk, informer, queue, handlers.Handle)
if g.handlers == nil {
g.handlers = map[schema.GroupVersionKind]*Handlers{}
}
if g.controllers == nil {
g.controllers = map[schema.GroupVersionKind]*Controller{}
}
g.handlers[gvk] = handlers
g.controllers[gvk] = controller
return handlers, controller, false
}
func (g *ControllerManager) AddHandler(ctx context.Context, gvk schema.GroupVersionKind, informer cache.SharedIndexInformer, name string, handler Handler) {
t := getHandlerTransaction(ctx)
if t == nil {
g.addHandler(ctx, gvk, informer, name, handler)
return
}
go func() {
if t.shouldContinue() {
g.addHandler(ctx, gvk, informer, name, handler)
}
}()
}
func (g *ControllerManager) addHandler(ctx context.Context, gvk schema.GroupVersionKind, informer cache.SharedIndexInformer, name string, handler Handler) {
g.lock.Lock()
defer g.lock.Unlock()
g.generation++
entry := handlerEntry{
generation: g.generation,
name: name,
handler: handler,
}
go func() {
<-ctx.Done()
g.removeHandler(gvk, entry.generation)
}()
handlers, controller, ok := g.getController(gvk, informer, false)
handlers.handlers = append(handlers.handlers, entry)
if ok {
for _, key := range controller.informer.GetStore().ListKeys() {
controller.workqueue.Add(key)
}
}
}

View File

@@ -0,0 +1,120 @@
package generic
import (
"context"
"sync"
"time"
"github.com/rancher/lasso/pkg/log"
"github.com/sirupsen/logrus"
"github.com/rancher/lasso/pkg/cache"
"github.com/rancher/lasso/pkg/client"
"github.com/rancher/lasso/pkg/controller"
"github.com/rancher/wrangler/pkg/schemes"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/rest"
)
func init() {
log.Infof = logrus.Infof
log.Errorf = logrus.Errorf
}
type Factory struct {
lock sync.Mutex
cacheFactory cache.SharedCacheFactory
controllerFactory controller.SharedControllerFactory
threadiness map[schema.GroupVersionKind]int
config *rest.Config
opts FactoryOptions
}
type FactoryOptions struct {
Namespace string
Resync time.Duration
SharedCacheFactory cache.SharedCacheFactory
SharedControllerFactory controller.SharedControllerFactory
}
func NewFactoryFromConfigWithOptions(config *rest.Config, opts *FactoryOptions) (*Factory, error) {
if opts == nil {
opts = &FactoryOptions{}
}
f := &Factory{
config: config,
threadiness: map[schema.GroupVersionKind]int{},
cacheFactory: opts.SharedCacheFactory,
controllerFactory: opts.SharedControllerFactory,
opts: *opts,
}
if f.cacheFactory == nil && f.controllerFactory != nil {
f.cacheFactory = f.controllerFactory.SharedCacheFactory()
}
return f, nil
}
func (c *Factory) SetThreadiness(gvk schema.GroupVersionKind, threadiness int) {
c.threadiness[gvk] = threadiness
}
func (c *Factory) ControllerFactory() controller.SharedControllerFactory {
err := c.setControllerFactoryWithLock()
utilruntime.Must(err)
return c.controllerFactory
}
func (c *Factory) setControllerFactoryWithLock() error {
c.lock.Lock()
defer c.lock.Unlock()
if c.controllerFactory != nil {
return nil
}
cacheFactory := c.cacheFactory
if cacheFactory == nil {
client, err := client.NewSharedClientFactory(c.config, &client.SharedClientFactoryOptions{
Scheme: schemes.All,
})
if err != nil {
return err
}
cacheFactory = cache.NewSharedCachedFactory(client, &cache.SharedCacheFactoryOptions{
DefaultNamespace: c.opts.Namespace,
DefaultResync: c.opts.Resync,
})
}
c.cacheFactory = cacheFactory
c.controllerFactory = controller.NewSharedControllerFactory(cacheFactory, &controller.SharedControllerFactoryOptions{
KindWorkers: c.threadiness,
})
return nil
}
func (c *Factory) Sync(ctx context.Context) error {
if c.cacheFactory != nil {
c.cacheFactory.Start(ctx)
c.cacheFactory.WaitForCacheSync(ctx)
}
return nil
}
func (c *Factory) Start(ctx context.Context, defaultThreadiness int) error {
if err := c.Sync(ctx); err != nil {
return err
}
if c.controllerFactory != nil {
return c.controllerFactory.Start(ctx, defaultThreadiness)
}
return nil
}

View File

@@ -1,7 +1,39 @@
package generic
import (
"github.com/rancher/wrangler/pkg/apply"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type GeneratingHandlerOptions struct {
AllowCrossNamespace bool
AllowClusterScoped bool
NoOwnerReference bool
DynamicLookup bool
}
func ConfigureApplyForObject(apply apply.Apply, obj metav1.Object, opts *GeneratingHandlerOptions) apply.Apply {
if opts == nil {
opts = &GeneratingHandlerOptions{}
}
if opts.DynamicLookup {
apply = apply.WithDynamicLookup()
}
if opts.NoOwnerReference {
apply = apply.WithSetOwnerReference(true, false)
}
if opts.AllowCrossNamespace && !opts.AllowClusterScoped {
apply = apply.
WithDefaultNamespace(obj.GetNamespace()).
WithListerNamespace(obj.GetNamespace())
}
if !opts.AllowClusterScoped {
apply = apply.WithRestrictClusterScoped()
}
return apply
}

View File

@@ -1,95 +0,0 @@
package generic
import (
"fmt"
"reflect"
"strings"
"k8s.io/apimachinery/pkg/runtime"
)
type handlerEntry struct {
generation int
name string
handler Handler
}
type Handlers struct {
handlers []handlerEntry
}
func (h *Handlers) Handle(key string, obj runtime.Object) (runtime.Object, error) {
var (
errs errors
)
for _, handler := range h.handlers {
newObj, err := handler.handler(key, obj)
if err != nil {
errs = append(errs, &handlerError{
HandlerName: handler.name,
Err: err,
})
}
if newObj != nil {
obj = newObj
}
}
return obj, errs.ToErr()
}
type errors []error
func (e errors) Error() string {
buf := strings.Builder{}
for _, err := range e {
if buf.Len() > 0 {
buf.WriteString(", ")
}
buf.WriteString(err.Error())
}
return buf.String()
}
func (e errors) ToErr() error {
switch len(e) {
case 0:
return nil
case 1:
return e[0]
default:
return e
}
}
func (e errors) Cause() error {
if len(e) > 0 {
return e[0]
}
return nil
}
type handlerError struct {
HandlerName string
Err error
}
func (h handlerError) Error() string {
return fmt.Sprintf("handler %s: %v", h.HandlerName, h.Err)
}
func (h handlerError) Cause() error {
return h.Err
}
func ToName(h interface{}) string {
if str, ok := h.(fmt.Stringer); ok {
return str.String()
}
s := reflect.ValueOf(h).Type().String()
if len(s) > 1 && s[0] == '*' {
return s[1:]
}
return s
}

View File

@@ -1,47 +0,0 @@
package generic
import (
"context"
)
type hTransactionKey struct{}
type HandlerTransaction struct {
context.Context
parent context.Context
done chan struct{}
result bool
}
func (h *HandlerTransaction) shouldContinue() bool {
select {
case <-h.parent.Done():
return false
case <-h.done:
return h.result
}
}
func (h *HandlerTransaction) Commit() {
h.result = true
close(h.done)
}
func (h *HandlerTransaction) Rollback() {
close(h.done)
}
func NewHandlerTransaction(ctx context.Context) *HandlerTransaction {
ht := &HandlerTransaction{
parent: ctx,
done: make(chan struct{}),
}
ctx = context.WithValue(ctx, hTransactionKey{}, ht)
ht.Context = ctx
return ht
}
func getHandlerTransaction(ctx context.Context) *HandlerTransaction {
v, _ := ctx.Value(hTransactionKey{}).(*HandlerTransaction)
return v
}

19
vendor/github.com/rancher/wrangler/pkg/gvk/detect.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
package gvk
import (
"encoding/json"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func Detect(obj []byte) (schema.GroupVersionKind, bool, error) {
partial := v1.PartialObjectMetadata{}
if err := json.Unmarshal(obj, &partial); err != nil {
return schema.GroupVersionKind{}, false, err
}
result := partial.GetObjectKind().GroupVersionKind()
ok := result.Kind != "" && result.Version != ""
return result, ok, nil
}

57
vendor/github.com/rancher/wrangler/pkg/gvk/get.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
package gvk
import (
"fmt"
"github.com/pkg/errors"
"github.com/rancher/wrangler/pkg/schemes"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func Get(obj runtime.Object) (schema.GroupVersionKind, error) {
gvk := obj.GetObjectKind().GroupVersionKind()
if gvk.Kind != "" {
return gvk, nil
}
gvks, _, err := schemes.All.ObjectKinds(obj)
if err != nil {
return schema.GroupVersionKind{}, errors.Wrapf(err, "failed to find gvk for %T, you may need to import the wrangler generated controller package", obj)
}
if len(gvks) == 0 {
return schema.GroupVersionKind{}, fmt.Errorf("failed to find gvk for %T", obj)
}
return gvks[0], nil
}
func Set(objs ...runtime.Object) error {
for _, obj := range objs {
if err := setObject(obj); err != nil {
return err
}
}
return nil
}
func setObject(obj runtime.Object) error {
gvk := obj.GetObjectKind().GroupVersionKind()
if gvk.Kind != "" {
return nil
}
gvks, _, err := schemes.All.ObjectKinds(obj)
if err != nil {
return err
}
if len(gvks) == 0 {
return nil
}
kind := obj.GetObjectKind()
kind.SetGroupVersionKind(gvks[0])
return nil
}

37
vendor/github.com/rancher/wrangler/pkg/merr/error.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
package merr
import "bytes"
type Errors []error
func (e Errors) Err() error {
return NewErrors(e...)
}
func (e Errors) Error() string {
buf := bytes.NewBuffer(nil)
for _, err := range e {
if buf.Len() > 0 {
buf.WriteString(", ")
}
buf.WriteString(err.Error())
}
return buf.String()
}
func NewErrors(inErrors ...error) error {
var errors []error
for _, err := range inErrors {
if err != nil {
errors = append(errors, err)
}
}
if len(errors) == 0 {
return nil
} else if len(errors) == 1 {
return errors[0]
}
return Errors(errors)
}

View File

@@ -0,0 +1,155 @@
package objectset
import (
"fmt"
"reflect"
"sort"
"github.com/pkg/errors"
"github.com/rancher/wrangler/pkg/gvk"
"github.com/rancher/wrangler/pkg/merr"
"k8s.io/apimachinery/pkg/api/meta"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type ObjectKey struct {
Name string
Namespace string
}
func NewObjectKey(obj v1.Object) ObjectKey {
return ObjectKey{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}
}
func (o ObjectKey) String() string {
if o.Namespace == "" {
return o.Name
}
return fmt.Sprintf("%s/%s", o.Namespace, o.Name)
}
type ObjectKeyByGVK map[schema.GroupVersionKind][]ObjectKey
type ObjectByGVK map[schema.GroupVersionKind]map[ObjectKey]runtime.Object
func (o ObjectByGVK) Add(obj runtime.Object) (schema.GroupVersionKind, error) {
metadata, err := meta.Accessor(obj)
if err != nil {
return schema.GroupVersionKind{}, err
}
gvk, err := gvk.Get(obj)
if err != nil {
return schema.GroupVersionKind{}, err
}
objs := o[gvk]
if objs == nil {
objs = map[ObjectKey]runtime.Object{}
o[gvk] = objs
}
objs[ObjectKey{
Namespace: metadata.GetNamespace(),
Name: metadata.GetName(),
}] = obj
return gvk, nil
}
type ObjectSet struct {
errs []error
objects ObjectByGVK
order []runtime.Object
gvkOrder []schema.GroupVersionKind
gvkSeen map[schema.GroupVersionKind]bool
}
func NewObjectSet(objs ...runtime.Object) *ObjectSet {
os := &ObjectSet{
objects: ObjectByGVK{},
gvkSeen: map[schema.GroupVersionKind]bool{},
}
os.Add(objs...)
return os
}
func (o *ObjectSet) ObjectsByGVK() ObjectByGVK {
if o == nil {
return nil
}
return o.objects
}
func (o *ObjectSet) All() []runtime.Object {
return o.order
}
func (o *ObjectSet) Add(objs ...runtime.Object) *ObjectSet {
for _, obj := range objs {
o.add(obj)
}
return o
}
func (o *ObjectSet) add(obj runtime.Object) {
if obj == nil || reflect.ValueOf(obj).IsNil() {
return
}
gvk, err := o.objects.Add(obj)
if err != nil {
o.err(errors.Wrapf(err, "failed to add %T", obj))
return
}
o.order = append(o.order, obj)
if !o.gvkSeen[gvk] {
o.gvkSeen[gvk] = true
o.gvkOrder = append(o.gvkOrder, gvk)
}
}
func (o *ObjectSet) err(err error) error {
o.errs = append(o.errs, err)
return o.Err()
}
func (o *ObjectSet) AddErr(err error) {
o.errs = append(o.errs, err)
}
func (o *ObjectSet) Err() error {
return merr.NewErrors(o.errs...)
}
func (o *ObjectSet) Len() int {
return len(o.objects)
}
func (o *ObjectSet) GVKs() []schema.GroupVersionKind {
return o.GVKOrder()
}
func (o *ObjectSet) GVKOrder(known ...schema.GroupVersionKind) []schema.GroupVersionKind {
var rest []schema.GroupVersionKind
for _, gvk := range known {
if o.gvkSeen[gvk] {
continue
}
rest = append(rest, gvk)
}
sort.Slice(rest, func(i, j int) bool {
return rest[i].String() < rest[j].String()
})
return append(o.gvkOrder, rest...)
}

57
vendor/github.com/rancher/wrangler/pkg/patch/apply.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
package patch
import (
"encoding/json"
"fmt"
jsonpatch "github.com/evanphx/json-patch"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
)
func Apply(original, patch []byte) ([]byte, error) {
style, metadata, err := GetPatchStyle(original, patch)
if err != nil {
return nil, err
}
switch style {
case types.JSONPatchType:
return applyJSONPatch(original, patch)
case types.MergePatchType:
return applyMergePatch(original, patch)
case types.StrategicMergePatchType:
return applyStrategicMergePatch(original, patch, metadata)
default:
return nil, fmt.Errorf("invalid patch")
}
}
func applyStrategicMergePatch(original, patch []byte, lookup strategicpatch.LookupPatchMeta) ([]byte, error) {
originalMap := map[string]interface{}{}
patchMap := map[string]interface{}{}
if err := json.Unmarshal(original, &originalMap); err != nil {
return nil, err
}
if err := json.Unmarshal(patch, &patchMap); err != nil {
return nil, err
}
patchedMap, err := strategicpatch.StrategicMergeMapPatchUsingLookupPatchMeta(originalMap, patchMap, lookup)
if err != nil {
return nil, err
}
return json.Marshal(patchedMap)
}
func applyMergePatch(original, patch []byte) ([]byte, error) {
return jsonpatch.MergePatch(original, patch)
}
func applyJSONPatch(original, patch []byte) ([]byte, error) {
jsonPatch, err := jsonpatch.DecodePatch(patch)
if err != nil {
return nil, err
}
return jsonPatch.Apply(original)
}

79
vendor/github.com/rancher/wrangler/pkg/patch/style.go generated vendored Normal file
View File

@@ -0,0 +1,79 @@
package patch
import (
"sync"
"github.com/rancher/wrangler/pkg/gvk"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/client-go/kubernetes/scheme"
)
var (
patchCache = map[schema.GroupVersionKind]patchCacheEntry{}
patchCacheLock = sync.Mutex{}
)
type patchCacheEntry struct {
patchType types.PatchType
lookup strategicpatch.LookupPatchMeta
}
func isJSONPatch(patch []byte) bool {
// a JSON patch is a list
return len(patch) > 0 && patch[0] == '['
}
func GetPatchStyle(original, patch []byte) (types.PatchType, strategicpatch.LookupPatchMeta, error) {
if isJSONPatch(patch) {
return types.JSONPatchType, nil, nil
}
gvk, ok, err := gvk.Detect(original)
if err != nil {
return "", nil, err
}
if !ok {
return types.MergePatchType, nil, nil
}
return GetMergeStyle(gvk)
}
func GetMergeStyle(gvk schema.GroupVersionKind) (types.PatchType, strategicpatch.LookupPatchMeta, error) {
var (
patchType types.PatchType
lookupPatchMeta strategicpatch.LookupPatchMeta
)
patchCacheLock.Lock()
entry, ok := patchCache[gvk]
patchCacheLock.Unlock()
if ok {
return entry.patchType, entry.lookup, nil
}
versionedObject, err := scheme.Scheme.New(gvk)
if runtime.IsNotRegisteredError(err) {
patchType = types.MergePatchType
} else if err != nil {
return patchType, nil, err
} else {
patchType = types.StrategicMergePatchType
lookupPatchMeta, err = strategicpatch.NewPatchMetaFromStruct(versionedObject)
if err != nil {
return patchType, nil, err
}
}
patchCacheLock.Lock()
patchCache[gvk] = patchCacheEntry{
patchType: patchType,
lookup: lookupPatchMeta,
}
patchCacheLock.Unlock()
return patchType, lookupPatchMeta, nil
}

View File

@@ -1,7 +1,20 @@
package schemes
import (
"github.com/rancher/lasso/pkg/scheme"
"k8s.io/apimachinery/pkg/runtime"
)
var All = runtime.NewScheme()
var (
All = scheme.All
localSchemeBuilder = runtime.NewSchemeBuilder()
)
func Register(addToScheme func(*runtime.Scheme) error) error {
localSchemeBuilder = append(localSchemeBuilder, addToScheme)
return addToScheme(All)
}
func AddToScheme(scheme *runtime.Scheme) error {
return localSchemeBuilder.AddToScheme(scheme)
}

View File

@@ -0,0 +1,160 @@
/*
Copyright 2017 The Kubernetes Authors.
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 jsonmergepatch
import (
"fmt"
"reflect"
"github.com/evanphx/json-patch"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/mergepatch"
)
// Create a 3-way merge patch based-on JSON merge patch.
// Calculate addition-and-change patch between current and modified.
// Calculate deletion patch between original and modified.
func CreateThreeWayJSONMergePatch(original, modified, current []byte, fns ...mergepatch.PreconditionFunc) ([]byte, error) {
if len(original) == 0 {
original = []byte(`{}`)
}
if len(modified) == 0 {
modified = []byte(`{}`)
}
if len(current) == 0 {
current = []byte(`{}`)
}
addAndChangePatch, err := jsonpatch.CreateMergePatch(current, modified)
if err != nil {
return nil, err
}
// Only keep addition and changes
addAndChangePatch, addAndChangePatchObj, err := keepOrDeleteNullInJsonPatch(addAndChangePatch, false)
if err != nil {
return nil, err
}
deletePatch, err := jsonpatch.CreateMergePatch(original, modified)
if err != nil {
return nil, err
}
// Only keep deletion
deletePatch, deletePatchObj, err := keepOrDeleteNullInJsonPatch(deletePatch, true)
if err != nil {
return nil, err
}
hasConflicts, err := mergepatch.HasConflicts(addAndChangePatchObj, deletePatchObj)
if err != nil {
return nil, err
}
if hasConflicts {
return nil, mergepatch.NewErrConflict(mergepatch.ToYAMLOrError(addAndChangePatchObj), mergepatch.ToYAMLOrError(deletePatchObj))
}
patch, err := jsonpatch.MergePatch(deletePatch, addAndChangePatch)
if err != nil {
return nil, err
}
var patchMap map[string]interface{}
err = json.Unmarshal(patch, &patchMap)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal patch for precondition check: %s", patch)
}
meetPreconditions, err := meetPreconditions(patchMap, fns...)
if err != nil {
return nil, err
}
if !meetPreconditions {
return nil, mergepatch.NewErrPreconditionFailed(patchMap)
}
return patch, nil
}
// keepOrDeleteNullInJsonPatch takes a json-encoded byte array and a boolean.
// It returns a filtered object and its corresponding json-encoded byte array.
// It is a wrapper of func keepOrDeleteNullInObj
func keepOrDeleteNullInJsonPatch(patch []byte, keepNull bool) ([]byte, map[string]interface{}, error) {
var patchMap map[string]interface{}
err := json.Unmarshal(patch, &patchMap)
if err != nil {
return nil, nil, err
}
filteredMap, err := keepOrDeleteNullInObj(patchMap, keepNull)
if err != nil {
return nil, nil, err
}
o, err := json.Marshal(filteredMap)
return o, filteredMap, err
}
// keepOrDeleteNullInObj will keep only the null value and delete all the others,
// if keepNull is true. Otherwise, it will delete all the null value and keep the others.
func keepOrDeleteNullInObj(m map[string]interface{}, keepNull bool) (map[string]interface{}, error) {
filteredMap := make(map[string]interface{})
var err error
for key, val := range m {
switch {
case keepNull && val == nil:
filteredMap[key] = nil
case val != nil:
switch typedVal := val.(type) {
case map[string]interface{}:
// Explicitly-set empty maps are treated as values instead of empty patches
if len(typedVal) == 0 {
if !keepNull {
filteredMap[key] = typedVal
}
continue
}
var filteredSubMap map[string]interface{}
filteredSubMap, err = keepOrDeleteNullInObj(typedVal, keepNull)
if err != nil {
return nil, err
}
// If the returned filtered submap was empty, this is an empty patch for the entire subdict, so the key
// should not be set
if len(filteredSubMap) != 0 {
filteredMap[key] = filteredSubMap
}
case []interface{}, string, float64, bool, int64, nil:
// Lists are always replaced in Json, no need to check each entry in the list.
if !keepNull {
filteredMap[key] = val
}
default:
return nil, fmt.Errorf("unknown type: %v", reflect.TypeOf(typedVal))
}
}
}
return filteredMap, nil
}
func meetPreconditions(patchObj map[string]interface{}, fns ...mergepatch.PreconditionFunc) (bool, error) {
// Apply the preconditions to the patch, and return an error if any of them fail.
for _, fn := range fns {
if !fn(patchObj) {
return false, fmt.Errorf("precondition failed for: %v", patchObj)
}
}
return true, nil
}

View File

@@ -0,0 +1,7 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- pwittrock
reviewers:
- mengqiy
- apelisse

View File

@@ -0,0 +1,102 @@
/*
Copyright 2017 The Kubernetes Authors.
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 mergepatch
import (
"errors"
"fmt"
"reflect"
)
var (
ErrBadJSONDoc = errors.New("invalid JSON document")
ErrNoListOfLists = errors.New("lists of lists are not supported")
ErrBadPatchFormatForPrimitiveList = errors.New("invalid patch format of primitive list")
ErrBadPatchFormatForRetainKeys = errors.New("invalid patch format of retainKeys")
ErrBadPatchFormatForSetElementOrderList = errors.New("invalid patch format of setElementOrder list")
ErrPatchContentNotMatchRetainKeys = errors.New("patch content doesn't match retainKeys list")
ErrUnsupportedStrategicMergePatchFormat = errors.New("strategic merge patch format is not supported")
)
func ErrNoMergeKey(m map[string]interface{}, k string) error {
return fmt.Errorf("map: %v does not contain declared merge key: %s", m, k)
}
func ErrBadArgType(expected, actual interface{}) error {
return fmt.Errorf("expected a %s, but received a %s",
reflect.TypeOf(expected),
reflect.TypeOf(actual))
}
func ErrBadArgKind(expected, actual interface{}) error {
var expectedKindString, actualKindString string
if expected == nil {
expectedKindString = "nil"
} else {
expectedKindString = reflect.TypeOf(expected).Kind().String()
}
if actual == nil {
actualKindString = "nil"
} else {
actualKindString = reflect.TypeOf(actual).Kind().String()
}
return fmt.Errorf("expected a %s, but received a %s", expectedKindString, actualKindString)
}
func ErrBadPatchType(t interface{}, m map[string]interface{}) error {
return fmt.Errorf("unknown patch type: %s in map: %v", t, m)
}
// IsPreconditionFailed returns true if the provided error indicates
// a precondition failed.
func IsPreconditionFailed(err error) bool {
_, ok := err.(ErrPreconditionFailed)
return ok
}
type ErrPreconditionFailed struct {
message string
}
func NewErrPreconditionFailed(target map[string]interface{}) ErrPreconditionFailed {
s := fmt.Sprintf("precondition failed for: %v", target)
return ErrPreconditionFailed{s}
}
func (err ErrPreconditionFailed) Error() string {
return err.message
}
type ErrConflict struct {
message string
}
func NewErrConflict(patch, current string) ErrConflict {
s := fmt.Sprintf("patch:\n%s\nconflicts with changes made from original to current:\n%s\n", patch, current)
return ErrConflict{s}
}
func (err ErrConflict) Error() string {
return err.message
}
// IsConflict returns true if the provided error indicates
// a conflict between the patch and the current configuration.
func IsConflict(err error) bool {
_, ok := err.(ErrConflict)
return ok
}

133
vendor/k8s.io/apimachinery/pkg/util/mergepatch/util.go generated vendored Normal file
View File

@@ -0,0 +1,133 @@
/*
Copyright 2017 The Kubernetes Authors.
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 mergepatch
import (
"fmt"
"reflect"
"github.com/davecgh/go-spew/spew"
"sigs.k8s.io/yaml"
)
// PreconditionFunc asserts that an incompatible change is not present within a patch.
type PreconditionFunc func(interface{}) bool
// RequireKeyUnchanged returns a precondition function that fails if the provided key
// is present in the patch (indicating that its value has changed).
func RequireKeyUnchanged(key string) PreconditionFunc {
return func(patch interface{}) bool {
patchMap, ok := patch.(map[string]interface{})
if !ok {
return true
}
// The presence of key means that its value has been changed, so the test fails.
_, ok = patchMap[key]
return !ok
}
}
// RequireMetadataKeyUnchanged creates a precondition function that fails
// if the metadata.key is present in the patch (indicating its value
// has changed).
func RequireMetadataKeyUnchanged(key string) PreconditionFunc {
return func(patch interface{}) bool {
patchMap, ok := patch.(map[string]interface{})
if !ok {
return true
}
patchMap1, ok := patchMap["metadata"]
if !ok {
return true
}
patchMap2, ok := patchMap1.(map[string]interface{})
if !ok {
return true
}
_, ok = patchMap2[key]
return !ok
}
}
func ToYAMLOrError(v interface{}) string {
y, err := toYAML(v)
if err != nil {
return err.Error()
}
return y
}
func toYAML(v interface{}) (string, error) {
y, err := yaml.Marshal(v)
if err != nil {
return "", fmt.Errorf("yaml marshal failed:%v\n%v\n", err, spew.Sdump(v))
}
return string(y), nil
}
// HasConflicts returns true if the left and right JSON interface objects overlap with
// different values in any key. All keys are required to be strings. Since patches of the
// same Type have congruent keys, this is valid for multiple patch types. This method
// supports JSON merge patch semantics.
//
// NOTE: Numbers with different types (e.g. int(0) vs int64(0)) will be detected as conflicts.
// Make sure the unmarshaling of left and right are consistent (e.g. use the same library).
func HasConflicts(left, right interface{}) (bool, error) {
switch typedLeft := left.(type) {
case map[string]interface{}:
switch typedRight := right.(type) {
case map[string]interface{}:
for key, leftValue := range typedLeft {
rightValue, ok := typedRight[key]
if !ok {
continue
}
if conflict, err := HasConflicts(leftValue, rightValue); err != nil || conflict {
return conflict, err
}
}
return false, nil
default:
return true, nil
}
case []interface{}:
switch typedRight := right.(type) {
case []interface{}:
if len(typedLeft) != len(typedRight) {
return true, nil
}
for i := range typedLeft {
if conflict, err := HasConflicts(typedLeft[i], typedRight[i]); err != nil || conflict {
return conflict, err
}
}
return false, nil
default:
return true, nil
}
case string, float64, bool, int64, nil:
return !reflect.DeepEqual(left, right), nil
default:
return true, fmt.Errorf("unknown type: %v", reflect.TypeOf(left))
}
}

View File

@@ -0,0 +1,8 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- pwittrock
- mengqiy
reviewers:
- mengqiy
- apelisse

View File

@@ -0,0 +1,49 @@
/*
Copyright 2017 The Kubernetes Authors.
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 strategicpatch
import (
"fmt"
)
type LookupPatchMetaError struct {
Path string
Err error
}
func (e LookupPatchMetaError) Error() string {
return fmt.Sprintf("LookupPatchMetaError(%s): %v", e.Path, e.Err)
}
type FieldNotFoundError struct {
Path string
Field string
}
func (e FieldNotFoundError) Error() string {
return fmt.Sprintf("unable to find api field %q in %s", e.Field, e.Path)
}
type InvalidTypeError struct {
Path string
Expected string
Actual string
}
func (e InvalidTypeError) Error() string {
return fmt.Sprintf("invalid type for %s: got %q, expected %q", e.Path, e.Actual, e.Expected)
}

View File

@@ -0,0 +1,194 @@
/*
Copyright 2017 The Kubernetes Authors.
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 strategicpatch
import (
"errors"
"fmt"
"reflect"
"k8s.io/apimachinery/pkg/util/mergepatch"
forkedjson "k8s.io/apimachinery/third_party/forked/golang/json"
openapi "k8s.io/kube-openapi/pkg/util/proto"
)
type PatchMeta struct {
patchStrategies []string
patchMergeKey string
}
func (pm PatchMeta) GetPatchStrategies() []string {
if pm.patchStrategies == nil {
return []string{}
}
return pm.patchStrategies
}
func (pm PatchMeta) SetPatchStrategies(ps []string) {
pm.patchStrategies = ps
}
func (pm PatchMeta) GetPatchMergeKey() string {
return pm.patchMergeKey
}
func (pm PatchMeta) SetPatchMergeKey(pmk string) {
pm.patchMergeKey = pmk
}
type LookupPatchMeta interface {
// LookupPatchMetadataForStruct gets subschema and the patch metadata (e.g. patch strategy and merge key) for map.
LookupPatchMetadataForStruct(key string) (LookupPatchMeta, PatchMeta, error)
// LookupPatchMetadataForSlice get subschema and the patch metadata for slice.
LookupPatchMetadataForSlice(key string) (LookupPatchMeta, PatchMeta, error)
// Get the type name of the field
Name() string
}
type PatchMetaFromStruct struct {
T reflect.Type
}
func NewPatchMetaFromStruct(dataStruct interface{}) (PatchMetaFromStruct, error) {
t, err := getTagStructType(dataStruct)
return PatchMetaFromStruct{T: t}, err
}
var _ LookupPatchMeta = PatchMetaFromStruct{}
func (s PatchMetaFromStruct) LookupPatchMetadataForStruct(key string) (LookupPatchMeta, PatchMeta, error) {
fieldType, fieldPatchStrategies, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadataForStruct(s.T, key)
if err != nil {
return nil, PatchMeta{}, err
}
return PatchMetaFromStruct{T: fieldType},
PatchMeta{
patchStrategies: fieldPatchStrategies,
patchMergeKey: fieldPatchMergeKey,
}, nil
}
func (s PatchMetaFromStruct) LookupPatchMetadataForSlice(key string) (LookupPatchMeta, PatchMeta, error) {
subschema, patchMeta, err := s.LookupPatchMetadataForStruct(key)
if err != nil {
return nil, PatchMeta{}, err
}
elemPatchMetaFromStruct := subschema.(PatchMetaFromStruct)
t := elemPatchMetaFromStruct.T
var elemType reflect.Type
switch t.Kind() {
// If t is an array or a slice, get the element type.
// If element is still an array or a slice, return an error.
// Otherwise, return element type.
case reflect.Array, reflect.Slice:
elemType = t.Elem()
if elemType.Kind() == reflect.Array || elemType.Kind() == reflect.Slice {
return nil, PatchMeta{}, errors.New("unexpected slice of slice")
}
// If t is an pointer, get the underlying element.
// If the underlying element is neither an array nor a slice, the pointer is pointing to a slice,
// e.g. https://github.com/kubernetes/kubernetes/blob/bc22e206c79282487ea0bf5696d5ccec7e839a76/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go#L2782-L2822
// If the underlying element is either an array or a slice, return its element type.
case reflect.Ptr:
t = t.Elem()
if t.Kind() == reflect.Array || t.Kind() == reflect.Slice {
t = t.Elem()
}
elemType = t
default:
return nil, PatchMeta{}, fmt.Errorf("expected slice or array type, but got: %s", s.T.Kind().String())
}
return PatchMetaFromStruct{T: elemType}, patchMeta, nil
}
func (s PatchMetaFromStruct) Name() string {
return s.T.Kind().String()
}
func getTagStructType(dataStruct interface{}) (reflect.Type, error) {
if dataStruct == nil {
return nil, mergepatch.ErrBadArgKind(struct{}{}, nil)
}
t := reflect.TypeOf(dataStruct)
// Get the underlying type for pointers
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return nil, mergepatch.ErrBadArgKind(struct{}{}, dataStruct)
}
return t, nil
}
func GetTagStructTypeOrDie(dataStruct interface{}) reflect.Type {
t, err := getTagStructType(dataStruct)
if err != nil {
panic(err)
}
return t
}
type PatchMetaFromOpenAPI struct {
Schema openapi.Schema
}
func NewPatchMetaFromOpenAPI(s openapi.Schema) PatchMetaFromOpenAPI {
return PatchMetaFromOpenAPI{Schema: s}
}
var _ LookupPatchMeta = PatchMetaFromOpenAPI{}
func (s PatchMetaFromOpenAPI) LookupPatchMetadataForStruct(key string) (LookupPatchMeta, PatchMeta, error) {
if s.Schema == nil {
return nil, PatchMeta{}, nil
}
kindItem := NewKindItem(key, s.Schema.GetPath())
s.Schema.Accept(kindItem)
err := kindItem.Error()
if err != nil {
return nil, PatchMeta{}, err
}
return PatchMetaFromOpenAPI{Schema: kindItem.subschema},
kindItem.patchmeta, nil
}
func (s PatchMetaFromOpenAPI) LookupPatchMetadataForSlice(key string) (LookupPatchMeta, PatchMeta, error) {
if s.Schema == nil {
return nil, PatchMeta{}, nil
}
sliceItem := NewSliceItem(key, s.Schema.GetPath())
s.Schema.Accept(sliceItem)
err := sliceItem.Error()
if err != nil {
return nil, PatchMeta{}, err
}
return PatchMetaFromOpenAPI{Schema: sliceItem.subschema},
sliceItem.patchmeta, nil
}
func (s PatchMetaFromOpenAPI) Name() string {
schema := s.Schema
return schema.GetName()
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,193 @@
/*
Copyright 2017 The Kubernetes Authors.
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 strategicpatch
import (
"errors"
"strings"
"k8s.io/apimachinery/pkg/util/mergepatch"
openapi "k8s.io/kube-openapi/pkg/util/proto"
)
const (
patchStrategyOpenapiextensionKey = "x-kubernetes-patch-strategy"
patchMergeKeyOpenapiextensionKey = "x-kubernetes-patch-merge-key"
)
type LookupPatchItem interface {
openapi.SchemaVisitor
Error() error
Path() *openapi.Path
}
type kindItem struct {
key string
path *openapi.Path
err error
patchmeta PatchMeta
subschema openapi.Schema
hasVisitKind bool
}
func NewKindItem(key string, path *openapi.Path) *kindItem {
return &kindItem{
key: key,
path: path,
}
}
var _ LookupPatchItem = &kindItem{}
func (item *kindItem) Error() error {
return item.err
}
func (item *kindItem) Path() *openapi.Path {
return item.path
}
func (item *kindItem) VisitPrimitive(schema *openapi.Primitive) {
item.err = errors.New("expected kind, but got primitive")
}
func (item *kindItem) VisitArray(schema *openapi.Array) {
item.err = errors.New("expected kind, but got slice")
}
func (item *kindItem) VisitMap(schema *openapi.Map) {
item.err = errors.New("expected kind, but got map")
}
func (item *kindItem) VisitReference(schema openapi.Reference) {
if !item.hasVisitKind {
schema.SubSchema().Accept(item)
}
}
func (item *kindItem) VisitKind(schema *openapi.Kind) {
subschema, ok := schema.Fields[item.key]
if !ok {
item.err = FieldNotFoundError{Path: schema.GetPath().String(), Field: item.key}
return
}
mergeKey, patchStrategies, err := parsePatchMetadata(subschema.GetExtensions())
if err != nil {
item.err = err
return
}
item.patchmeta = PatchMeta{
patchStrategies: patchStrategies,
patchMergeKey: mergeKey,
}
item.subschema = subschema
}
type sliceItem struct {
key string
path *openapi.Path
err error
patchmeta PatchMeta
subschema openapi.Schema
hasVisitKind bool
}
func NewSliceItem(key string, path *openapi.Path) *sliceItem {
return &sliceItem{
key: key,
path: path,
}
}
var _ LookupPatchItem = &sliceItem{}
func (item *sliceItem) Error() error {
return item.err
}
func (item *sliceItem) Path() *openapi.Path {
return item.path
}
func (item *sliceItem) VisitPrimitive(schema *openapi.Primitive) {
item.err = errors.New("expected slice, but got primitive")
}
func (item *sliceItem) VisitArray(schema *openapi.Array) {
if !item.hasVisitKind {
item.err = errors.New("expected visit kind first, then visit array")
}
subschema := schema.SubType
item.subschema = subschema
}
func (item *sliceItem) VisitMap(schema *openapi.Map) {
item.err = errors.New("expected slice, but got map")
}
func (item *sliceItem) VisitReference(schema openapi.Reference) {
if !item.hasVisitKind {
schema.SubSchema().Accept(item)
} else {
item.subschema = schema.SubSchema()
}
}
func (item *sliceItem) VisitKind(schema *openapi.Kind) {
subschema, ok := schema.Fields[item.key]
if !ok {
item.err = FieldNotFoundError{Path: schema.GetPath().String(), Field: item.key}
return
}
mergeKey, patchStrategies, err := parsePatchMetadata(subschema.GetExtensions())
if err != nil {
item.err = err
return
}
item.patchmeta = PatchMeta{
patchStrategies: patchStrategies,
patchMergeKey: mergeKey,
}
item.hasVisitKind = true
subschema.Accept(item)
}
func parsePatchMetadata(extensions map[string]interface{}) (string, []string, error) {
ps, foundPS := extensions[patchStrategyOpenapiextensionKey]
var patchStrategies []string
var mergeKey, patchStrategy string
var ok bool
if foundPS {
patchStrategy, ok = ps.(string)
if ok {
patchStrategies = strings.Split(patchStrategy, ",")
} else {
return "", nil, mergepatch.ErrBadArgType(patchStrategy, ps)
}
}
mk, foundMK := extensions[patchMergeKeyOpenapiextensionKey]
if foundMK {
mergeKey, ok = mk.(string)
if !ok {
return "", nil, mergepatch.ErrBadArgType(mergeKey, mk)
}
}
return mergeKey, patchStrategies, nil
}

View File

@@ -0,0 +1,7 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- pwittrock
reviewers:
- mengqiy
- apelisse

View File

@@ -0,0 +1,513 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package json is forked from the Go standard library to enable us to find the
// field of a struct that a given JSON key maps to.
package json
import (
"bytes"
"fmt"
"reflect"
"sort"
"strings"
"sync"
"unicode"
"unicode/utf8"
)
const (
patchStrategyTagKey = "patchStrategy"
patchMergeKeyTagKey = "patchMergeKey"
)
// Finds the patchStrategy and patchMergeKey struct tag fields on a given
// struct field given the struct type and the JSON name of the field.
// It returns field type, a slice of patch strategies, merge key and error.
// TODO: fix the returned errors to be introspectable.
func LookupPatchMetadataForStruct(t reflect.Type, jsonField string) (
elemType reflect.Type, patchStrategies []string, patchMergeKey string, e error) {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
e = fmt.Errorf("merging an object in json but data type is not struct, instead is: %s",
t.Kind().String())
return
}
jf := []byte(jsonField)
// Find the field that the JSON library would use.
var f *field
fields := cachedTypeFields(t)
for i := range fields {
ff := &fields[i]
if bytes.Equal(ff.nameBytes, jf) {
f = ff
break
}
// Do case-insensitive comparison.
if f == nil && ff.equalFold(ff.nameBytes, jf) {
f = ff
}
}
if f != nil {
// Find the reflect.Value of the most preferential struct field.
tjf := t.Field(f.index[0])
// we must navigate down all the anonymously included structs in the chain
for i := 1; i < len(f.index); i++ {
tjf = tjf.Type.Field(f.index[i])
}
patchStrategy := tjf.Tag.Get(patchStrategyTagKey)
patchMergeKey = tjf.Tag.Get(patchMergeKeyTagKey)
patchStrategies = strings.Split(patchStrategy, ",")
elemType = tjf.Type
return
}
e = fmt.Errorf("unable to find api field in struct %s for the json field %q", t.Name(), jsonField)
return
}
// A field represents a single field found in a struct.
type field struct {
name string
nameBytes []byte // []byte(name)
equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
tag bool
// index is the sequence of indexes from the containing type fields to this field.
// it is a slice because anonymous structs will need multiple navigation steps to correctly
// resolve the proper fields
index []int
typ reflect.Type
omitEmpty bool
quoted bool
}
func (f field) String() string {
return fmt.Sprintf("{name: %s, type: %v, tag: %v, index: %v, omitEmpty: %v, quoted: %v}", f.name, f.typ, f.tag, f.index, f.omitEmpty, f.quoted)
}
func fillField(f field) field {
f.nameBytes = []byte(f.name)
f.equalFold = foldFunc(f.nameBytes)
return f
}
// byName sorts field by name, breaking ties with depth,
// then breaking ties with "name came from json tag", then
// breaking ties with index sequence.
type byName []field
func (x byName) Len() int { return len(x) }
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byName) Less(i, j int) bool {
if x[i].name != x[j].name {
return x[i].name < x[j].name
}
if len(x[i].index) != len(x[j].index) {
return len(x[i].index) < len(x[j].index)
}
if x[i].tag != x[j].tag {
return x[i].tag
}
return byIndex(x).Less(i, j)
}
// byIndex sorts field by index sequence.
type byIndex []field
func (x byIndex) Len() int { return len(x) }
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byIndex) Less(i, j int) bool {
for k, xik := range x[i].index {
if k >= len(x[j].index) {
return false
}
if xik != x[j].index[k] {
return xik < x[j].index[k]
}
}
return len(x[i].index) < len(x[j].index)
}
// typeFields returns a list of fields that JSON should recognize for the given type.
// The algorithm is breadth-first search over the set of structs to include - the top struct
// and then any reachable anonymous structs.
func typeFields(t reflect.Type) []field {
// Anonymous fields to explore at the current level and the next.
current := []field{}
next := []field{{typ: t}}
// Count of queued names for current level and the next.
count := map[reflect.Type]int{}
nextCount := map[reflect.Type]int{}
// Types already visited at an earlier level.
visited := map[reflect.Type]bool{}
// Fields found.
var fields []field
for len(next) > 0 {
current, next = next, current[:0]
count, nextCount = nextCount, map[reflect.Type]int{}
for _, f := range current {
if visited[f.typ] {
continue
}
visited[f.typ] = true
// Scan f.typ for fields to include.
for i := 0; i < f.typ.NumField(); i++ {
sf := f.typ.Field(i)
if sf.PkgPath != "" { // unexported
continue
}
tag := sf.Tag.Get("json")
if tag == "-" {
continue
}
name, opts := parseTag(tag)
if !isValidTag(name) {
name = ""
}
index := make([]int, len(f.index)+1)
copy(index, f.index)
index[len(f.index)] = i
ft := sf.Type
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
// Follow pointer.
ft = ft.Elem()
}
// Record found field and index sequence.
if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
tagged := name != ""
if name == "" {
name = sf.Name
}
fields = append(fields, fillField(field{
name: name,
tag: tagged,
index: index,
typ: ft,
omitEmpty: opts.Contains("omitempty"),
quoted: opts.Contains("string"),
}))
if count[f.typ] > 1 {
// If there were multiple instances, add a second,
// so that the annihilation code will see a duplicate.
// It only cares about the distinction between 1 or 2,
// so don't bother generating any more copies.
fields = append(fields, fields[len(fields)-1])
}
continue
}
// Record new anonymous struct to explore in next round.
nextCount[ft]++
if nextCount[ft] == 1 {
next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft}))
}
}
}
}
sort.Sort(byName(fields))
// Delete all fields that are hidden by the Go rules for embedded fields,
// except that fields with JSON tags are promoted.
// The fields are sorted in primary order of name, secondary order
// of field index length. Loop over names; for each name, delete
// hidden fields by choosing the one dominant field that survives.
out := fields[:0]
for advance, i := 0, 0; i < len(fields); i += advance {
// One iteration per name.
// Find the sequence of fields with the name of this first field.
fi := fields[i]
name := fi.name
for advance = 1; i+advance < len(fields); advance++ {
fj := fields[i+advance]
if fj.name != name {
break
}
}
if advance == 1 { // Only one field with this name
out = append(out, fi)
continue
}
dominant, ok := dominantField(fields[i : i+advance])
if ok {
out = append(out, dominant)
}
}
fields = out
sort.Sort(byIndex(fields))
return fields
}
// dominantField looks through the fields, all of which are known to
// have the same name, to find the single field that dominates the
// others using Go's embedding rules, modified by the presence of
// JSON tags. If there are multiple top-level fields, the boolean
// will be false: This condition is an error in Go and we skip all
// the fields.
func dominantField(fields []field) (field, bool) {
// The fields are sorted in increasing index-length order. The winner
// must therefore be one with the shortest index length. Drop all
// longer entries, which is easy: just truncate the slice.
length := len(fields[0].index)
tagged := -1 // Index of first tagged field.
for i, f := range fields {
if len(f.index) > length {
fields = fields[:i]
break
}
if f.tag {
if tagged >= 0 {
// Multiple tagged fields at the same level: conflict.
// Return no field.
return field{}, false
}
tagged = i
}
}
if tagged >= 0 {
return fields[tagged], true
}
// All remaining fields have the same length. If there's more than one,
// we have a conflict (two fields named "X" at the same level) and we
// return no field.
if len(fields) > 1 {
return field{}, false
}
return fields[0], true
}
var fieldCache struct {
sync.RWMutex
m map[reflect.Type][]field
}
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
func cachedTypeFields(t reflect.Type) []field {
fieldCache.RLock()
f := fieldCache.m[t]
fieldCache.RUnlock()
if f != nil {
return f
}
// Compute fields without lock.
// Might duplicate effort but won't hold other computations back.
f = typeFields(t)
if f == nil {
f = []field{}
}
fieldCache.Lock()
if fieldCache.m == nil {
fieldCache.m = map[reflect.Type][]field{}
}
fieldCache.m[t] = f
fieldCache.Unlock()
return f
}
func isValidTag(s string) bool {
if s == "" {
return false
}
for _, c := range s {
switch {
case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
// Backslash and quote chars are reserved, but
// otherwise any punctuation chars are allowed
// in a tag name.
default:
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
return false
}
}
}
return true
}
const (
caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
kelvin = '\u212a'
smallLongEss = '\u017f'
)
// foldFunc returns one of four different case folding equivalence
// functions, from most general (and slow) to fastest:
//
// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
// 3) asciiEqualFold, no special, but includes non-letters (including _)
// 4) simpleLetterEqualFold, no specials, no non-letters.
//
// The letters S and K are special because they map to 3 runes, not just 2:
// * S maps to s and to U+017F 'ſ' Latin small letter long s
// * k maps to K and to U+212A '' Kelvin sign
// See http://play.golang.org/p/tTxjOc0OGo
//
// The returned function is specialized for matching against s and
// should only be given s. It's not curried for performance reasons.
func foldFunc(s []byte) func(s, t []byte) bool {
nonLetter := false
special := false // special letter
for _, b := range s {
if b >= utf8.RuneSelf {
return bytes.EqualFold
}
upper := b & caseMask
if upper < 'A' || upper > 'Z' {
nonLetter = true
} else if upper == 'K' || upper == 'S' {
// See above for why these letters are special.
special = true
}
}
if special {
return equalFoldRight
}
if nonLetter {
return asciiEqualFold
}
return simpleLetterEqualFold
}
// equalFoldRight is a specialization of bytes.EqualFold when s is
// known to be all ASCII (including punctuation), but contains an 's',
// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
// See comments on foldFunc.
func equalFoldRight(s, t []byte) bool {
for _, sb := range s {
if len(t) == 0 {
return false
}
tb := t[0]
if tb < utf8.RuneSelf {
if sb != tb {
sbUpper := sb & caseMask
if 'A' <= sbUpper && sbUpper <= 'Z' {
if sbUpper != tb&caseMask {
return false
}
} else {
return false
}
}
t = t[1:]
continue
}
// sb is ASCII and t is not. t must be either kelvin
// sign or long s; sb must be s, S, k, or K.
tr, size := utf8.DecodeRune(t)
switch sb {
case 's', 'S':
if tr != smallLongEss {
return false
}
case 'k', 'K':
if tr != kelvin {
return false
}
default:
return false
}
t = t[size:]
}
if len(t) > 0 {
return false
}
return true
}
// asciiEqualFold is a specialization of bytes.EqualFold for use when
// s is all ASCII (but may contain non-letters) and contains no
// special-folding letters.
// See comments on foldFunc.
func asciiEqualFold(s, t []byte) bool {
if len(s) != len(t) {
return false
}
for i, sb := range s {
tb := t[i]
if sb == tb {
continue
}
if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
if sb&caseMask != tb&caseMask {
return false
}
} else {
return false
}
}
return true
}
// simpleLetterEqualFold is a specialization of bytes.EqualFold for
// use when s is all ASCII letters (no underscores, etc) and also
// doesn't contain 'k', 'K', 's', or 'S'.
// See comments on foldFunc.
func simpleLetterEqualFold(s, t []byte) bool {
if len(s) != len(t) {
return false
}
for i, b := range s {
if b&caseMask != t[i]&caseMask {
return false
}
}
return true
}
// tagOptions is the string following a comma in a struct field's "json"
// tag, or the empty string. It does not include the leading comma.
type tagOptions string
// parseTag splits a struct field's json tag into its name and
// comma-separated options.
func parseTag(tag string) (string, tagOptions) {
if idx := strings.Index(tag, ","); idx != -1 {
return tag[:idx], tagOptions(tag[idx+1:])
}
return tag, tagOptions("")
}
// Contains reports whether a comma-separated list of options
// contains a particular substr flag. substr must be surrounded by a
// string boundary or commas.
func (o tagOptions) Contains(optionName string) bool {
if len(o) == 0 {
return false
}
s := string(o)
for s != "" {
var next string
i := strings.Index(s, ",")
if i >= 0 {
s, next = s[:i], s[i+1:]
}
if s == optionName {
return true
}
s = next
}
return false
}

View File

@@ -0,0 +1,243 @@
/*
Copyright 2017 The Kubernetes Authors.
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 memory
import (
"errors"
"fmt"
"net"
"net/url"
"sync"
"syscall"
"github.com/googleapis/gnostic/OpenAPIv2"
errorsutil "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/discovery"
restclient "k8s.io/client-go/rest"
)
type cacheEntry struct {
resourceList *metav1.APIResourceList
err error
}
// memCacheClient can Invalidate() to stay up-to-date with discovery
// information.
//
// TODO: Switch to a watch interface. Right now it will poll after each
// Invalidate() call.
type memCacheClient struct {
delegate discovery.DiscoveryInterface
lock sync.RWMutex
groupToServerResources map[string]*cacheEntry
groupList *metav1.APIGroupList
cacheValid bool
}
// Error Constants
var (
ErrCacheNotFound = errors.New("not found")
)
var _ discovery.CachedDiscoveryInterface = &memCacheClient{}
// isTransientConnectionError checks whether given error is "Connection refused" or
// "Connection reset" error which usually means that apiserver is temporarily
// unavailable.
func isTransientConnectionError(err error) bool {
urlError, ok := err.(*url.Error)
if !ok {
return false
}
opError, ok := urlError.Err.(*net.OpError)
if !ok {
return false
}
errno, ok := opError.Err.(syscall.Errno)
if !ok {
return false
}
return errno == syscall.ECONNREFUSED || errno == syscall.ECONNRESET
}
func isTransientError(err error) bool {
if isTransientConnectionError(err) {
return true
}
if t, ok := err.(errorsutil.APIStatus); ok && t.Status().Code >= 500 {
return true
}
return errorsutil.IsTooManyRequests(err)
}
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
func (d *memCacheClient) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
d.lock.Lock()
defer d.lock.Unlock()
if !d.cacheValid {
if err := d.refreshLocked(); err != nil {
return nil, err
}
}
cachedVal, ok := d.groupToServerResources[groupVersion]
if !ok {
return nil, ErrCacheNotFound
}
if cachedVal.err != nil && isTransientError(cachedVal.err) {
r, err := d.serverResourcesForGroupVersion(groupVersion)
if err != nil {
utilruntime.HandleError(fmt.Errorf("couldn't get resource list for %v: %v", groupVersion, err))
}
cachedVal = &cacheEntry{r, err}
d.groupToServerResources[groupVersion] = cachedVal
}
return cachedVal.resourceList, cachedVal.err
}
// ServerResources returns the supported resources for all groups and versions.
// Deprecated: use ServerGroupsAndResources instead.
func (d *memCacheClient) ServerResources() ([]*metav1.APIResourceList, error) {
return discovery.ServerResources(d)
}
// ServerGroupsAndResources returns the groups and supported resources for all groups and versions.
func (d *memCacheClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
return discovery.ServerGroupsAndResources(d)
}
func (d *memCacheClient) ServerGroups() (*metav1.APIGroupList, error) {
d.lock.Lock()
defer d.lock.Unlock()
if !d.cacheValid {
if err := d.refreshLocked(); err != nil {
return nil, err
}
}
return d.groupList, nil
}
func (d *memCacheClient) RESTClient() restclient.Interface {
return d.delegate.RESTClient()
}
func (d *memCacheClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
return discovery.ServerPreferredResources(d)
}
func (d *memCacheClient) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
return discovery.ServerPreferredNamespacedResources(d)
}
func (d *memCacheClient) ServerVersion() (*version.Info, error) {
return d.delegate.ServerVersion()
}
func (d *memCacheClient) OpenAPISchema() (*openapi_v2.Document, error) {
return d.delegate.OpenAPISchema()
}
func (d *memCacheClient) Fresh() bool {
d.lock.RLock()
defer d.lock.RUnlock()
// Return whether the cache is populated at all. It is still possible that
// a single entry is missing due to transient errors and the attempt to read
// that entry will trigger retry.
return d.cacheValid
}
// Invalidate enforces that no cached data that is older than the current time
// is used.
func (d *memCacheClient) Invalidate() {
d.lock.Lock()
defer d.lock.Unlock()
d.cacheValid = false
d.groupToServerResources = nil
d.groupList = nil
}
// refreshLocked refreshes the state of cache. The caller must hold d.lock for
// writing.
func (d *memCacheClient) refreshLocked() error {
// TODO: Could this multiplicative set of calls be replaced by a single call
// to ServerResources? If it's possible for more than one resulting
// APIResourceList to have the same GroupVersion, the lists would need merged.
gl, err := d.delegate.ServerGroups()
if err != nil || len(gl.Groups) == 0 {
utilruntime.HandleError(fmt.Errorf("couldn't get current server API group list: %v", err))
return err
}
wg := &sync.WaitGroup{}
resultLock := &sync.Mutex{}
rl := map[string]*cacheEntry{}
for _, g := range gl.Groups {
for _, v := range g.Versions {
gv := v.GroupVersion
wg.Add(1)
go func() {
defer wg.Done()
defer utilruntime.HandleCrash()
r, err := d.serverResourcesForGroupVersion(gv)
if err != nil {
utilruntime.HandleError(fmt.Errorf("couldn't get resource list for %v: %v", gv, err))
}
resultLock.Lock()
defer resultLock.Unlock()
rl[gv] = &cacheEntry{r, err}
}()
}
}
wg.Wait()
d.groupToServerResources, d.groupList = rl, gl
d.cacheValid = true
return nil
}
func (d *memCacheClient) serverResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
r, err := d.delegate.ServerResourcesForGroupVersion(groupVersion)
if err != nil {
return r, err
}
if len(r.APIResources) == 0 {
return r, fmt.Errorf("Got empty response for: %v", groupVersion)
}
return r, nil
}
// NewMemCacheClient creates a new CachedDiscoveryInterface which caches
// discovery information in memory and will stay up-to-date if Invalidate is
// called with regularity.
//
// NOTE: The client will NOT resort to live lookups on cache misses.
func NewMemCacheClient(delegate discovery.DiscoveryInterface) discovery.CachedDiscoveryInterface {
return &memCacheClient{
delegate: delegate,
groupToServerResources: map[string]*cacheEntry{},
}
}

View File

@@ -1,54 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package admissionregistration
import (
v1 "k8s.io/client-go/informers/admissionregistration/v1"
v1beta1 "k8s.io/client-go/informers/admissionregistration/v1beta1"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1 provides access to shared informers for resources in V1.
V1() v1.Interface
// V1beta1 provides access to shared informers for resources in V1beta1.
V1beta1() v1beta1.Interface
}
type group struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// V1 returns a new v1.Interface.
func (g *group) V1() v1.Interface {
return v1.New(g.factory, g.namespace, g.tweakListOptions)
}
// V1beta1 returns a new v1beta1.Interface.
func (g *group) V1beta1() v1beta1.Interface {
return v1beta1.New(g.factory, g.namespace, g.tweakListOptions)
}

View File

@@ -1,52 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// MutatingWebhookConfigurations returns a MutatingWebhookConfigurationInformer.
MutatingWebhookConfigurations() MutatingWebhookConfigurationInformer
// ValidatingWebhookConfigurations returns a ValidatingWebhookConfigurationInformer.
ValidatingWebhookConfigurations() ValidatingWebhookConfigurationInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// MutatingWebhookConfigurations returns a MutatingWebhookConfigurationInformer.
func (v *version) MutatingWebhookConfigurations() MutatingWebhookConfigurationInformer {
return &mutatingWebhookConfigurationInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
}
// ValidatingWebhookConfigurations returns a ValidatingWebhookConfigurationInformer.
func (v *version) ValidatingWebhookConfigurations() ValidatingWebhookConfigurationInformer {
return &validatingWebhookConfigurationInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
}

View File

@@ -1,89 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
"context"
time "time"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1 "k8s.io/client-go/listers/admissionregistration/v1"
cache "k8s.io/client-go/tools/cache"
)
// MutatingWebhookConfigurationInformer provides access to a shared informer and lister for
// MutatingWebhookConfigurations.
type MutatingWebhookConfigurationInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.MutatingWebhookConfigurationLister
}
type mutatingWebhookConfigurationInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// NewMutatingWebhookConfigurationInformer constructs a new informer for MutatingWebhookConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewMutatingWebhookConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredMutatingWebhookConfigurationInformer(client, resyncPeriod, indexers, nil)
}
// NewFilteredMutatingWebhookConfigurationInformer constructs a new informer for MutatingWebhookConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredMutatingWebhookConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AdmissionregistrationV1().MutatingWebhookConfigurations().List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AdmissionregistrationV1().MutatingWebhookConfigurations().Watch(context.TODO(), options)
},
},
&admissionregistrationv1.MutatingWebhookConfiguration{},
resyncPeriod,
indexers,
)
}
func (f *mutatingWebhookConfigurationInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredMutatingWebhookConfigurationInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *mutatingWebhookConfigurationInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&admissionregistrationv1.MutatingWebhookConfiguration{}, f.defaultInformer)
}
func (f *mutatingWebhookConfigurationInformer) Lister() v1.MutatingWebhookConfigurationLister {
return v1.NewMutatingWebhookConfigurationLister(f.Informer().GetIndexer())
}

View File

@@ -1,89 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
"context"
time "time"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1 "k8s.io/client-go/listers/admissionregistration/v1"
cache "k8s.io/client-go/tools/cache"
)
// ValidatingWebhookConfigurationInformer provides access to a shared informer and lister for
// ValidatingWebhookConfigurations.
type ValidatingWebhookConfigurationInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.ValidatingWebhookConfigurationLister
}
type validatingWebhookConfigurationInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// NewValidatingWebhookConfigurationInformer constructs a new informer for ValidatingWebhookConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewValidatingWebhookConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredValidatingWebhookConfigurationInformer(client, resyncPeriod, indexers, nil)
}
// NewFilteredValidatingWebhookConfigurationInformer constructs a new informer for ValidatingWebhookConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredValidatingWebhookConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AdmissionregistrationV1().ValidatingWebhookConfigurations().List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AdmissionregistrationV1().ValidatingWebhookConfigurations().Watch(context.TODO(), options)
},
},
&admissionregistrationv1.ValidatingWebhookConfiguration{},
resyncPeriod,
indexers,
)
}
func (f *validatingWebhookConfigurationInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredValidatingWebhookConfigurationInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *validatingWebhookConfigurationInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&admissionregistrationv1.ValidatingWebhookConfiguration{}, f.defaultInformer)
}
func (f *validatingWebhookConfigurationInformer) Lister() v1.ValidatingWebhookConfigurationLister {
return v1.NewValidatingWebhookConfigurationLister(f.Informer().GetIndexer())
}

View File

@@ -1,52 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
import (
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// MutatingWebhookConfigurations returns a MutatingWebhookConfigurationInformer.
MutatingWebhookConfigurations() MutatingWebhookConfigurationInformer
// ValidatingWebhookConfigurations returns a ValidatingWebhookConfigurationInformer.
ValidatingWebhookConfigurations() ValidatingWebhookConfigurationInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// MutatingWebhookConfigurations returns a MutatingWebhookConfigurationInformer.
func (v *version) MutatingWebhookConfigurations() MutatingWebhookConfigurationInformer {
return &mutatingWebhookConfigurationInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
}
// ValidatingWebhookConfigurations returns a ValidatingWebhookConfigurationInformer.
func (v *version) ValidatingWebhookConfigurations() ValidatingWebhookConfigurationInformer {
return &validatingWebhookConfigurationInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
}

View File

@@ -1,89 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
import (
"context"
time "time"
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1beta1 "k8s.io/client-go/listers/admissionregistration/v1beta1"
cache "k8s.io/client-go/tools/cache"
)
// MutatingWebhookConfigurationInformer provides access to a shared informer and lister for
// MutatingWebhookConfigurations.
type MutatingWebhookConfigurationInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1beta1.MutatingWebhookConfigurationLister
}
type mutatingWebhookConfigurationInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// NewMutatingWebhookConfigurationInformer constructs a new informer for MutatingWebhookConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewMutatingWebhookConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredMutatingWebhookConfigurationInformer(client, resyncPeriod, indexers, nil)
}
// NewFilteredMutatingWebhookConfigurationInformer constructs a new informer for MutatingWebhookConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredMutatingWebhookConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Watch(context.TODO(), options)
},
},
&admissionregistrationv1beta1.MutatingWebhookConfiguration{},
resyncPeriod,
indexers,
)
}
func (f *mutatingWebhookConfigurationInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredMutatingWebhookConfigurationInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *mutatingWebhookConfigurationInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&admissionregistrationv1beta1.MutatingWebhookConfiguration{}, f.defaultInformer)
}
func (f *mutatingWebhookConfigurationInformer) Lister() v1beta1.MutatingWebhookConfigurationLister {
return v1beta1.NewMutatingWebhookConfigurationLister(f.Informer().GetIndexer())
}

View File

@@ -1,89 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
import (
"context"
time "time"
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1beta1 "k8s.io/client-go/listers/admissionregistration/v1beta1"
cache "k8s.io/client-go/tools/cache"
)
// ValidatingWebhookConfigurationInformer provides access to a shared informer and lister for
// ValidatingWebhookConfigurations.
type ValidatingWebhookConfigurationInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1beta1.ValidatingWebhookConfigurationLister
}
type validatingWebhookConfigurationInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// NewValidatingWebhookConfigurationInformer constructs a new informer for ValidatingWebhookConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewValidatingWebhookConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredValidatingWebhookConfigurationInformer(client, resyncPeriod, indexers, nil)
}
// NewFilteredValidatingWebhookConfigurationInformer constructs a new informer for ValidatingWebhookConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredValidatingWebhookConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Watch(context.TODO(), options)
},
},
&admissionregistrationv1beta1.ValidatingWebhookConfiguration{},
resyncPeriod,
indexers,
)
}
func (f *validatingWebhookConfigurationInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredValidatingWebhookConfigurationInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *validatingWebhookConfigurationInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&admissionregistrationv1beta1.ValidatingWebhookConfiguration{}, f.defaultInformer)
}
func (f *validatingWebhookConfigurationInformer) Lister() v1beta1.ValidatingWebhookConfigurationLister {
return v1beta1.NewValidatingWebhookConfigurationLister(f.Informer().GetIndexer())
}

View File

@@ -1,62 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package apps
import (
v1 "k8s.io/client-go/informers/apps/v1"
v1beta1 "k8s.io/client-go/informers/apps/v1beta1"
v1beta2 "k8s.io/client-go/informers/apps/v1beta2"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1 provides access to shared informers for resources in V1.
V1() v1.Interface
// V1beta1 provides access to shared informers for resources in V1beta1.
V1beta1() v1beta1.Interface
// V1beta2 provides access to shared informers for resources in V1beta2.
V1beta2() v1beta2.Interface
}
type group struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// V1 returns a new v1.Interface.
func (g *group) V1() v1.Interface {
return v1.New(g.factory, g.namespace, g.tweakListOptions)
}
// V1beta1 returns a new v1beta1.Interface.
func (g *group) V1beta1() v1beta1.Interface {
return v1beta1.New(g.factory, g.namespace, g.tweakListOptions)
}
// V1beta2 returns a new v1beta2.Interface.
func (g *group) V1beta2() v1beta2.Interface {
return v1beta2.New(g.factory, g.namespace, g.tweakListOptions)
}

View File

@@ -1,90 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
"context"
time "time"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1 "k8s.io/client-go/listers/apps/v1"
cache "k8s.io/client-go/tools/cache"
)
// ControllerRevisionInformer provides access to a shared informer and lister for
// ControllerRevisions.
type ControllerRevisionInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.ControllerRevisionLister
}
type controllerRevisionInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewControllerRevisionInformer constructs a new informer for ControllerRevision type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewControllerRevisionInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredControllerRevisionInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredControllerRevisionInformer constructs a new informer for ControllerRevision type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredControllerRevisionInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().ControllerRevisions(namespace).List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().ControllerRevisions(namespace).Watch(context.TODO(), options)
},
},
&appsv1.ControllerRevision{},
resyncPeriod,
indexers,
)
}
func (f *controllerRevisionInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredControllerRevisionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *controllerRevisionInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&appsv1.ControllerRevision{}, f.defaultInformer)
}
func (f *controllerRevisionInformer) Lister() v1.ControllerRevisionLister {
return v1.NewControllerRevisionLister(f.Informer().GetIndexer())
}

View File

@@ -1,90 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
"context"
time "time"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1 "k8s.io/client-go/listers/apps/v1"
cache "k8s.io/client-go/tools/cache"
)
// DaemonSetInformer provides access to a shared informer and lister for
// DaemonSets.
type DaemonSetInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.DaemonSetLister
}
type daemonSetInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewDaemonSetInformer constructs a new informer for DaemonSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewDaemonSetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredDaemonSetInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredDaemonSetInformer constructs a new informer for DaemonSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredDaemonSetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().DaemonSets(namespace).List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().DaemonSets(namespace).Watch(context.TODO(), options)
},
},
&appsv1.DaemonSet{},
resyncPeriod,
indexers,
)
}
func (f *daemonSetInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredDaemonSetInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *daemonSetInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&appsv1.DaemonSet{}, f.defaultInformer)
}
func (f *daemonSetInformer) Lister() v1.DaemonSetLister {
return v1.NewDaemonSetLister(f.Informer().GetIndexer())
}

View File

@@ -1,90 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
"context"
time "time"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1 "k8s.io/client-go/listers/apps/v1"
cache "k8s.io/client-go/tools/cache"
)
// DeploymentInformer provides access to a shared informer and lister for
// Deployments.
type DeploymentInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.DeploymentLister
}
type deploymentInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewDeploymentInformer constructs a new informer for Deployment type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewDeploymentInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredDeploymentInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredDeploymentInformer constructs a new informer for Deployment type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredDeploymentInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().Deployments(namespace).List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().Deployments(namespace).Watch(context.TODO(), options)
},
},
&appsv1.Deployment{},
resyncPeriod,
indexers,
)
}
func (f *deploymentInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredDeploymentInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *deploymentInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&appsv1.Deployment{}, f.defaultInformer)
}
func (f *deploymentInformer) Lister() v1.DeploymentLister {
return v1.NewDeploymentLister(f.Informer().GetIndexer())
}

View File

@@ -1,73 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// ControllerRevisions returns a ControllerRevisionInformer.
ControllerRevisions() ControllerRevisionInformer
// DaemonSets returns a DaemonSetInformer.
DaemonSets() DaemonSetInformer
// Deployments returns a DeploymentInformer.
Deployments() DeploymentInformer
// ReplicaSets returns a ReplicaSetInformer.
ReplicaSets() ReplicaSetInformer
// StatefulSets returns a StatefulSetInformer.
StatefulSets() StatefulSetInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// ControllerRevisions returns a ControllerRevisionInformer.
func (v *version) ControllerRevisions() ControllerRevisionInformer {
return &controllerRevisionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// DaemonSets returns a DaemonSetInformer.
func (v *version) DaemonSets() DaemonSetInformer {
return &daemonSetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// Deployments returns a DeploymentInformer.
func (v *version) Deployments() DeploymentInformer {
return &deploymentInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// ReplicaSets returns a ReplicaSetInformer.
func (v *version) ReplicaSets() ReplicaSetInformer {
return &replicaSetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// StatefulSets returns a StatefulSetInformer.
func (v *version) StatefulSets() StatefulSetInformer {
return &statefulSetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@@ -1,90 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
"context"
time "time"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1 "k8s.io/client-go/listers/apps/v1"
cache "k8s.io/client-go/tools/cache"
)
// ReplicaSetInformer provides access to a shared informer and lister for
// ReplicaSets.
type ReplicaSetInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.ReplicaSetLister
}
type replicaSetInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewReplicaSetInformer constructs a new informer for ReplicaSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewReplicaSetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredReplicaSetInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredReplicaSetInformer constructs a new informer for ReplicaSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredReplicaSetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().ReplicaSets(namespace).List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().ReplicaSets(namespace).Watch(context.TODO(), options)
},
},
&appsv1.ReplicaSet{},
resyncPeriod,
indexers,
)
}
func (f *replicaSetInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredReplicaSetInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *replicaSetInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&appsv1.ReplicaSet{}, f.defaultInformer)
}
func (f *replicaSetInformer) Lister() v1.ReplicaSetLister {
return v1.NewReplicaSetLister(f.Informer().GetIndexer())
}

View File

@@ -1,90 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
"context"
time "time"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1 "k8s.io/client-go/listers/apps/v1"
cache "k8s.io/client-go/tools/cache"
)
// StatefulSetInformer provides access to a shared informer and lister for
// StatefulSets.
type StatefulSetInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.StatefulSetLister
}
type statefulSetInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewStatefulSetInformer constructs a new informer for StatefulSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewStatefulSetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredStatefulSetInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredStatefulSetInformer constructs a new informer for StatefulSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredStatefulSetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().StatefulSets(namespace).List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1().StatefulSets(namespace).Watch(context.TODO(), options)
},
},
&appsv1.StatefulSet{},
resyncPeriod,
indexers,
)
}
func (f *statefulSetInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredStatefulSetInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *statefulSetInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&appsv1.StatefulSet{}, f.defaultInformer)
}
func (f *statefulSetInformer) Lister() v1.StatefulSetLister {
return v1.NewStatefulSetLister(f.Informer().GetIndexer())
}

View File

@@ -1,90 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
import (
"context"
time "time"
appsv1beta1 "k8s.io/api/apps/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1beta1 "k8s.io/client-go/listers/apps/v1beta1"
cache "k8s.io/client-go/tools/cache"
)
// ControllerRevisionInformer provides access to a shared informer and lister for
// ControllerRevisions.
type ControllerRevisionInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1beta1.ControllerRevisionLister
}
type controllerRevisionInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewControllerRevisionInformer constructs a new informer for ControllerRevision type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewControllerRevisionInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredControllerRevisionInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredControllerRevisionInformer constructs a new informer for ControllerRevision type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredControllerRevisionInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1beta1().ControllerRevisions(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1beta1().ControllerRevisions(namespace).Watch(context.TODO(), options)
},
},
&appsv1beta1.ControllerRevision{},
resyncPeriod,
indexers,
)
}
func (f *controllerRevisionInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredControllerRevisionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *controllerRevisionInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&appsv1beta1.ControllerRevision{}, f.defaultInformer)
}
func (f *controllerRevisionInformer) Lister() v1beta1.ControllerRevisionLister {
return v1beta1.NewControllerRevisionLister(f.Informer().GetIndexer())
}

View File

@@ -1,90 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
import (
"context"
time "time"
appsv1beta1 "k8s.io/api/apps/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1beta1 "k8s.io/client-go/listers/apps/v1beta1"
cache "k8s.io/client-go/tools/cache"
)
// DeploymentInformer provides access to a shared informer and lister for
// Deployments.
type DeploymentInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1beta1.DeploymentLister
}
type deploymentInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewDeploymentInformer constructs a new informer for Deployment type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewDeploymentInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredDeploymentInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredDeploymentInformer constructs a new informer for Deployment type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredDeploymentInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1beta1().Deployments(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1beta1().Deployments(namespace).Watch(context.TODO(), options)
},
},
&appsv1beta1.Deployment{},
resyncPeriod,
indexers,
)
}
func (f *deploymentInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredDeploymentInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *deploymentInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&appsv1beta1.Deployment{}, f.defaultInformer)
}
func (f *deploymentInformer) Lister() v1beta1.DeploymentLister {
return v1beta1.NewDeploymentLister(f.Informer().GetIndexer())
}

View File

@@ -1,59 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
import (
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// ControllerRevisions returns a ControllerRevisionInformer.
ControllerRevisions() ControllerRevisionInformer
// Deployments returns a DeploymentInformer.
Deployments() DeploymentInformer
// StatefulSets returns a StatefulSetInformer.
StatefulSets() StatefulSetInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// ControllerRevisions returns a ControllerRevisionInformer.
func (v *version) ControllerRevisions() ControllerRevisionInformer {
return &controllerRevisionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// Deployments returns a DeploymentInformer.
func (v *version) Deployments() DeploymentInformer {
return &deploymentInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// StatefulSets returns a StatefulSetInformer.
func (v *version) StatefulSets() StatefulSetInformer {
return &statefulSetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@@ -1,90 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
import (
"context"
time "time"
appsv1beta1 "k8s.io/api/apps/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1beta1 "k8s.io/client-go/listers/apps/v1beta1"
cache "k8s.io/client-go/tools/cache"
)
// StatefulSetInformer provides access to a shared informer and lister for
// StatefulSets.
type StatefulSetInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1beta1.StatefulSetLister
}
type statefulSetInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewStatefulSetInformer constructs a new informer for StatefulSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewStatefulSetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredStatefulSetInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredStatefulSetInformer constructs a new informer for StatefulSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredStatefulSetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1beta1().StatefulSets(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1beta1().StatefulSets(namespace).Watch(context.TODO(), options)
},
},
&appsv1beta1.StatefulSet{},
resyncPeriod,
indexers,
)
}
func (f *statefulSetInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredStatefulSetInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *statefulSetInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&appsv1beta1.StatefulSet{}, f.defaultInformer)
}
func (f *statefulSetInformer) Lister() v1beta1.StatefulSetLister {
return v1beta1.NewStatefulSetLister(f.Informer().GetIndexer())
}

View File

@@ -1,90 +0,0 @@
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1beta2
import (
"context"
time "time"
appsv1beta2 "k8s.io/api/apps/v1beta2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1beta2 "k8s.io/client-go/listers/apps/v1beta2"
cache "k8s.io/client-go/tools/cache"
)
// ControllerRevisionInformer provides access to a shared informer and lister for
// ControllerRevisions.
type ControllerRevisionInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1beta2.ControllerRevisionLister
}
type controllerRevisionInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewControllerRevisionInformer constructs a new informer for ControllerRevision type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewControllerRevisionInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredControllerRevisionInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredControllerRevisionInformer constructs a new informer for ControllerRevision type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredControllerRevisionInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1beta2().ControllerRevisions(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AppsV1beta2().ControllerRevisions(namespace).Watch(context.TODO(), options)
},
},
&appsv1beta2.ControllerRevision{},
resyncPeriod,
indexers,
)
}
func (f *controllerRevisionInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredControllerRevisionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *controllerRevisionInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&appsv1beta2.ControllerRevision{}, f.defaultInformer)
}
func (f *controllerRevisionInformer) Lister() v1beta2.ControllerRevisionLister {
return v1beta2.NewControllerRevisionLister(f.Informer().GetIndexer())
}

Some files were not shown because too many files have changed in this diff Show More