mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-09-19 06:26:44 +00:00
Migrate ServerStatusRequest controller and resource to kubebuilder (#2838)
* Convert ServerStatusRequest controller to controller-runtime Signed-off-by: Carlisia <carlisia@vmware.com> * Add select stm Signed-off-by: Carlisia <carlisia@vmware.com> * Fixed status patch bug Signed-off-by: Carlisia <carlisia@vmware.com> * Add mgr start Signed-off-by: Carlisia <carlisia@vmware.com> * Trying to sync Signed-off-by: Carlisia <carlisia@vmware.com> * Clean async now Signed-off-by: Carlisia <carlisia@vmware.com> * Clean up + move context out Signed-off-by: Carlisia <carlisia@vmware.com> * Bug: not closing the channel Signed-off-by: Carlisia <carlisia@vmware.com> * Clean up some tests Signed-off-by: Carlisia <carlisia@vmware.com> * Much better way to fetch an update using a backoff loop Signed-off-by: Carlisia <carlisia@vmware.com> * Even better way to retry: use apimachinery lib Signed-off-by: Carlisia <carlisia@vmware.com> * Refactor controller + add test Signed-off-by: Carlisia <carlisia@vmware.com> * partially fix unit tests Signed-off-by: Ashish Amarnath <ashisham@vmware.com> * Fix and add tests Signed-off-by: Carlisia <carlisia@vmware.com> * Add changelog Signed-off-by: Carlisia <carlisia@vmware.com> * Add ability to disable the controller + cleanups Signed-off-by: Carlisia <carlisia@vmware.com> * Fix bug w/ disabling controllers + fix test + clean up Signed-off-by: Carlisia <carlisia@vmware.com> * Move role.yaml to the correct folder Signed-off-by: Carlisia <carlisia@vmware.com> * Add sample serverstatusrequest.yaml Signed-off-by: Carlisia <carlisia@vmware.com> * Add requeue + better formatting Signed-off-by: Carlisia <carlisia@vmware.com> * Increase # of max concurrent reconciles Signed-off-by: Carlisia <carlisia@vmware.com> Co-authored-by: Ashish Amarnath <ashisham@vmware.com>
This commit is contained in:
co-authored by
Ashish Amarnath
parent
aed504a0fd
commit
c952932f1b
+12
-12
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
@@ -30,9 +31,7 @@ import (
|
||||
)
|
||||
|
||||
func NewGetCommand(f client.Factory, use string) *cobra.Command {
|
||||
serverStatusGetter := &serverstatus.DefaultServerStatusGetter{
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
timeout := 5 * time.Second
|
||||
|
||||
c := &cobra.Command{
|
||||
Use: use,
|
||||
@@ -41,17 +40,18 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
|
||||
err := output.ValidateFlags(c)
|
||||
cmd.CheckError(err)
|
||||
|
||||
serverStatusGetter := &serverstatus.DefaultServerStatusGetter{
|
||||
Namespace: f.Namespace(),
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
client, err := f.Client()
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
|
||||
veleroClient := client.VeleroV1()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
serverStatus, err := serverStatusGetter.GetServerStatus(veleroClient)
|
||||
serverStatusGetter := &serverstatus.DefaultServerStatusGetter{
|
||||
Namespace: f.Namespace(),
|
||||
Context: ctx,
|
||||
}
|
||||
|
||||
serverStatus, err := serverStatusGetter.GetServerStatus(kbClient)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stdout, "<error getting plugin information: %s>\n", err)
|
||||
return
|
||||
@@ -62,7 +62,7 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
c.Flags().DurationVar(&serverStatusGetter.Timeout, "timeout", serverStatusGetter.Timeout, "Maximum time to wait for plugin information to be reported.")
|
||||
c.Flags().DurationVar(&timeout, "timeout", timeout, "maximum time to wait for plugin information to be reported. Default is 5 seconds.")
|
||||
output.BindFlagsSimple(c.Flags())
|
||||
|
||||
return c
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019 the Velero contributors.
|
||||
Copyright 2020 the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -21,78 +21,53 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1"
|
||||
)
|
||||
|
||||
type ServerStatusGetter interface {
|
||||
GetServerStatus(client velerov1client.ServerStatusRequestsGetter) (*velerov1api.ServerStatusRequest, error)
|
||||
GetServerStatus(kbClient kbclient.Client) (*velerov1api.ServerStatusRequest, error)
|
||||
}
|
||||
|
||||
type DefaultServerStatusGetter struct {
|
||||
Namespace string
|
||||
Timeout time.Duration
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
func (g *DefaultServerStatusGetter) GetServerStatus(client velerov1client.ServerStatusRequestsGetter) (*velerov1api.ServerStatusRequest, error) {
|
||||
req := builder.ForServerStatusRequest(g.Namespace, "").
|
||||
ObjectMeta(
|
||||
builder.WithGenerateName("velero-cli-"),
|
||||
).Result()
|
||||
func (g *DefaultServerStatusGetter) GetServerStatus(kbClient kbclient.Client) (*velerov1api.ServerStatusRequest, error) {
|
||||
created := builder.ForServerStatusRequest(g.Namespace, "", "0").ObjectMeta(builder.WithGenerateName("velero-cli-")).Result()
|
||||
|
||||
created, err := client.ServerStatusRequests(g.Namespace).Create(context.TODO(), req, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
if err := kbClient.Create(context.Background(), created, &kbclient.CreateOptions{}); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
defer client.ServerStatusRequests(g.Namespace).Delete(context.TODO(), created.Name, metav1.DeleteOptions{})
|
||||
|
||||
listOptions := metav1.ListOptions{
|
||||
// TODO: once the minimum supported Kubernetes version is v1.9.0, uncomment the following line.
|
||||
ctx, cancel := context.WithCancel(g.Context)
|
||||
defer cancel()
|
||||
|
||||
key := client.ObjectKey{Name: created.Name, Namespace: g.Namespace}
|
||||
checkFunc := func() {
|
||||
updated := &velerov1api.ServerStatusRequest{}
|
||||
if err := kbClient.Get(ctx, key, updated); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: once the minimum supported Kubernetes version is v1.9.0, remove the following check.
|
||||
// See http://issue.k8s.io/51046 for details.
|
||||
//FieldSelector: "metadata.name=" + req.Name
|
||||
ResourceVersion: created.ResourceVersion,
|
||||
}
|
||||
watcher, err := client.ServerStatusRequests(g.Namespace).Watch(context.TODO(), listOptions)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
defer watcher.Stop()
|
||||
if updated.Name != created.Name {
|
||||
return
|
||||
}
|
||||
|
||||
expired := time.NewTimer(g.Timeout)
|
||||
defer expired.Stop()
|
||||
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case <-expired.C:
|
||||
return nil, errors.New("timed out waiting for server status request to be processed")
|
||||
case e := <-watcher.ResultChan():
|
||||
updated, ok := e.Object.(*velerov1api.ServerStatusRequest)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("unexpected type %T", e.Object)
|
||||
}
|
||||
|
||||
// TODO: once the minimum supported Kubernetes version is v1.9.0, remove the following check.
|
||||
// See http://issue.k8s.io/51046 for details.
|
||||
if updated.Name != created.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
switch e.Type {
|
||||
case watch.Deleted:
|
||||
return nil, errors.New("server status request was unexpectedly deleted")
|
||||
case watch.Modified:
|
||||
if updated.Status.Phase == velerov1api.ServerStatusRequestPhaseProcessed {
|
||||
req = updated
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
if updated.Status.Phase == velerov1api.ServerStatusRequestPhaseProcessed {
|
||||
created = updated
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
|
||||
return req, nil
|
||||
wait.Until(checkFunc, 250*time.Millisecond, ctx.Done())
|
||||
|
||||
return created, nil
|
||||
}
|
||||
|
||||
@@ -17,51 +17,54 @@ limitations under the License.
|
||||
package version
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/buildinfo"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/cli/serverstatus"
|
||||
velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1"
|
||||
)
|
||||
|
||||
func NewCommand(f client.Factory) *cobra.Command {
|
||||
clientOnly := false
|
||||
serverStatusGetter := &serverstatus.DefaultServerStatusGetter{
|
||||
Namespace: f.Namespace(),
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
var clientOnly bool
|
||||
timeout := 5 * time.Second
|
||||
|
||||
c := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print the velero version and associated image",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
var veleroClient velerov1client.ServerStatusRequestsGetter
|
||||
|
||||
var kbClient kbclient.Client
|
||||
if !clientOnly {
|
||||
client, err := f.Client()
|
||||
var err error
|
||||
kbClient, err = f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
|
||||
veleroClient = client.VeleroV1()
|
||||
}
|
||||
serverStatusGetter.Namespace = f.Namespace()
|
||||
printVersion(os.Stdout, clientOnly, veleroClient, serverStatusGetter)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
serverStatusGetter := &serverstatus.DefaultServerStatusGetter{
|
||||
Namespace: f.Namespace(),
|
||||
Context: ctx,
|
||||
}
|
||||
printVersion(os.Stdout, clientOnly, kbClient, serverStatusGetter)
|
||||
},
|
||||
}
|
||||
|
||||
c.Flags().DurationVar(&serverStatusGetter.Timeout, "timeout", serverStatusGetter.Timeout, "Maximum time to wait for server version to be reported")
|
||||
c.Flags().BoolVar(&clientOnly, "client-only", clientOnly, "Only get velero client version, not server version")
|
||||
c.Flags().DurationVar(&timeout, "timeout", timeout, "maximum time to wait for server version to be reported. Default is 5 seconds.")
|
||||
c.Flags().BoolVar(&clientOnly, "client-only", clientOnly, "only get velero client version, not server version")
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func printVersion(w io.Writer, clientOnly bool, client velerov1client.ServerStatusRequestsGetter, serverStatusGetter serverstatus.ServerStatusGetter) {
|
||||
func printVersion(w io.Writer, clientOnly bool, kbClient kbclient.Client, serverStatusGetter serverstatus.ServerStatusGetter) {
|
||||
fmt.Fprintln(w, "Client:")
|
||||
fmt.Fprintf(w, "\tVersion: %s\n", buildinfo.Version)
|
||||
fmt.Fprintf(w, "\tGit commit: %s\n", buildinfo.FormattedGitSHA())
|
||||
@@ -70,7 +73,7 @@ func printVersion(w io.Writer, clientOnly bool, client velerov1client.ServerStat
|
||||
return
|
||||
}
|
||||
|
||||
serverStatus, err := serverStatusGetter.GetServerStatus(client)
|
||||
serverStatus, err := serverStatusGetter.GetServerStatus(kbClient)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "<error getting server version: %s>\n", err)
|
||||
return
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019 the Velero contributors.
|
||||
Copyright 2020 the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -24,12 +24,13 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
"github.com/vmware-tanzu/velero/pkg/buildinfo"
|
||||
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/fake"
|
||||
v1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
|
||||
)
|
||||
|
||||
func TestPrintVersion(t *testing.T) {
|
||||
@@ -73,7 +74,7 @@ func TestPrintVersion(t *testing.T) {
|
||||
{
|
||||
name: "server status getter returns normally",
|
||||
clientOnly: false,
|
||||
serverStatusRequest: builder.ForServerStatusRequest("velero", "ssr-1").ServerVersion("v1.0.1").Result(),
|
||||
serverStatusRequest: builder.ForServerStatusRequest("velero", "ssr-1", "0").ServerVersion("v1.0.1").Result(),
|
||||
getterError: nil,
|
||||
want: clientVersion + "Server:\n\tVersion: v1.0.1\n",
|
||||
},
|
||||
@@ -82,36 +83,37 @@ func TestPrintVersion(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var (
|
||||
kbClient = fake.NewFakeClientWithScheme(scheme.Scheme)
|
||||
serverStatusGetter = new(mockServerStatusGetter)
|
||||
buf = new(bytes.Buffer)
|
||||
client = fake.NewSimpleClientset()
|
||||
)
|
||||
defer serverStatusGetter.AssertExpectations(t)
|
||||
|
||||
// GetServerStatus should only be called when clientOnly = false
|
||||
if !tc.clientOnly {
|
||||
serverStatusGetter.On("GetServerStatus", client.VeleroV1()).Return(tc.serverStatusRequest, tc.getterError)
|
||||
serverStatusGetter.On("GetServerStatus", kbClient).Return(tc.serverStatusRequest, tc.getterError)
|
||||
}
|
||||
|
||||
printVersion(buf, tc.clientOnly, client.VeleroV1(), serverStatusGetter)
|
||||
printVersion(buf, tc.clientOnly, kbClient, serverStatusGetter)
|
||||
|
||||
assert.Equal(t, tc.want, buf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// serverStatusGetter is an autogenerated mock type for the serverStatusGetter type
|
||||
// mockServerStatusGetter is an autogenerated mock type for the serverStatusGetter type
|
||||
// Code generated by mockery v2.2.1.
|
||||
type mockServerStatusGetter struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// GetServerStatus provides a mock function with given fields: client
|
||||
func (_m *mockServerStatusGetter) GetServerStatus(client v1.ServerStatusRequestsGetter) (*velerov1.ServerStatusRequest, error) {
|
||||
ret := _m.Called(client)
|
||||
// GetServerStatus provides a mock function with given fields: mgr
|
||||
func (_m *mockServerStatusGetter) GetServerStatus(kbClient kbclient.Client) (*velerov1.ServerStatusRequest, error) {
|
||||
ret := _m.Called(kbClient)
|
||||
|
||||
var r0 *velerov1.ServerStatusRequest
|
||||
if rf, ok := ret.Get(0).(func(v1.ServerStatusRequestsGetter) *velerov1.ServerStatusRequest); ok {
|
||||
r0 = rf(client)
|
||||
if rf, ok := ret.Get(0).(func(kbclient.Client) *velerov1.ServerStatusRequest); ok {
|
||||
r0 = rf(kbClient)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*velerov1.ServerStatusRequest)
|
||||
@@ -119,8 +121,8 @@ func (_m *mockServerStatusGetter) GetServerStatus(client v1.ServerStatusRequests
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(v1.ServerStatusRequestsGetter) error); ok {
|
||||
r1 = rf(client)
|
||||
if rf, ok := ret.Get(1).(func(kbclient.Client) error); ok {
|
||||
r1 = rf(kbClient)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user