Skip to content
This repository was archived by the owner on Jun 22, 2023. It is now read-only.

Commit 7ee76a1

Browse files
varshaprasad96dinhxuanvu
authored andcommitted
Hack: reconciler logic for verifying if APIExport exists
1 parent 381028f commit 7ee76a1

File tree

4 files changed

+141
-11
lines changed

4 files changed

+141
-11
lines changed

controllers/catalogentry_controller.go

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,16 @@ package controllers
1919
import (
2020
"context"
2121

22+
"github.com/kcp-dev/catalog/api/v1alpha1"
2223
catalogv1alpha1 "github.com/kcp-dev/catalog/api/v1alpha1"
24+
apisv1alpha1 "github.com/kcp-dev/kcp/pkg/apis/apis/v1alpha1"
25+
"github.com/kcp-dev/logicalcluster"
26+
"k8s.io/apimachinery/pkg/api/errors"
2327
"k8s.io/apimachinery/pkg/runtime"
28+
"k8s.io/apimachinery/pkg/types"
2429
ctrl "sigs.k8s.io/controller-runtime"
2530
"sigs.k8s.io/controller-runtime/pkg/client"
26-
"sigs.k8s.io/controller-runtime/pkg/log"
31+
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
2732
)
2833

2934
// CatalogEntryReconciler reconciles a CatalogEntry object
@@ -46,9 +51,43 @@ type CatalogEntryReconciler struct {
4651
// For more details, check Reconcile and its Result here:
4752
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.2/pkg/reconcile
4853
func (r *CatalogEntryReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
49-
_ = log.FromContext(ctx)
54+
log := ctrllog.FromContext(ctx)
5055

51-
// TODO(user): your logic here
56+
ctx = logicalcluster.WithCluster(ctx, logicalcluster.New(req.ClusterName))
57+
// Fetch the catalog entry from the request
58+
catalogEntry := &v1alpha1.CatalogEntry{}
59+
err := r.Get(ctx, req.NamespacedName, catalogEntry)
60+
if err != nil {
61+
if errors.IsNotFound(err) {
62+
// Request object not found, could have been deleted after reconcile request.
63+
// Owned objects are automatically garbage collected.
64+
log.Info("Catalog Entry not found. Ignoring since object must be deleted")
65+
return ctrl.Result{}, nil
66+
}
67+
// Error reading the object - requeue the request.
68+
log.Error(err, "Failed to get resource")
69+
return ctrl.Result{}, err
70+
}
71+
72+
apiExportNameReferences := catalogEntry.Spec.References
73+
74+
for _, exportRef := range apiExportNameReferences {
75+
// TODO: verify if path contains the entire heirarchy or just the clusterName.
76+
// If it contains the heirarchy then extract the clusterName
77+
path := exportRef.Workspace.Path
78+
name := exportRef.Workspace.ExportName
79+
clusterApiExport := apisv1alpha1.APIExport{}
80+
err := r.Get(logicalcluster.WithCluster(ctx, logicalcluster.New(path)), types.NamespacedName{Name: name, Namespace: req.Namespace}, &clusterApiExport)
81+
if err != nil {
82+
if errors.IsNotFound(err) {
83+
log.Error(err, "APIExport referenced in catalog entry does not exist")
84+
return ctrl.Result{}, err
85+
}
86+
// Error reading the object - requeue the request.
87+
log.Error(err, "Failed to get resource")
88+
return ctrl.Result{}, err
89+
}
90+
}
5291

5392
return ctrl.Result{}, nil
5493
}

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ go 1.18
44

55
require (
66
github.com/kcp-dev/kcp/pkg/apis v0.8.2
7+
github.com/kcp-dev/logicalcluster v1.1.1
78
github.com/onsi/ginkgo v1.16.5
8-
github.com/onsi/gomega v1.17.0
9+
github.com/onsi/gomega v1.18.1
910
k8s.io/apimachinery v0.24.3
1011
k8s.io/client-go v0.24.3
1112
sigs.k8s.io/controller-runtime v0.11.2
@@ -43,6 +44,8 @@ require (
4344
github.com/imdario/mergo v0.3.12 // indirect
4445
github.com/josharian/intern v1.0.0 // indirect
4546
github.com/json-iterator/go v1.1.12 // indirect
47+
github.com/kcp-dev/apimachinery v0.0.0-20220803185518-868856d14e8a // indirect
48+
github.com/kcp-dev/logicalcluster/v2 v2.0.0-alpha.1 // indirect
4649
github.com/mailru/easyjson v0.7.6 // indirect
4750
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
4851
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -82,3 +85,5 @@ require (
8285
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
8386
sigs.k8s.io/yaml v1.3.0 // indirect
8487
)
88+
89+
replace sigs.k8s.io/controller-runtime => github.com/kcp-dev/controller-runtime v0.12.2-0.20220808200255-4b60fd66e5de

go.sum

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
249249
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
250250
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
251251
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
252+
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
252253
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
253254
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
254255
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -306,8 +307,16 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
306307
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
307308
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
308309
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
310+
github.com/kcp-dev/apimachinery v0.0.0-20220803185518-868856d14e8a h1:lJyVMNywLln1x5A3WVELeDpftc5FktP3asI1Prx0lOU=
311+
github.com/kcp-dev/apimachinery v0.0.0-20220803185518-868856d14e8a/go.mod h1:qnvUHkdxOrNzX17yX+z8r81CZEBuFdveNzWqFlwZ55w=
312+
github.com/kcp-dev/controller-runtime v0.12.2-0.20220808200255-4b60fd66e5de h1:IuXSIlIKJiR3ZsuO5PJ1yYdncsheX3A9rpuXQJ/TfQg=
313+
github.com/kcp-dev/controller-runtime v0.12.2-0.20220808200255-4b60fd66e5de/go.mod h1:OFkNQPsWPPz6qWrIY3FUjmSb0W7qKLK8aZC/xBIJwUE=
309314
github.com/kcp-dev/kcp/pkg/apis v0.8.2 h1:yGeI+wZvv32w2leVd354ELydOr2TZikywGf74M3QzL8=
310315
github.com/kcp-dev/kcp/pkg/apis v0.8.2/go.mod h1:jwvDdhVuswpwqCriyr7frT3Ak23OzuFoVRjqSvfFiRk=
316+
github.com/kcp-dev/logicalcluster v1.1.1 h1:6jv54KRHDVvsJjuaV6dWNHVivYCSxDjGjfN+m1pVu3k=
317+
github.com/kcp-dev/logicalcluster v1.1.1/go.mod h1:3IvnQ1TDaTuyhgRqagtKWd1XKz3kBeP8ByLvyNiWywg=
318+
github.com/kcp-dev/logicalcluster/v2 v2.0.0-alpha.1 h1:6EMfOioekQNrpcHEK7k2ANBWogFMlf+3xTB3CC4k+2s=
319+
github.com/kcp-dev/logicalcluster/v2 v2.0.0-alpha.1/go.mod h1:lfWJL764jKFJxZWOGuFuT3PCCLPo6lV5Cl8P7u9T05g=
311320
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
312321
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
313322
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@@ -370,11 +379,14 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
370379
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
371380
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
372381
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
382+
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
383+
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
373384
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
374385
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
375386
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
376-
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
377387
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
388+
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
389+
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
378390
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
379391
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
380392
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -961,8 +973,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
961973
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
962974
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
963975
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw=
964-
sigs.k8s.io/controller-runtime v0.11.2 h1:H5GTxQl0Mc9UjRJhORusqfJCIjBO8UtUxGggCwL1rLA=
965-
sigs.k8s.io/controller-runtime v0.11.2/go.mod h1:P6QCzrEjLaZGqHsfd+os7JQ+WFZhvB8MRFsn4dWF7O4=
966976
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=
967977
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
968978
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=

main.go

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,28 @@ limitations under the License.
1717
package main
1818

1919
import (
20+
"context"
2021
"flag"
22+
"fmt"
2123
"os"
2224

2325
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
2426
// to ensure that exec-entrypoint and run can make use of them.
27+
apisv1alpha1 "github.com/kcp-dev/kcp/pkg/apis/apis/v1alpha1"
2528
_ "k8s.io/client-go/plugin/pkg/client/auth"
29+
"k8s.io/client-go/rest"
2630

2731
"k8s.io/apimachinery/pkg/runtime"
32+
"k8s.io/apimachinery/pkg/types"
2833
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2934
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3035
ctrl "sigs.k8s.io/controller-runtime"
36+
"sigs.k8s.io/controller-runtime/pkg/client"
3137
"sigs.k8s.io/controller-runtime/pkg/healthz"
38+
"sigs.k8s.io/controller-runtime/pkg/kcp"
3239
"sigs.k8s.io/controller-runtime/pkg/log/zap"
3340

41+
"github.com/kcp-dev/catalog/api/v1alpha1"
3442
catalogv1alpha1 "github.com/kcp-dev/catalog/api/v1alpha1"
3543
"github.com/kcp-dev/catalog/controllers"
3644
//+kubebuilder:scaffold:imports
@@ -52,6 +60,8 @@ func main() {
5260
var metricsAddr string
5361
var enableLeaderElection bool
5462
var probeAddr string
63+
var apiExportName string
64+
flag.StringVar(&apiExportName, "api-export-name", "", "The name of the APIExport.")
5565
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
5666
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
5767
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
@@ -64,17 +74,38 @@ func main() {
6474
flag.Parse()
6575

6676
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
77+
ctx := ctrl.SetupSignalHandler()
6778

68-
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
79+
restConfig := ctrl.GetConfigOrDie()
80+
setupLog = setupLog.WithValues("api-export-name", apiExportName)
81+
82+
var mgr ctrl.Manager
83+
var err error
84+
options := ctrl.Options{
6985
Scheme: scheme,
7086
MetricsBindAddress: metricsAddr,
7187
Port: 9443,
7288
HealthProbeBindAddress: probeAddr,
7389
LeaderElection: enableLeaderElection,
74-
LeaderElectionID: "eaf0b9ae.apis.kcp.dev",
75-
})
90+
LeaderElectionID: "68a0532d.my.domain",
91+
LeaderElectionConfig: restConfig,
92+
}
93+
94+
// This controller is intended to run only on kcp, hence use
95+
// only cluster aware config.
96+
setupLog.Info("Looking up virtual workspace URL")
97+
// TODO: verify if rest config should look at APIExport endpoint or not
98+
cfg, err := restConfigForAPIExport(ctx, restConfig, apiExportName)
99+
if err != nil {
100+
setupLog.Error(err, "error looking up virtual workspace URL")
101+
}
102+
103+
setupLog.Info("Using virtual workspace URL", "url", cfg.Host)
104+
105+
options.LeaderElectionConfig = restConfig
106+
mgr, err = kcp.NewClusterAwareManager(cfg, options)
76107
if err != nil {
77-
setupLog.Error(err, "unable to start manager")
108+
setupLog.Error(err, "unable to start cluster aware manager")
78109
os.Exit(1)
79110
}
80111

@@ -102,3 +133,48 @@ func main() {
102133
os.Exit(1)
103134
}
104135
}
136+
137+
// restConfigForAPIExport returns a *rest.Config properly configured to communicate with the endpoint for the
138+
// APIExport's virtual workspace.
139+
func restConfigForAPIExport(ctx context.Context, cfg *rest.Config, apiExportName string) (*rest.Config, error) {
140+
scheme := runtime.NewScheme()
141+
if err := v1alpha1.AddToScheme(scheme); err != nil {
142+
return nil, fmt.Errorf("error adding apis.kcp.dev/v1alpha1 to scheme: %w", err)
143+
}
144+
145+
apiExportClient, err := client.New(cfg, client.Options{Scheme: scheme})
146+
if err != nil {
147+
return nil, fmt.Errorf("error creating APIExport client: %w", err)
148+
}
149+
150+
var apiExport apisv1alpha1.APIExport
151+
152+
if apiExportName != "" {
153+
if err := apiExportClient.Get(ctx, types.NamespacedName{Name: apiExportName}, &apiExport); err != nil {
154+
return nil, fmt.Errorf("error getting APIExport %q: %w", apiExportName, err)
155+
}
156+
} else {
157+
setupLog.Info("api-export-name is empty - listing")
158+
exports := &apisv1alpha1.APIExportList{}
159+
if err := apiExportClient.List(ctx, exports); err != nil {
160+
return nil, fmt.Errorf("error listing APIExports: %w", err)
161+
}
162+
if len(exports.Items) == 0 {
163+
return nil, fmt.Errorf("no APIExport found")
164+
}
165+
if len(exports.Items) > 1 {
166+
return nil, fmt.Errorf("more than one APIExport found")
167+
}
168+
apiExport = exports.Items[0]
169+
}
170+
171+
if len(apiExport.Status.VirtualWorkspaces) < 1 {
172+
return nil, fmt.Errorf("APIExport %q status.virtualWorkspaces is empty", apiExportName)
173+
}
174+
175+
cfg = rest.CopyConfig(cfg)
176+
// TODO(ncdc): sharding support
177+
cfg.Host = apiExport.Status.VirtualWorkspaces[0].URL
178+
179+
return cfg, nil
180+
}

0 commit comments

Comments
 (0)